8be66a
From 8cc497e735104080f6830a8f468b2724ae372990 Mon Sep 17 00:00:00 2001
8be66a
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
8be66a
Date: Wed, 3 Apr 2019 13:11:00 +0200
8be66a
Subject: [PATCH] seccomp: rework how the S[UG]ID filter is installed
8be66a
8be66a
If we know that a syscall is undefined on the given architecture, don't
8be66a
even try to add it.
8be66a
8be66a
Try to install the filter even if some syscalls fail. Also use a helper
8be66a
function to make the whole a bit less magic.
8be66a
8be66a
This allows the S[UG]ID test to pass on arm64.
8be66a
8be66a
(cherry picked from commit da4dc9a6748797e804b6bc92ad513d509abf581c)
8be66a
8be66a
Resolves: #1860374
8be66a
---
8be66a
 src/shared/seccomp-util.c | 244 +++++++++++++++++++++-----------------
8be66a
 1 file changed, 138 insertions(+), 106 deletions(-)
8be66a
8be66a
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
8be66a
index fd46b9f88d..d91fb4e269 100644
8be66a
--- a/src/shared/seccomp-util.c
8be66a
+++ b/src/shared/seccomp-util.c
8be66a
@@ -1750,9 +1750,139 @@ int seccomp_lock_personality(unsigned long personality) {
8be66a
         return 0;
8be66a
 }
8be66a
 
8be66a
+static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
8be66a
+        /* Checks the mode_t parameter of the following system calls:
8be66a
+         *
8be66a
+         *       → chmod() + fchmod() + fchmodat()
8be66a
+         *       → open() + creat() + openat()
8be66a
+         *       → mkdir() + mkdirat()
8be66a
+         *       → mknod() + mknodat()
8be66a
+         *
8be66a
+         * Returns error if *everything* failed, and 0 otherwise.
8be66a
+         */
8be66a
+        int r = 0;
8be66a
+        bool any = false;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(chmod),
8be66a
+                        1,
8be66a
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for chmod: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(fchmod),
8be66a
+                        1,
8be66a
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for fchmod: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(fchmodat),
8be66a
+                        1,
8be66a
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for fchmodat: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(mkdir),
8be66a
+                        1,
8be66a
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for mkdir: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(mkdirat),
8be66a
+                        1,
8be66a
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for mkdirat: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(mknod),
8be66a
+                        1,
8be66a
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for mknod: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(mknodat),
8be66a
+                        1,
8be66a
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for mknodat: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+#if SCMP_SYS(open) > 0
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(open),
8be66a
+                        2,
8be66a
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
8be66a
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for open: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+#endif
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(openat),
8be66a
+                        2,
8be66a
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
8be66a
+                        SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for openat: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        r = seccomp_rule_add_exact(
8be66a
+                        seccomp,
8be66a
+                        SCMP_ACT_ERRNO(EPERM),
8be66a
+                        SCMP_SYS(creat),
8be66a
+                        1,
8be66a
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
+        if (r < 0)
8be66a
+                log_debug_errno(r, "Failed to add filter for creat: %m");
8be66a
+        else
8be66a
+                any = true;
8be66a
+
8be66a
+        return any ? 0 : r;
8be66a
+}
8be66a
+
8be66a
 int seccomp_restrict_suid_sgid(void) {
8be66a
         uint32_t arch;
8be66a
-        int r;
8be66a
+        int r, k;
8be66a
 
8be66a
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
8be66a
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
8be66a
@@ -1761,114 +1891,16 @@ int seccomp_restrict_suid_sgid(void) {
8be66a
                 if (r < 0)
8be66a
                         return r;
8be66a
 
8be66a
-                /* Checks the mode_t parameter of the following system calls:
8be66a
-                 *
8be66a
-                 *       → chmod() + fchmod() + fchmodat()
8be66a
-                 *       → open() + creat() + openat()
8be66a
-                 *       → mkdir() + mkdirat()
8be66a
-                 *       → mknod() + mknodat()
8be66a
-                 */
8be66a
-
8be66a
-                for (unsigned bit = 0; bit < 2; bit ++) {
8be66a
-                        /* Block S_ISUID in the first iteration, S_ISGID in the second */
8be66a
-                        mode_t m = bit == 0 ? S_ISUID : S_ISGID;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(chmod),
8be66a
-                                        1,
8be66a
-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(fchmod),
8be66a
-                                        1,
8be66a
-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(fchmodat),
8be66a
-                                        1,
8be66a
-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(mkdir),
8be66a
-                                        1,
8be66a
-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(mkdirat),
8be66a
-                                        1,
8be66a
-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(mknod),
8be66a
-                                        1,
8be66a
-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(mknodat),
8be66a
-                                        1,
8be66a
-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(open),
8be66a
-                                        2,
8be66a
-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
8be66a
-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
+                r = seccomp_restrict_sxid(seccomp, S_ISUID);
8be66a
+                if (r < 0)
8be66a
+                        log_debug_errno(r, "Failed to add suid rule for architecture %s, ignoring: %m", seccomp_arch_to_string(arch));
8be66a
 
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(openat),
8be66a
-                                        2,
8be66a
-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
8be66a
-                                        SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
+                k = seccomp_restrict_sxid(seccomp, S_ISGID);
8be66a
+                if (k < 0)
8be66a
+                        log_debug_errno(r, "Failed to add sgid rule for architecture %s, ignoring: %m", seccomp_arch_to_string(arch));
8be66a
 
8be66a
-                        r = seccomp_rule_add_exact(
8be66a
-                                        seccomp,
8be66a
-                                        SCMP_ACT_ERRNO(EPERM),
8be66a
-                                        SCMP_SYS(creat),
8be66a
-                                        1,
8be66a
-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
8be66a
-                        if (r < 0)
8be66a
-                                break;
8be66a
-                }
8be66a
-                if (r < 0) {
8be66a
-                        log_debug_errno(r, "Failed to add suid/sgid rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
8be66a
+                if (r < 0 && k < 0)
8be66a
                         continue;
8be66a
-                }
8be66a
 
8be66a
                 r = seccomp_load(seccomp);
8be66a
                 if (IN_SET(r, -EPERM, -EACCES))