b9a53a
From 5a62c0daff82e8343d24f98e1761d27bf8015782 Mon Sep 17 00:00:00 2001
b9a53a
From: Lennart Poettering <lennart@poettering.net>
b9a53a
Date: Wed, 20 Mar 2019 19:00:28 +0100
b9a53a
Subject: [PATCH] seccomp: introduce seccomp_restrict_suid_sgid() for blocking
b9a53a
 chmod() for suid/sgid files
b9a53a
b9a53a
(cherry picked from commit 3c27973b13724ede05a06a5d346a569794cda433)
b9a53a
Related: #1687512
b9a53a
---
b9a53a
 src/shared/seccomp-util.c | 132 ++++++++++++++++++++++++++++++++++++++
b9a53a
 src/shared/seccomp-util.h |   1 +
b9a53a
 2 files changed, 133 insertions(+)
b9a53a
b9a53a
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
b9a53a
index 92910acf0e..fd46b9f88d 100644
b9a53a
--- a/src/shared/seccomp-util.c
b9a53a
+++ b/src/shared/seccomp-util.c
b9a53a
@@ -1,12 +1,14 @@
b9a53a
 /* SPDX-License-Identifier: LGPL-2.1+ */
b9a53a
 
b9a53a
 #include <errno.h>
b9a53a
+#include <fcntl.h>
b9a53a
 #include <linux/seccomp.h>
b9a53a
 #include <seccomp.h>
b9a53a
 #include <stddef.h>
b9a53a
 #include <sys/mman.h>
b9a53a
 #include <sys/prctl.h>
b9a53a
 #include <sys/shm.h>
b9a53a
+#include <sys/stat.h>
b9a53a
 
b9a53a
 #include "af-list.h"
b9a53a
 #include "alloc-util.h"
b9a53a
@@ -1747,3 +1749,133 @@ int seccomp_lock_personality(unsigned long personality) {
b9a53a
 
b9a53a
         return 0;
b9a53a
 }
b9a53a
+
b9a53a
+int seccomp_restrict_suid_sgid(void) {
b9a53a
+        uint32_t arch;
b9a53a
+        int r;
b9a53a
+
b9a53a
+        SECCOMP_FOREACH_LOCAL_ARCH(arch) {
b9a53a
+                _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
b9a53a
+
b9a53a
+                r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
b9a53a
+                if (r < 0)
b9a53a
+                        return r;
b9a53a
+
b9a53a
+                /* Checks the mode_t parameter of the following system calls:
b9a53a
+                 *
b9a53a
+                 *       → chmod() + fchmod() + fchmodat()
b9a53a
+                 *       → open() + creat() + openat()
b9a53a
+                 *       → mkdir() + mkdirat()
b9a53a
+                 *       → mknod() + mknodat()
b9a53a
+                 */
b9a53a
+
b9a53a
+                for (unsigned bit = 0; bit < 2; bit ++) {
b9a53a
+                        /* Block S_ISUID in the first iteration, S_ISGID in the second */
b9a53a
+                        mode_t m = bit == 0 ? S_ISUID : S_ISGID;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(chmod),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(fchmod),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(fchmodat),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(mkdir),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(mkdirat),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(mknod),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(mknodat),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(open),
b9a53a
+                                        2,
b9a53a
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
b9a53a
+                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(openat),
b9a53a
+                                        2,
b9a53a
+                                        SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
b9a53a
+                                        SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+
b9a53a
+                        r = seccomp_rule_add_exact(
b9a53a
+                                        seccomp,
b9a53a
+                                        SCMP_ACT_ERRNO(EPERM),
b9a53a
+                                        SCMP_SYS(creat),
b9a53a
+                                        1,
b9a53a
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
b9a53a
+                        if (r < 0)
b9a53a
+                                break;
b9a53a
+                }
b9a53a
+                if (r < 0) {
b9a53a
+                        log_debug_errno(r, "Failed to add suid/sgid rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
b9a53a
+                        continue;
b9a53a
+                }
b9a53a
+
b9a53a
+                r = seccomp_load(seccomp);
b9a53a
+                if (IN_SET(r, -EPERM, -EACCES))
b9a53a
+                        return r;
b9a53a
+                if (r < 0)
b9a53a
+                        log_debug_errno(r, "Failed to apply suid/sgid restrictions for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
b9a53a
+        }
b9a53a
+
b9a53a
+        return 0;
b9a53a
+}
b9a53a
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
b9a53a
index d8a36c4e21..602f092255 100644
b9a53a
--- a/src/shared/seccomp-util.h
b9a53a
+++ b/src/shared/seccomp-util.h
b9a53a
@@ -85,6 +85,7 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist);
b9a53a
 int seccomp_restrict_realtime(void);
b9a53a
 int seccomp_memory_deny_write_execute(void);
b9a53a
 int seccomp_lock_personality(unsigned long personality);
b9a53a
+int seccomp_restrict_suid_sgid(void);
b9a53a
 
b9a53a
 extern const uint32_t seccomp_local_archs[];
b9a53a