Loading src/runtime.cpp +42 −0 Changes for src/runtime.cpp: 42 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <algorithm> #include <cerrno> #include <csignal> #include <cstddef> #include <cstdint> #include <cstdio> #include <cstring> Loading @@ -42,8 +43,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <net/if.h> #include <poll.h> #include <grp.h> #include <linux/audit.h> #include <linux/capability.h> #include <linux/ethtool.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <linux/sockios.h> #include <sched.h> #include <sys/mount.h> Loading Loading @@ -337,6 +341,44 @@ struct Pid1 { for (int c = 0; c <= lastCap(); ++c) if (!keep.count(c) && prctl(PR_CAPBSET_DROP, c, 0, 0, 0) != 0 && errno != EINVAL) fail(sysErr("PR_CAPBSET_DROP", errno)); if (!keep.count(capabilityNumber("SYSLOG"))) noKernelLog(); } // the kernel log isn't namespaced, and the kernel lets CAP_SYS_ADMIN (a // booted OS keeps it) read it as well as CAP_SYSLOG: syslog(2) gives // EPERM unless Capability=SYSLOG -- as in Docker's seccomp profile; // /dev/kmsg, the other way, isn't in the container's /dev void noKernelLog() { #if defined(__x86_64__) const uint32_t arch = AUDIT_ARCH_X86_64; #elif defined(__aarch64__) const uint32_t arch = AUDIT_ARCH_AARCH64; #elif defined(__i386__) const uint32_t arch = AUDIT_ARCH_I386; #else return; #endif std::vector<sock_filter> f = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(seccomp_data, arch)), #if defined(__x86_64__) // i386 programs: their syslog is 103 too BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_I386, 1, 0), #endif BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, arch, 0, 3), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(seccomp_data, nr)), #if defined(__x86_64__) BPF_STMT(BPF_ALU | BPF_AND | BPF_K, ~0x40000000u), // x32 #endif BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_syslog, 0, 1), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EPERM), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), }; #if defined(__x86_64__) f[2].jf = 4; // past the x32 mask too #endif sock_fprog prog{(unsigned short)f.size(), f.data()}; // still root with every capability here: no PR_SET_NO_NEW_PRIVS needed if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0) != 0) fail(sysErr("seccomp", errno)); } // ---- the command ---- Loading src/settings.h +3 −0 Changes for src/settings.h: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Environment=KEY=value (one per line) * User=www-data WorkingDirectory=/srv * Hostname=web Capability=NET_ADMIN DropCapability=NET_RAW * (Capability=SYSLOG also lets dmesg read * the host's kernel log; without it, syslog(2) * gives EPERM even with SYS_ADMIN) * * [Files] * ReadOnly=no Bind=/srv/www:/usr/share/nginx/html Loading Loading
src/runtime.cpp +42 −0 Changes for src/runtime.cpp: 42 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <algorithm> #include <cerrno> #include <csignal> #include <cstddef> #include <cstdint> #include <cstdio> #include <cstring> Loading @@ -42,8 +43,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <net/if.h> #include <poll.h> #include <grp.h> #include <linux/audit.h> #include <linux/capability.h> #include <linux/ethtool.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <linux/sockios.h> #include <sched.h> #include <sys/mount.h> Loading Loading @@ -337,6 +341,44 @@ struct Pid1 { for (int c = 0; c <= lastCap(); ++c) if (!keep.count(c) && prctl(PR_CAPBSET_DROP, c, 0, 0, 0) != 0 && errno != EINVAL) fail(sysErr("PR_CAPBSET_DROP", errno)); if (!keep.count(capabilityNumber("SYSLOG"))) noKernelLog(); } // the kernel log isn't namespaced, and the kernel lets CAP_SYS_ADMIN (a // booted OS keeps it) read it as well as CAP_SYSLOG: syslog(2) gives // EPERM unless Capability=SYSLOG -- as in Docker's seccomp profile; // /dev/kmsg, the other way, isn't in the container's /dev void noKernelLog() { #if defined(__x86_64__) const uint32_t arch = AUDIT_ARCH_X86_64; #elif defined(__aarch64__) const uint32_t arch = AUDIT_ARCH_AARCH64; #elif defined(__i386__) const uint32_t arch = AUDIT_ARCH_I386; #else return; #endif std::vector<sock_filter> f = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(seccomp_data, arch)), #if defined(__x86_64__) // i386 programs: their syslog is 103 too BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_I386, 1, 0), #endif BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, arch, 0, 3), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(seccomp_data, nr)), #if defined(__x86_64__) BPF_STMT(BPF_ALU | BPF_AND | BPF_K, ~0x40000000u), // x32 #endif BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_syslog, 0, 1), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EPERM), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), }; #if defined(__x86_64__) f[2].jf = 4; // past the x32 mask too #endif sock_fprog prog{(unsigned short)f.size(), f.data()}; // still root with every capability here: no PR_SET_NO_NEW_PRIVS needed if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0) != 0) fail(sysErr("seccomp", errno)); } // ---- the command ---- Loading
src/settings.h +3 −0 Changes for src/settings.h: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Environment=KEY=value (one per line) * User=www-data WorkingDirectory=/srv * Hostname=web Capability=NET_ADMIN DropCapability=NET_RAW * (Capability=SYSLOG also lets dmesg read * the host's kernel log; without it, syslog(2) * gives EPERM even with SYS_ADMIN) * * [Files] * ReadOnly=no Bind=/srv/www:/usr/share/nginx/html Loading