Skip to content

Commit 2331c02

Browse files
committed
core: when applying syscall filters, use ENOSYS for unknown calls
glibc starting using fchmodat2 to implement fchmod with flags [1], but current version of libseccomp does not support fchmodat2 [2]. This is causing problems with programs sandboxed by systemd. libseccomp needs to know a syscall to be able to set any kind of filter for it, so for syscalls unknown by libseccomp we would always do the default action, i.e. either return the errno set by SystemCallErrorNumber or send a fatal signal. For glibc to ignore the unknown syscall and gracefully fall back to the older implementation, we need to return ENOSYS. In particular, tar now fails with the default SystemCallFilter="@System-service" sandbox [3]. This is of course a wider problem: any time the kernel gains new syscalls, before libseccomp and systemd have caught up, we'd behave incorrectly. Let's do the same as we already were doing in nspawn since 3573e03, and do the "default action" only for syscalls which are known by us and libseccomp, and return ENOSYS for anything else. This means that users can start using a sandbox with the new syscalls only after libseccomp and systemd have been updated, but before that happens they behaviour that is backwards-compatible. [1] bminor/glibc@65341f7 [2] seccomp/libseccomp#406 [2] systemd/systemd#30250 Fixes systemd/systemd#30250. In seccomp_restrict_sxid() there's a chunk conditionalized with '#if defined(__SNR_fchmodat2)'. We need to kep that because seccomp_restrict_sxid() seccomp_restrict_suid_sgid() uses SCMP_ACT_ALLOW as the default action.
1 parent 86a1ee9 commit 2331c02

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

src/shared/seccomp-util.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,9 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
11291129

11301130
log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch));
11311131

1132-
r = seccomp_init_for_arch(&seccomp, arch, default_action);
1132+
/* We install ENOSYS as the default action, but it will only apply to syscalls which are not
1133+
* in the @known set. */
1134+
r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ERRNO(ENOSYS));
11331135
if (r < 0)
11341136
return r;
11351137

@@ -1164,6 +1166,23 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
11641166
}
11651167
}
11661168

1169+
NULSTR_FOREACH(name, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value) {
1170+
int id;
1171+
1172+
id = seccomp_syscall_resolve_name(name);
1173+
if (id < 0)
1174+
continue;
1175+
1176+
/* Ignore the syscall if it was already handled above */
1177+
if (hashmap_contains(filter, INT_TO_PTR(id + 1)))
1178+
continue;
1179+
1180+
r = seccomp_rule_add_exact(seccomp, default_action, id, 0);
1181+
if (r < 0 && r != -EDOM) /* EDOM means that the syscall is not available for arch */
1182+
return log_debug_errno(r, "Failed to add rule for system call %s() / %d: %m",
1183+
name, id);
1184+
}
1185+
11671186
r = seccomp_load(seccomp);
11681187
if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
11691188
return r;

0 commit comments

Comments
 (0)