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