$RodHat_
Syscall reference · Processes

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

NameWhat it does
PR_SET_NO_NEW_PRIVSLinux 3.5Permanently stop execve from granting privileges (setuid/setgid bits, file caps). Inherited, can't be unset.
PR_SET_DUMPABLE0 or 1 only. Not dumpable: no core dumps, no PTRACE_ATTACH, /proc/pid files owned by root. Value 2 was removed.
PR_SET_PDEATHSIGSignal to receive when the parent thread dies. Cleared on fork and setuid/caps exec; kept across plain execve.
PR_SET_SECCOMPSet seccomp mode; SECCOMP_MODE_FILTER (Linux 3.5) needs CAP_SYS_ADMIN or no_new_privs. seccomp(2) is preferred.
PR_CAP_AMBIENTLinux 4.3Read or change the ambient capability set: RAISE, LOWER, IS_SET, CLEAR_ALL.
PR_SET_VMALinux 5.17PR_SET_VMA_ANON_NAME names an anonymous mapping. Max 80 bytes with NUL; printable ASCII except [ ] \ $ `.
PR_SET_NAMESet the calling thread's name (comm).

Errors you will actually hit

errnoMeaning
EINVALUnrecognized op, or a bad argument for it (e.g. NO_NEW_PRIVS arg2 != 1, DUMPABLE arg2 not 0/1).
EACCESPR_SET_SECCOMP filter mode without CAP_SYS_ADMIN and without no_new_privs set.
EFAULTA 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

  1. prctl(2), man7.org
  2. PR_SET_NO_NEW_PRIVS(2const), man7.org
  3. PR_SET_DUMPABLE(2const), man7.org
  4. PR_SET_PDEATHSIG(2const), man7.org
  5. PR_SET_VMA(2const), man7.org
  6. PR_SET_SECCOMP(2const), man7.org
  7. PR_CAP_AMBIENT(2const), man7.org
  8. procctl(2), FreeBSD

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.