treewide: switch to clang-format
All checks were successful
Test / Create distribution (push) Successful in 32s
Test / Sandbox (push) Successful in 1m49s
Test / Fortify (push) Successful in 2m44s
Test / Sandbox (race detector) (push) Successful in 3m5s
Test / Fpkg (push) Successful in 3m32s
Test / Fortify (race detector) (push) Successful in 4m15s
Test / Flake checks (push) Successful in 1m4s

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-06-18 13:43:48 +09:00
parent 717771ae80
commit ef80b19f2f
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
6 changed files with 293 additions and 260 deletions

View File

@ -1,69 +1,71 @@
#include "acl-update.h" #include "acl-update.h"
#include <stdlib.h>
#include <stdbool.h>
#include <sys/acl.h>
#include <acl/libacl.h> #include <acl/libacl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/acl.h>
int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms, size_t plen) { int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
int ret = -1; size_t plen) {
bool v; int ret = -1;
int i; bool v;
acl_t acl; int i;
acl_entry_t entry; acl_t acl;
acl_tag_t tag_type; acl_entry_t entry;
void *qualifier_p; acl_tag_t tag_type;
acl_permset_t permset; void *qualifier_p;
acl_permset_t permset;
acl = acl_get_file(path_p, ACL_TYPE_ACCESS); acl = acl_get_file(path_p, ACL_TYPE_ACCESS);
if (acl == NULL) if (acl == NULL)
goto out; goto out;
// prune entries by uid // prune entries by uid
for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1; i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1;
if (acl_get_tag_type(entry, &tag_type) != 0) i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
return -1; if (acl_get_tag_type(entry, &tag_type) != 0)
if (tag_type != ACL_USER) return -1;
continue; if (tag_type != ACL_USER)
continue;
qualifier_p = acl_get_qualifier(entry); qualifier_p = acl_get_qualifier(entry);
if (qualifier_p == NULL) if (qualifier_p == NULL)
return -1; return -1;
v = *(uid_t *)qualifier_p == uid; v = *(uid_t *)qualifier_p == uid;
acl_free(qualifier_p); acl_free(qualifier_p);
if (!v) if (!v)
continue; continue;
acl_delete_entry(acl, entry); acl_delete_entry(acl, entry);
} }
if (plen == 0) if (plen == 0)
goto set; goto set;
if (acl_create_entry(&acl, &entry) != 0) if (acl_create_entry(&acl, &entry) != 0)
goto out; goto out;
if (acl_get_permset(entry, &permset) != 0) if (acl_get_permset(entry, &permset) != 0)
goto out; goto out;
for (i = 0; i < plen; i++) { for (i = 0; i < plen; i++) {
if (acl_add_perm(permset, perms[i]) != 0) if (acl_add_perm(permset, perms[i]) != 0)
goto out; goto out;
} }
if (acl_set_tag_type(entry, ACL_USER) != 0) if (acl_set_tag_type(entry, ACL_USER) != 0)
goto out; goto out;
if (acl_set_qualifier(entry, (void *)&uid) != 0) if (acl_set_qualifier(entry, (void *)&uid) != 0)
goto out; goto out;
set: set:
if (acl_calc_mask(&acl) != 0) if (acl_calc_mask(&acl) != 0)
goto out; goto out;
if (acl_valid(acl) != 0) if (acl_valid(acl) != 0)
goto out; goto out;
if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0) if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0)
ret = 0; ret = 0;
out: out:
free((void *)path_p); free((void *)path_p);
if (acl != NULL) if (acl != NULL)
acl_free((void *)acl); acl_free((void *)acl);
return ret; return ret;
} }

View File

@ -1,3 +1,4 @@
#include <sys/acl.h> #include <sys/acl.h>
int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms, size_t plen); int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
size_t plen);

View File

@ -1,224 +1,232 @@
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE // CLONE_NEWUSER #define _GNU_SOURCE /* CLONE_NEWUSER */
#endif #endif
#include "seccomp-build.h" #include "seccomp-build.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <sys/syscall.h> #include <sched.h>
#include <sys/socket.h> #include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/personality.h> #include <sys/personality.h>
#include <sched.h> #include <sys/socket.h>
#include <sys/syscall.h>
#if (SCMP_VER_MAJOR < 2) || \ #if (SCMP_VER_MAJOR < 2) || (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) || \
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) || \
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 5 && SCMP_VER_MICRO < 1) (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 5 && SCMP_VER_MICRO < 1)
#error This package requires libseccomp >= v2.5.1 #error This package requires libseccomp >= v2.5.1
#endif #endif
struct f_syscall_act { struct f_syscall_act {
int syscall; int syscall;
int m_errno; int m_errno;
struct scmp_arg_cmp *arg; struct scmp_arg_cmp *arg;
}; };
#define LEN(arr) (sizeof(arr) / sizeof((arr)[0])) #define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
#define SECCOMP_RULESET_ADD(ruleset) do { \ #define SECCOMP_RULESET_ADD(ruleset) \
if (opts & F_VERBOSE) f_println("adding seccomp ruleset \"" #ruleset "\""); \ do { \
for (int i = 0; i < LEN(ruleset); i++) { \ if (opts & F_VERBOSE) \
assert(ruleset[i].m_errno == EPERM || ruleset[i].m_errno == ENOSYS); \ f_println("adding seccomp ruleset \"" #ruleset "\""); \
\ for (int i = 0; i < LEN(ruleset); i++) { \
if (ruleset[i].arg) \ assert(ruleset[i].m_errno == EPERM || ruleset[i].m_errno == ENOSYS); \
*ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ruleset[i].m_errno), ruleset[i].syscall, 1, *ruleset[i].arg); \ \
else \ if (ruleset[i].arg) \
*ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ruleset[i].m_errno), ruleset[i].syscall, 0); \ *ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ruleset[i].m_errno), \
\ ruleset[i].syscall, 1, *ruleset[i].arg); \
if (*ret_p == -EFAULT) { \ else \
res = 4; \ *ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ruleset[i].m_errno), \
goto out; \ ruleset[i].syscall, 0); \
} else if (*ret_p < 0) { \ \
res = 5; \ if (*ret_p == -EFAULT) { \
goto out; \ res = 4; \
} \ goto out; \
} \ } else if (*ret_p < 0) { \
} while (0) res = 5; \
goto out; \
} \
} \
} while (0)
int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_filter_opts opts) { int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch,
int32_t res = 0; // refer to resErr for meaning f_filter_opts opts) {
int32_t res = 0; /* refer to resPrefix for message */
int allow_multiarch = opts & F_MULTIARCH; int allow_multiarch = opts & F_MULTIARCH;
int allowed_personality = PER_LINUX; int allowed_personality = PER_LINUX;
if (opts & F_LINUX32) if (opts & F_LINUX32)
allowed_personality = PER_LINUX32; allowed_personality = PER_LINUX32;
// flatpak commit 4c3bf179e2e4a2a298cd1db1d045adaf3f564532 /* flatpak commit 4c3bf179e2e4a2a298cd1db1d045adaf3f564532 */
struct f_syscall_act deny_common[] = { struct f_syscall_act deny_common[] = {
// Block dmesg /* Block dmesg */
{SCMP_SYS(syslog), EPERM}, {SCMP_SYS(syslog), EPERM},
// Useless old syscall /* Useless old syscall */
{SCMP_SYS(uselib), EPERM}, {SCMP_SYS(uselib), EPERM},
// Don't allow disabling accounting /* Don't allow disabling accounting */
{SCMP_SYS(acct), EPERM}, {SCMP_SYS(acct), EPERM},
// Don't allow reading current quota use /* Don't allow reading current quota use */
{SCMP_SYS(quotactl), EPERM}, {SCMP_SYS(quotactl), EPERM},
// Don't allow access to the kernel keyring /* Don't allow access to the kernel keyring */
{SCMP_SYS(add_key), EPERM}, {SCMP_SYS(add_key), EPERM},
{SCMP_SYS(keyctl), EPERM}, {SCMP_SYS(keyctl), EPERM},
{SCMP_SYS(request_key), EPERM}, {SCMP_SYS(request_key), EPERM},
// Scary VM/NUMA ops /* Scary VM/NUMA ops */
{SCMP_SYS(move_pages), EPERM}, {SCMP_SYS(move_pages), EPERM},
{SCMP_SYS(mbind), EPERM}, {SCMP_SYS(mbind), EPERM},
{SCMP_SYS(get_mempolicy), EPERM}, {SCMP_SYS(get_mempolicy), EPERM},
{SCMP_SYS(set_mempolicy), EPERM}, {SCMP_SYS(set_mempolicy), EPERM},
{SCMP_SYS(migrate_pages), EPERM}, {SCMP_SYS(migrate_pages), EPERM},
}; };
// fortify: project-specific extensions /* fortify: project-specific extensions */
struct f_syscall_act deny_common_ext[] = { struct f_syscall_act deny_common_ext[] = {
// system calls for changing the system clock /* system calls for changing the system clock */
{SCMP_SYS(adjtimex), EPERM}, {SCMP_SYS(adjtimex), EPERM},
{SCMP_SYS(clock_adjtime), EPERM}, {SCMP_SYS(clock_adjtime), EPERM},
{SCMP_SYS(clock_adjtime64), EPERM}, {SCMP_SYS(clock_adjtime64), EPERM},
{SCMP_SYS(clock_settime), EPERM}, {SCMP_SYS(clock_settime), EPERM},
{SCMP_SYS(clock_settime64), EPERM}, {SCMP_SYS(clock_settime64), EPERM},
{SCMP_SYS(settimeofday), EPERM}, {SCMP_SYS(settimeofday), EPERM},
// loading and unloading of kernel modules /* loading and unloading of kernel modules */
{SCMP_SYS(delete_module), EPERM}, {SCMP_SYS(delete_module), EPERM},
{SCMP_SYS(finit_module), EPERM}, {SCMP_SYS(finit_module), EPERM},
{SCMP_SYS(init_module), EPERM}, {SCMP_SYS(init_module), EPERM},
// system calls for rebooting and reboot preparation /* system calls for rebooting and reboot preparation */
{SCMP_SYS(kexec_file_load), EPERM}, {SCMP_SYS(kexec_file_load), EPERM},
{SCMP_SYS(kexec_load), EPERM}, {SCMP_SYS(kexec_load), EPERM},
{SCMP_SYS(reboot), EPERM}, {SCMP_SYS(reboot), EPERM},
// system calls for enabling/disabling swap devices /* system calls for enabling/disabling swap devices */
{SCMP_SYS(swapoff), EPERM}, {SCMP_SYS(swapoff), EPERM},
{SCMP_SYS(swapon), EPERM}, {SCMP_SYS(swapon), EPERM},
}; };
struct f_syscall_act deny_ns[] = { struct f_syscall_act deny_ns[] = {
// Don't allow subnamespace setups: /* Don't allow subnamespace setups: */
{SCMP_SYS(unshare), EPERM}, {SCMP_SYS(unshare), EPERM},
{SCMP_SYS(setns), EPERM}, {SCMP_SYS(setns), EPERM},
{SCMP_SYS(mount), EPERM}, {SCMP_SYS(mount), EPERM},
{SCMP_SYS(umount), EPERM}, {SCMP_SYS(umount), EPERM},
{SCMP_SYS(umount2), EPERM}, {SCMP_SYS(umount2), EPERM},
{SCMP_SYS(pivot_root), EPERM}, {SCMP_SYS(pivot_root), EPERM},
{SCMP_SYS(chroot), EPERM}, {SCMP_SYS(chroot), EPERM},
#if defined(__s390__) || defined(__s390x__) || defined(__CRIS__) #if defined(__s390__) || defined(__s390x__) || defined(__CRIS__)
// Architectures with CONFIG_CLONE_BACKWARDS2: the child stack /* Architectures with CONFIG_CLONE_BACKWARDS2: the child stack
// and flags arguments are reversed so the flags come second * and flags arguments are reversed so the flags come second */
{SCMP_SYS(clone), EPERM, &SCMP_A1(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)}, {SCMP_SYS(clone), EPERM,
&SCMP_A1(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)},
#else #else
// Normally the flags come first /* Normally the flags come first */
{SCMP_SYS(clone), EPERM, &SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)}, {SCMP_SYS(clone), EPERM,
&SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)},
#endif #endif
// seccomp can't look into clone3()'s struct clone_args to check whether /* seccomp can't look into clone3()'s struct clone_args to check whether
// the flags are OK, so we have no choice but to block clone3(). * the flags are OK, so we have no choice but to block clone3().
// Return ENOSYS so user-space will fall back to clone(). * Return ENOSYS so user-space will fall back to clone().
// (CVE-2021-41133; see also https://github.com/moby/moby/commit/9f6b562d) * (CVE-2021-41133; see also https://github.com/moby/moby/commit/9f6b562d)
{SCMP_SYS(clone3), ENOSYS}, */
{SCMP_SYS(clone3), ENOSYS},
// New mount manipulation APIs can also change our VFS. There's no /* New mount manipulation APIs can also change our VFS. There's no
// legitimate reason to do these in the sandbox, so block all of them * legitimate reason to do these in the sandbox, so block all of them
// rather than thinking about which ones might be dangerous. * rather than thinking about which ones might be dangerous.
// (CVE-2021-41133) * (CVE-2021-41133) */
{SCMP_SYS(open_tree), ENOSYS}, {SCMP_SYS(open_tree), ENOSYS},
{SCMP_SYS(move_mount), ENOSYS}, {SCMP_SYS(move_mount), ENOSYS},
{SCMP_SYS(fsopen), ENOSYS}, {SCMP_SYS(fsopen), ENOSYS},
{SCMP_SYS(fsconfig), ENOSYS}, {SCMP_SYS(fsconfig), ENOSYS},
{SCMP_SYS(fsmount), ENOSYS}, {SCMP_SYS(fsmount), ENOSYS},
{SCMP_SYS(fspick), ENOSYS}, {SCMP_SYS(fspick), ENOSYS},
{SCMP_SYS(mount_setattr), ENOSYS}, {SCMP_SYS(mount_setattr), ENOSYS},
}; };
// fortify: project-specific extensions /* fortify: project-specific extensions */
struct f_syscall_act deny_ns_ext[] = { struct f_syscall_act deny_ns_ext[] = {
// changing file ownership /* changing file ownership */
{SCMP_SYS(chown), EPERM}, {SCMP_SYS(chown), EPERM},
{SCMP_SYS(chown32), EPERM}, {SCMP_SYS(chown32), EPERM},
{SCMP_SYS(fchown), EPERM}, {SCMP_SYS(fchown), EPERM},
{SCMP_SYS(fchown32), EPERM}, {SCMP_SYS(fchown32), EPERM},
{SCMP_SYS(fchownat), EPERM}, {SCMP_SYS(fchownat), EPERM},
{SCMP_SYS(lchown), EPERM}, {SCMP_SYS(lchown), EPERM},
{SCMP_SYS(lchown32), EPERM}, {SCMP_SYS(lchown32), EPERM},
// system calls for changing user ID and group ID credentials /* system calls for changing user ID and group ID credentials */
{SCMP_SYS(setgid), EPERM}, {SCMP_SYS(setgid), EPERM},
{SCMP_SYS(setgid32), EPERM}, {SCMP_SYS(setgid32), EPERM},
{SCMP_SYS(setgroups), EPERM}, {SCMP_SYS(setgroups), EPERM},
{SCMP_SYS(setgroups32), EPERM}, {SCMP_SYS(setgroups32), EPERM},
{SCMP_SYS(setregid), EPERM}, {SCMP_SYS(setregid), EPERM},
{SCMP_SYS(setregid32), EPERM}, {SCMP_SYS(setregid32), EPERM},
{SCMP_SYS(setresgid), EPERM}, {SCMP_SYS(setresgid), EPERM},
{SCMP_SYS(setresgid32), EPERM}, {SCMP_SYS(setresgid32), EPERM},
{SCMP_SYS(setresuid), EPERM}, {SCMP_SYS(setresuid), EPERM},
{SCMP_SYS(setresuid32), EPERM}, {SCMP_SYS(setresuid32), EPERM},
{SCMP_SYS(setreuid), EPERM}, {SCMP_SYS(setreuid), EPERM},
{SCMP_SYS(setreuid32), EPERM}, {SCMP_SYS(setreuid32), EPERM},
{SCMP_SYS(setuid), EPERM}, {SCMP_SYS(setuid), EPERM},
{SCMP_SYS(setuid32), EPERM}, {SCMP_SYS(setuid32), EPERM},
}; };
struct f_syscall_act deny_tty[] = { struct f_syscall_act deny_tty[] = {
// Don't allow faking input to the controlling tty (CVE-2017-5226) /* Don't allow faking input to the controlling tty (CVE-2017-5226) */
{SCMP_SYS(ioctl), EPERM, &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCSTI)}, {SCMP_SYS(ioctl), EPERM,
// In the unlikely event that the controlling tty is a Linux virtual &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCSTI)},
// console (/dev/tty2 or similar), copy/paste operations have an effect /* In the unlikely event that the controlling tty is a Linux virtual
// similar to TIOCSTI (CVE-2023-28100) * console (/dev/tty2 or similar), copy/paste operations have an effect
{SCMP_SYS(ioctl), EPERM, &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCLINUX)}, * similar to TIOCSTI (CVE-2023-28100) */
{SCMP_SYS(ioctl), EPERM,
&SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCLINUX)},
}; };
struct f_syscall_act deny_devel[] = { struct f_syscall_act deny_devel[] = {
// Profiling operations; we expect these to be done by tools from outside /* Profiling operations; we expect these to be done by tools from outside
// the sandbox. In particular perf has been the source of many CVEs. * the sandbox. In particular perf has been the source of many CVEs. */
{SCMP_SYS(perf_event_open), EPERM}, {SCMP_SYS(perf_event_open), EPERM},
// Don't allow you to switch to bsd emulation or whatnot /* Don't allow you to switch to bsd emulation or whatnot */
{SCMP_SYS(personality), EPERM, &SCMP_A0(SCMP_CMP_NE, allowed_personality)}, {SCMP_SYS(personality), EPERM,
&SCMP_A0(SCMP_CMP_NE, allowed_personality)},
{SCMP_SYS(ptrace), EPERM} {SCMP_SYS(ptrace), EPERM}};
};
struct f_syscall_act deny_emu[] = { struct f_syscall_act deny_emu[] = {
// modify_ldt is a historic source of interesting information leaks, /* modify_ldt is a historic source of interesting information leaks,
// so it's disabled as a hardening measure. * so it's disabled as a hardening measure.
// However, it is required to run old 16-bit applications * However, it is required to run old 16-bit applications
// as well as some Wine patches, so it's allowed in multiarch. * as well as some Wine patches, so it's allowed in multiarch. */
{SCMP_SYS(modify_ldt), EPERM}, {SCMP_SYS(modify_ldt), EPERM},
}; };
// fortify: project-specific extensions /* fortify: project-specific extensions */
struct f_syscall_act deny_emu_ext[] = { struct f_syscall_act deny_emu_ext[] = {
{SCMP_SYS(subpage_prot), ENOSYS}, {SCMP_SYS(subpage_prot), ENOSYS},
{SCMP_SYS(switch_endian), ENOSYS}, {SCMP_SYS(switch_endian), ENOSYS},
{SCMP_SYS(vm86), ENOSYS}, {SCMP_SYS(vm86), ENOSYS},
{SCMP_SYS(vm86old), ENOSYS}, {SCMP_SYS(vm86old), ENOSYS},
}; };
// Blocklist all but unix, inet, inet6 and netlink /* Blocklist all but unix, inet, inet6 and netlink */
struct struct {
{ int family;
int family;
f_filter_opts flags_mask; f_filter_opts flags_mask;
} socket_family_allowlist[] = { } socket_family_allowlist[] = {
// NOTE: Keep in numerical order /* NOTE: Keep in numerical order */
{ AF_UNSPEC, 0 }, {AF_UNSPEC, 0},
{ AF_LOCAL, 0 }, {AF_LOCAL, 0},
{ AF_INET, 0 }, {AF_INET, 0},
{ AF_INET6, 0 }, {AF_INET6, 0},
{ AF_NETLINK, 0 }, {AF_NETLINK, 0},
{ AF_CAN, F_CAN }, {AF_CAN, F_CAN},
{ AF_BLUETOOTH, F_BLUETOOTH }, {AF_BLUETOOTH, F_BLUETOOTH},
}; };
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW); scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
@ -228,14 +236,14 @@ int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_
} else } else
errno = 0; errno = 0;
// We only really need to handle arches on multiarch systems. /* We only really need to handle arches on multiarch systems.
// If only one arch is supported the default is fine * If only one arch is supported the default is fine */
if (arch != 0) { if (arch != 0) {
// This *adds* the target arch, instead of replacing the /* This *adds* the target arch, instead of replacing the
// native one. This is not ideal, because we'd like to only * native one. This is not ideal, because we'd like to only
// allow the target arch, but we can't really disallow the * allow the target arch, but we can't really disallow the
// native arch at this point, because then bubblewrap * native arch at this point, because then bubblewrap
// couldn't continue running. * couldn't continue running. */
*ret_p = seccomp_arch_add(ctx, arch); *ret_p = seccomp_arch_add(ctx, arch);
if (*ret_p < 0 && *ret_p != -EEXIST) { if (*ret_p < 0 && *ret_p != -EEXIST) {
res = 2; res = 2;
@ -252,33 +260,44 @@ int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_
} }
SECCOMP_RULESET_ADD(deny_common); SECCOMP_RULESET_ADD(deny_common);
if (opts & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns); if (opts & F_DENY_NS)
if (opts & F_DENY_TTY) SECCOMP_RULESET_ADD(deny_tty); SECCOMP_RULESET_ADD(deny_ns);
if (opts & F_DENY_DEVEL) SECCOMP_RULESET_ADD(deny_devel); if (opts & F_DENY_TTY)
if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu); SECCOMP_RULESET_ADD(deny_tty);
if (opts & F_DENY_DEVEL)
SECCOMP_RULESET_ADD(deny_devel);
if (!allow_multiarch)
SECCOMP_RULESET_ADD(deny_emu);
if (opts & F_EXT) { if (opts & F_EXT) {
SECCOMP_RULESET_ADD(deny_common_ext); SECCOMP_RULESET_ADD(deny_common_ext);
if (opts & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns_ext); if (opts & F_DENY_NS)
if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu_ext); SECCOMP_RULESET_ADD(deny_ns_ext);
if (!allow_multiarch)
SECCOMP_RULESET_ADD(deny_emu_ext);
} }
// Socket filtering doesn't work on e.g. i386, so ignore failures here /* Socket filtering doesn't work on e.g. i386, so ignore failures here
// However, we need to user seccomp_rule_add_exact to avoid libseccomp doing * However, we need to user seccomp_rule_add_exact to avoid libseccomp doing
// something else: https://github.com/seccomp/libseccomp/issues/8 * something else: https://github.com/seccomp/libseccomp/issues/8 */
int last_allowed_family = -1; int last_allowed_family = -1;
for (int i = 0; i < LEN(socket_family_allowlist); i++) { for (int i = 0; i < LEN(socket_family_allowlist); i++) {
if (socket_family_allowlist[i].flags_mask != 0 && if (socket_family_allowlist[i].flags_mask != 0 &&
(socket_family_allowlist[i].flags_mask & opts) != socket_family_allowlist[i].flags_mask) (socket_family_allowlist[i].flags_mask & opts) !=
socket_family_allowlist[i].flags_mask)
continue; continue;
for (int disallowed = last_allowed_family + 1; disallowed < socket_family_allowlist[i].family; disallowed++) { for (int disallowed = last_allowed_family + 1;
// Blocklist the in-between valid families disallowed < socket_family_allowlist[i].family; disallowed++) {
seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1, SCMP_A0(SCMP_CMP_EQ, disallowed)); /* Blocklist the in-between valid families */
seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT),
SCMP_SYS(socket), 1,
SCMP_A0(SCMP_CMP_EQ, disallowed));
} }
last_allowed_family = socket_family_allowlist[i].family; last_allowed_family = socket_family_allowlist[i].family;
} }
// Blocklist the rest /* Blocklist the rest */
seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1, SCMP_A0(SCMP_CMP_GE, last_allowed_family + 1)); seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1,
SCMP_A0(SCMP_CMP_GE, last_allowed_family + 1));
if (fd < 0) { if (fd < 0) {
*ret_p = seccomp_load(ctx); *ret_p = seccomp_load(ctx);

View File

@ -1,23 +1,23 @@
#include <stdint.h>
#include <seccomp.h> #include <seccomp.h>
#include <stdint.h>
#if (SCMP_VER_MAJOR < 2) || \ #if (SCMP_VER_MAJOR < 2) || (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) || \
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) || \
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 5 && SCMP_VER_MICRO < 1) (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 5 && SCMP_VER_MICRO < 1)
#error This package requires libseccomp >= v2.5.1 #error This package requires libseccomp >= v2.5.1
#endif #endif
typedef enum { typedef enum {
F_VERBOSE = 1 << 0, F_VERBOSE = 1 << 0,
F_EXT = 1 << 1, F_EXT = 1 << 1,
F_DENY_NS = 1 << 2, F_DENY_NS = 1 << 2,
F_DENY_TTY = 1 << 3, F_DENY_TTY = 1 << 3,
F_DENY_DEVEL = 1 << 4, F_DENY_DEVEL = 1 << 4,
F_MULTIARCH = 1 << 5, F_MULTIARCH = 1 << 5,
F_LINUX32 = 1 << 6, F_LINUX32 = 1 << 6,
F_CAN = 1 << 7, F_CAN = 1 << 7,
F_BLUETOOTH = 1 << 8, F_BLUETOOTH = 1 << 8,
} f_filter_opts; } f_filter_opts;
extern void f_println(char *v); extern void f_println(char *v);
int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_filter_opts opts); int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch,
f_filter_opts opts);

View File

@ -1,30 +1,36 @@
#include "wayland-bind.h" #include "wayland-bind.h"
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h>
#include <wayland-client.h>
#include "security-context-v1-protocol.h" #include "security-context-v1-protocol.h"
#include <wayland-client.h>
static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { static void registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
uint32_t version) {
struct wp_security_context_manager_v1 **out = data; struct wp_security_context_manager_v1 **out = data;
if (strcmp(interface, wp_security_context_manager_v1_interface.name) == 0) if (strcmp(interface, wp_security_context_manager_v1_interface.name) == 0)
*out = wl_registry_bind(registry, name, &wp_security_context_manager_v1_interface, 1); *out = wl_registry_bind(registry, name,
&wp_security_context_manager_v1_interface, 1);
} }
static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { } // no-op static void registry_handle_global_remove(void *data,
struct wl_registry *registry,
uint32_t name) {} /* no-op */
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {
.global = registry_handle_global, .global = registry_handle_global,
.global_remove = registry_handle_global_remove, .global_remove = registry_handle_global_remove,
}; };
int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd) { int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id,
int32_t res = 0; // refer to resErr for meaning const char *instance_id, int sync_fd) {
int32_t res = 0; /* refer to resErr for corresponding Go error */
struct wl_display *display; struct wl_display *display;
display = wl_display_connect_to_fd(fd); display = wl_display_connect_to_fd(fd);
@ -37,7 +43,8 @@ int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const c
registry = wl_display_get_registry(display); registry = wl_display_get_registry(display);
struct wp_security_context_manager_v1 *security_context_manager = NULL; struct wp_security_context_manager_v1 *security_context_manager = NULL;
wl_registry_add_listener(registry, &registry_listener, &security_context_manager); wl_registry_add_listener(registry, &registry_listener,
&security_context_manager);
int ret; int ret;
ret = wl_display_roundtrip(display); ret = wl_display_roundtrip(display);
wl_registry_destroy(registry); wl_registry_destroy(registry);
@ -64,8 +71,11 @@ int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const c
goto out; goto out;
struct wp_security_context_v1 *security_context; struct wp_security_context_v1 *security_context;
security_context = wp_security_context_manager_v1_create_listener(security_context_manager, listen_fd, sync_fd); security_context = wp_security_context_manager_v1_create_listener(
wp_security_context_v1_set_sandbox_engine(security_context, "uk.gensokyo.fortify"); security_context_manager, listen_fd, sync_fd);
wp_security_context_v1_set_sandbox_engine(security_context,
"uk.gensokyo.fortify");
wp_security_context_v1_set_app_id(security_context, app_id); wp_security_context_v1_set_app_id(security_context, app_id);
wp_security_context_v1_set_instance_id(security_context, instance_id); wp_security_context_v1_set_instance_id(security_context, instance_id);
wp_security_context_v1_commit(security_context); wp_security_context_v1_commit(security_context);

View File

@ -1,3 +1,4 @@
#include <stdint.h> #include <stdint.h>
int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd); int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id,
const char *instance_id, int sync_fd);