The author of the standard C library Cosmopolitan and the Redbean platform has announced the implementation of the pledge() isolation mechanism for Linux. Originally developed by the OpenBSD project, pledge allows applications to selectively prohibit access to unused system calls (creating a sort of whitelist of system calls for the application, while others are denied). Unlike available Linux mechanisms for restricting access to system calls, such as seccomp, the pledge mechanism was designed with a focus on simplifying its use.
The unsuccessful initiative to isolate base environment applications in OpenBSD using the systrace mechanism demonstrated that isolating at the level of individual system calls is too complex and cumbersome. As an alternative, pledge was proposed, allowing the creation of isolation rules without delving into details and manipulating pre-defined access classes. For example, the classes offered include stdio (input/output), rpath (read-only files), wpath (write files), cpath (create files), tmppath (work with temporary files), inet (network sockets), unix (Unix sockets), dns (DNS resolution), getpw (read access to the user database), ioctl (ioctl call), proc (process management), exec (process execution), and id (access control management).
The rules for working with system calls are specified in the form of annotations, including a list of allowed classes of system calls and an array of file paths where access is permitted. After building and running the modified application, the kernel takes on the task of ensuring compliance with the specified rules.
A separate implementation of pledge is being developed for FreeBSD, which differs in its ability to isolate applications without modifying their code, while in OpenBSD, the pledge call is aimed at tight integration with the base environment and adding annotations to the code of each application.
The developers of the pledge port for Linux took inspiration from FreeBSD and instead of modifying the code, they prepared a wrapper utility called pledge.com, which allows applying restrictions without altering the application's code. For example, to run the curl utility with access only to the stdio, rpath, inet, and thread syscall classes, you just need to execute ".\/pledge.com -p 'stdio rpath inet thread' curl http:\/\/example.com".
The pledge utility works on all Linux distributions starting from RHEL6 and does not require root access. Additionally, there is an API based on the cosmopolitan library to manage restrictions in C code, which also allows creating enclaves for selective access limitation tied to specific application functions.
The implementation does not require kernel modifications — pledge restrictions are translated into SECCOMP BPF rules and processed using Linux's native syscall isolation mechanism. For example, the call pledge("stdio rpath", 0) will be transformed into the BPF filter static const struct sock_filter kFilter[] = { /* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, syscall, 0, 14 - 1), /* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])), /* L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 2, 4 - 3, 0), /* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 10, 0, 13 - 4), /* L4*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])), /* L5*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, ~0x80800), /* L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 8 - 7, 0), /* L7*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 2, 0, 13 - 8), /* L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])), /* L9*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 12 - 10, 0), /*L10*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 12 - 11, 0), /*L11*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 17, 0, 13 - 11), /*L12*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /*L13*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)), /*L14*/ /* next filter */ };
Source: opennet.ru
