]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
seccomp-util: allow openat2() with --suppress-sync=yes
authorFrantisek Sumsal <frantisek@sumsal.cz>
Wed, 22 Jul 2026 12:34:05 +0000 (14:34 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 24 Jul 2026 05:10:58 +0000 (14:10 +0900)
When --suppress-sync=yes was introduced in
4a4654e0241fbeabecb8587fd3520b6b39264b9c it filtered out openat2()
completely, as we can't check its "flags" argument because it's hidden
in an indirect struct. This was perfectly fine at that time, as
openat2() was quite new and software shipped with a fallback to
open()/openat() if the syscall wasn't present.

However, today the situation is different and an increasing number of
software is moving to openat2() without any fallback - tar [0] being the
most common one in the recent reports and workarounds, and attr recently
fixed a CVE by switching to openat2() [1] as well, to name a few.

Given that we already block all the sync-family syscalls and calling
openat2() with O_SYNC is relatively rare, let's just blanket-enable it
in the --suppress-sync=yes mode. This means that we might issue a
synchronous write when something calls openat2() with O_SYNC, but not
breaking the apps here feels like a reasonable trade-off, at least until
a better solution pops up.

Note that the same situation is in seccomp_restrict_sxid(), but allowing
the openat2() syscall there could actually have some security-related
implications under certain circumstances.

Resolves: #41868

[0] https://cgit.git.savannah.gnu.org/cgit/tar.git/commit/?id=75b03fdff48916bd0654677ed21379bdb0db016d
[1] https://cgit.git.savannah.gnu.org/cgit/attr.git/commit/?id=1cea2fc5e8b5c8a5f29abf1141399e01a57a3154

src/shared/seccomp-util.c

index f02280e454961ce1c009e60e24d0f6f6f2e6e9fd..0a0471bcb18cdefd301b002bb566bf5a3d160cee 100644 (file)
@@ -2515,18 +2515,16 @@ static int block_open_flag(scmp_filter_ctx seccomp, int flag) {
         else
                 any = true;
 
-#if defined(__SNR_openat2)
-        /* The new openat2() system call can't be filtered sensibly, see above. */
-        r = sym_seccomp_rule_add_exact(
-                        seccomp,
-                        SCMP_ACT_ERRNO(ENOSYS),
-                        SCMP_SYS(openat2),
-                        0);
-        if (r < 0)
-                log_debug_errno(r, "Failed to add filter for openat2: %m");
-        else
-                any = true;
-#endif
+        /* We can't reasonably filter openat2() here, because the flags are in an indirect struct instead of
+         * a regular scalar argument, see also the comment in seccomp_restrict_sxid() above. However,
+         * blocking it here causes an increasing number of issues as more software moves to openat2() without
+         * any fallback to open()/openat().
+         *
+         * Given that calling openat2() with O_SYNC is rather rare, and most of the heavy-lifting is done by
+         * filtering out the sync-family syscalls in seccomp_suppress_sync() below, let's just blanket-allow
+         * openat2() to avoid unnecessarily breaking stuff left and right when nspawn is running with
+         * --suppress-sync=yes. This means that we might issue a synchronous write when something calls
+         * openat2() with O_SYNC, but it is the best we can do at least until a better solution pops up. */
 
         return any ? 0 : r;
 }
@@ -2538,7 +2536,7 @@ int seccomp_suppress_sync(void) {
         /* This behaves slightly differently from SystemCallFilter=~@sync:0, in that negative fds (which
          * we can determine to be invalid) are still refused with EBADF. See #34478.
          *
-         * Additionally, O_SYNC/O_DSYNC are masked. */
+         * Additionally, O_SYNC/O_DSYNC are masked (except for openat2(), see above). */
 
         r = dlopen_libseccomp(LOG_DEBUG);
         if (r < 0)