pledge(2)
Restrict the process to named groups of system operations; violations kill it with SIGABRT.
- Since
- OpenBSD 5.9check your kernel →
- System
- OpenBSD
- Man page
- pledge(2)
Synopsis
#include <unistd.h>
int pledge(const char *promises, const char *execpromises);Rod's take
One syscall, one string. Call pledge("stdio inet dns", NULL) once setup is done and that's all the process gets; step outside it and the kernel kills it with SIGABRT, core and all. Do the broad work first, open the config and the log file, then narrow. Later calls can only take promises away, never add them back. Compare Linux, where the same box means a seccomp filter, Landlock rules and no_new_privs: three APIs, three ways to screw it up. OpenBSD retrofitted nearly its whole base system with this. That's your proof the ergonomics are right.
Flags and arguments that matter
| Name | What it does |
|---|---|
| stdio | Baseline: I/O on already-open fds, memory management, clocks, process info. Almost always needed. |
| rpath | Path traversal, reading struct stat, and opening files for reading. |
| wpath | Like rpath, but files can be opened for writing. |
| cpath | Like wpath, but files can also be created and removed. |
| inet | socket/connect/bind/listen/accept and friends in AF_INET and AF_INET6, with reduced setsockopt. |
| dns | Resolver support: reads resolv.conf, hosts, services; sockets restricted to SOCK_DNS. |
| proc | fork, vfork, kill, setpgid, setsid and related process-relationship calls. Not execve. |
| exec | Allow execve(2). The new program starts with execpromises if set, otherwise unpledged. |
| sendfd / recvfd | Send or receive file descriptors over sendmsg/recvmsg. Directory fds may not be passed. |
| error | Return ENOSYS on violation instead of killing the process; requests for more promises are ignored. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EPERM | The process tried to increase its permissions with a later pledge() call. |
| EINVAL | promises is malformed or contains an invalid keyword. |
| EFAULT | promises or execpromises points outside the process's address space. |
Example
FILE *cfg = fopen("/etc/myapp/config", "r");
if (cfg == NULL) err(1, "fopen config");
parse_config(cfg);
fclose(cfg);
FILE *log = fopen("/var/log/myapp.log", "a");
if (log == NULL) err(1, "fopen log");
/* setup done: no filesystem, no exec, no fork from here */
if (pledge("stdio inet dns", NULL) == -1)
err(1, "pledge");
run_daemon(log);Trimmed from the full walkthrough in pledge(2) and unveil(2): what OpenBSD figured out that Linux is still catching up to.
Linux equivalent
Linux: no single equivalent; combine seccomp(2) filters, Landlock (landlock_create_ruleset(2)) and prctl(PR_SET_NO_NEW_PRIVS). FreeBSD: Capsicum, cap_enter(2) and cap_rights_limit(2).
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
