mirror of
https://github.com/systemd/systemd.git
synced 2025-01-10 05:18:17 +03:00
Merge pull request #34480 from yuwata/test-seccomp-suppress-sync
seccomp-util: pass negative fds as is to fsync() and friends
This commit is contained in:
commit
754d6414f8
@ -879,6 +879,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
|
|||||||
.name = "@sync",
|
.name = "@sync",
|
||||||
.help = "Synchronize files and memory to storage",
|
.help = "Synchronize files and memory to storage",
|
||||||
.value =
|
.value =
|
||||||
|
/* Please also update the list in seccomp_suppress_sync(). */
|
||||||
"fdatasync\0"
|
"fdatasync\0"
|
||||||
"fsync\0"
|
"fsync\0"
|
||||||
"msync\0"
|
"msync\0"
|
||||||
@ -2464,8 +2465,10 @@ int seccomp_suppress_sync(void) {
|
|||||||
uint32_t arch;
|
uint32_t arch;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* This is mostly identical to SystemCallFilter=~@sync:0, but simpler to use, and separately
|
/* This behaves slightly differently from SystemCallFilter=~@sync:0, in that negative fds (which
|
||||||
* manageable, and also masks O_SYNC/O_DSYNC */
|
* we can determine to be invalid) are still refused with EBADF. See #34478.
|
||||||
|
*
|
||||||
|
* Additionally, O_SYNC/O_DSYNC are masked. */
|
||||||
|
|
||||||
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
|
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
|
||||||
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
|
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
|
||||||
@ -2483,6 +2486,16 @@ int seccomp_suppress_sync(void) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (STR_IN_SET(c, "fdatasync", "fsync", "sync_file_range", "sync_file_range2", "syncfs"))
|
||||||
|
r = seccomp_rule_add_exact(
|
||||||
|
seccomp,
|
||||||
|
SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
|
||||||
|
id,
|
||||||
|
1,
|
||||||
|
SCMP_A0(SCMP_CMP_LE, INT_MAX)); /* The rule handles arguments in unsigned. Hence, this
|
||||||
|
* means non-negative fd matches the rule, and the negative
|
||||||
|
* fd passed to the syscall (then it fails with EBADF). */
|
||||||
|
else
|
||||||
r = seccomp_rule_add_exact(
|
r = seccomp_rule_add_exact(
|
||||||
seccomp,
|
seccomp,
|
||||||
SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
|
SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "fs-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "missing_sched.h"
|
#include "missing_sched.h"
|
||||||
@ -1229,4 +1230,55 @@ TEST(restrict_suid_sgid) {
|
|||||||
assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
|
assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_seccomp_suppress_sync_child(void) {
|
||||||
|
_cleanup_(unlink_and_freep) char *path = NULL;
|
||||||
|
_cleanup_close_ int fd = -EBADF;
|
||||||
|
|
||||||
|
ASSERT_OK(tempfn_random("/tmp/seccomp_suppress_sync", NULL, &path));
|
||||||
|
ASSERT_OK_ERRNO(fd = open(path, O_RDWR | O_CREAT | O_SYNC | O_CLOEXEC, 0666));
|
||||||
|
fd = safe_close(fd);
|
||||||
|
|
||||||
|
ASSERT_ERROR_ERRNO(fdatasync(-1), EBADF);
|
||||||
|
ASSERT_ERROR_ERRNO(fsync(-1), EBADF);
|
||||||
|
ASSERT_ERROR_ERRNO(syncfs(-1), EBADF);
|
||||||
|
|
||||||
|
ASSERT_ERROR_ERRNO(fdatasync(INT_MAX), EBADF);
|
||||||
|
ASSERT_ERROR_ERRNO(fsync(INT_MAX), EBADF);
|
||||||
|
ASSERT_ERROR_ERRNO(syncfs(INT_MAX), EBADF);
|
||||||
|
|
||||||
|
ASSERT_OK(seccomp_suppress_sync());
|
||||||
|
|
||||||
|
ASSERT_ERROR_ERRNO(fd = open(path, O_RDWR | O_CREAT | O_SYNC | O_CLOEXEC, 0666), EINVAL);
|
||||||
|
|
||||||
|
ASSERT_OK_ERRNO(fdatasync(INT_MAX));
|
||||||
|
ASSERT_OK_ERRNO(fsync(INT_MAX));
|
||||||
|
ASSERT_OK_ERRNO(syncfs(INT_MAX));
|
||||||
|
|
||||||
|
ASSERT_ERROR_ERRNO(fdatasync(-1), EBADF);
|
||||||
|
ASSERT_ERROR_ERRNO(fsync(-1), EBADF);
|
||||||
|
ASSERT_ERROR_ERRNO(syncfs(-1), EBADF);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(seccomp_suppress_sync) {
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if (!is_seccomp_available()) {
|
||||||
|
log_notice("Seccomp not available, skipping %s", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!have_seccomp_privs()) {
|
||||||
|
log_notice("Not privileged, skipping %s", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_OK_ERRNO(pid = fork());
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
test_seccomp_suppress_sync_child();
|
||||||
|
_exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(wait_for_terminate_and_check("seccomp_suppress_sync", pid, WAIT_LOG), EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
|
Loading…
Reference in New Issue
Block a user