prctl(2)
Per-process/thread control knobs: no_new_privs, dumpable, parent-death signal, VMA names and more.
- Since
- Linux 2.1.57check your kernel →
- glibc
- glibc 2.0.6
- System
- Linux
- Man page
- prctl(2)
Synopsis
#include <linux/prctl.h> /* Definition of PR_* constants */
#include <sys/prctl.h>
int prctl(int op, ...);Rod's take
prctl is a junk drawer with forty-odd operations in it, and three of them matter for a daemon that drops privileges and wants to stay dropped. PR_SET_NO_NEW_PRIVS turns setuid bits and file capabilities into dead letters across execve, permanently, and it's your ticket to installing seccomp filters without CAP_SYS_ADMIN. PR_SET_DUMPABLE at 0 keeps your memory out of core files and out of reach of ptrace. PR_SET_PDEATHSIG keeps orphaned workers from wandering off when the supervisor dies. Each plugs a different hole. They stack. Do the privileged work, set the bits, stop being interesting.
Flags and arguments that matter
| Name | What it does |
|---|---|
| PR_SET_NO_NEW_PRIVSLinux 3.5 | Permanently stop execve from granting privileges (setuid/setgid bits, file caps). Inherited, can't be unset. |
| PR_SET_DUMPABLE | 0 or 1 only. Not dumpable: no core dumps, no PTRACE_ATTACH, /proc/pid files owned by root. Value 2 was removed. |
| PR_SET_PDEATHSIG | Signal to receive when the parent thread dies. Cleared on fork and setuid/caps exec; kept across plain execve. |
| PR_SET_SECCOMP | Set seccomp mode; SECCOMP_MODE_FILTER (Linux 3.5) needs CAP_SYS_ADMIN or no_new_privs. seccomp(2) is preferred. |
| PR_CAP_AMBIENTLinux 4.3 | Read or change the ambient capability set: RAISE, LOWER, IS_SET, CLEAR_ALL. |
| PR_SET_VMALinux 5.17 | PR_SET_VMA_ANON_NAME names an anonymous mapping. Max 80 bytes with NUL; printable ASCII except [ ] \ $ `. |
| PR_SET_NAME | Set the calling thread's name (comm). |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EINVAL | Unrecognized op, or a bad argument for it (e.g. NO_NEW_PRIVS arg2 != 1, DUMPABLE arg2 not 0/1). |
| EACCES | PR_SET_SECCOMP filter mode without CAP_SYS_ADMIN and without no_new_privs set. |
| EFAULT | A pointer argument (e.g. a seccomp filter) is an invalid address. |
Example
/* after binding ports and dropping capabilities */
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
err(1, "PR_SET_NO_NEW_PRIVS");
if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) < 0)
err(1, "PR_SET_DUMPABLE");
/* install_seccomp_filter(); */
pid_t parent = getpid();
if (fork() == 0) {
if (prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) < 0)
err(1, "PR_SET_PDEATHSIG");
if (getppid() != parent) /* parent already gone: no signal coming */
_exit(1);
run_worker();
}Trimmed from the full walkthrough in prctl: the per-process security levers worth knowing.
BSD equivalent
FreeBSD: procctl(2) (FreeBSD 9.3), including PROC_PDEATHSIG_CTL (FreeBSD 11.2, modeled on PR_SET_PDEATHSIG) and PROC_NO_NEW_PRIVS_CTL. OpenBSD: none; pledge(2) covers the sandboxing side.
The long version, from the console
Sources
- prctl(2), man7.org
- PR_SET_NO_NEW_PRIVS(2const), man7.org
- PR_SET_DUMPABLE(2const), man7.org
- PR_SET_PDEATHSIG(2const), man7.org
- PR_SET_VMA(2const), man7.org
- PR_SET_SECCOMP(2const), man7.org
- PR_CAP_AMBIENT(2const), man7.org
- procctl(2), FreeBSD
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
