Linux System Programming · intermediate · ~15 min

rlimit — capping CPU, memory, fds

Set resource limits on yourself before privilege escalation or sandbox.

Overview

setrlimit puts a per-process cap on a resource. Once you lower the hard limit, only root can raise it again. Used to drop your own privileges before running risky code.

Why it matters

Sandboxing in C starts with rlimits. Every Docker, every CI runner, every code-execution service tweaks them.

Core concepts

RLIMIT_AS. Total address space (anonymous + mmap'd). Caps malloc.

RLIMIT_CPU. CPU seconds. SIGXCPU when soft hits, SIGKILL on hard.

RLIMIT_FSIZE. Max file write size. SIGXFSZ on overrun.

RLIMIT_NOFILE. Open file descriptor count.

RLIMIT_NPROC. Per-user process count.

Pentester mindset. When auditing a sandbox runner, check whether it sets rlimits. Missing RLIMIT_CPU = an attacker can pin a core forever. Missing RLIMIT_AS = OOM.

Defensive coding habit. Lower BOTH soft and hard limits at the start of a privileged-then-dropped section. Never raise a hard limit you set yourself.

Syntax notes

#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);

Lesson

setrlimit / getrlimit configure per-process resource caps: CPU seconds, address space, file size, number of open fds. They are how the user-space side of every sandbox is built — including ours.

Code examples

struct rlimit r = { .rlim_cur = 128 * 1024 * 1024, .rlim_max = 128 * 1024 * 1024 };
setrlimit(RLIMIT_AS, &r);     /* 128 MB max address space */

Line by line

struct rlimit r;
r.rlim_cur = r.rlim_max = 5;              /* 5 CPU-seconds */
setrlimit(RLIMIT_CPU, &r);
r.rlim_cur = r.rlim_max = 128 * 1024L * 1024L;   /* 128 MB */
setrlimit(RLIMIT_AS, &r);

Common mistakes

  • Raising the hard limit after dropping it (you can't).

Debugging tips

ulimit -a in a shell shows your current limits. prlimit --pid PID queries any process. cat /proc/PID/limits is the kernel's view.

Memory safety

Setting RLIMIT_AS too low can make later malloc fail unexpectedly. Test under load.

Real-world uses

Every code runner. Every cgroup ancestor. Every shell builtin ulimit.

Practice tasks

  1. Cap RLIMIT_AS to 128 MB and watch a 200 MB malloc fail. 2. Cap RLIMIT_CPU to 5s and run an infinite loop. 3. Lower NOFILE to 16 and watch the 17th open fail.

Summary

setrlimit caps a per-process resource. Lower the hard limit to drop forever. The kernel side of every sandbox.

Practice with these exercises