]> granicus.if.org Git - sudo/commitdiff
Use a seccomp filter on Linux to disable execve(2) and execveat(2).
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 9 Oct 2016 01:09:17 +0000 (19:09 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 9 Oct 2016 01:09:17 +0000 (19:09 -0600)
This still relies on LD_PRELOAD to work so it has the same issues
as the existing mether with respect to running 32-bit binaries on
a 64-bit kernel.

config.h.in
configure
configure.ac
src/sudo_noexec.c

index 3ca0056787a093475e88d5bb4e795a05e0baab46..1e7858fa7b15da15d0ef5077cb235effb825e607 100644 (file)
 /* Define to 1 if you have the `posix_spawnp' function. */
 #undef HAVE_POSIX_SPAWNP
 
+/* Define to 1 if you have the `prctl' function. */
+#undef HAVE_PRCTL
+
 /* Define to 1 if you have the `pread' function. */
 #undef HAVE_PREAD
 
index 576ca1028fbece9d3dd0ecbd8f386c13acffae0d..d5469296697282ecb74d386e44250371c06c276c 100755 (executable)
--- a/configure
+++ b/configure
     *-*-linux*|*-*-k*bsd*-gnu)
                shadow_funcs="getspnam"
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
+               # Check for linux/filter.h and prctl to use seccomp(2)
+               ac_fn_c_check_header_mongrel "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_filter_h" = xyes; then :
+  for ac_func in prctl
+do :
+  ac_fn_c_check_func "$LINENO" "prctl" "ac_cv_func_prctl"
+if test "x$ac_cv_func_prctl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PRCTL 1
+_ACEOF
+
+fi
+done
+
+fi
+
+
                ;;
     *-*-gnu*)
                # lockf() is broken on the Hurd
index 2479b54dc9d63fb85482982ba4b653f6e1dbebfe..64a3fc0805d4a819dc8834076f447c7fad7b020d 100644 (file)
@@ -1962,6 +1962,8 @@ case "$host" in
     *-*-linux*|*-*-k*bsd*-gnu)
                shadow_funcs="getspnam"
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
+               # Check for linux/filter.h and prctl to use seccomp(2)
+               AC_CHECK_HEADER([linux/filter.h], [AC_CHECK_FUNCS([prctl])])
                ;;
     *-*-gnu*)
                # lockf() is broken on the Hurd
index 43392da6855be20c860f871464cb4ae059596241..b2c3c382998c2368d958aaedd400fac7b760270a 100644 (file)
 
 #include <sys/types.h>
 
+#if defined(__linux__) && defined(HAVE_PRCTL)
+# include <sys/prctl.h>
+# include <asm/unistd.h>
+# include <linux/audit.h>
+# include <linux/filter.h>
+# include <linux/seccomp.h>
+#endif
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -204,3 +212,43 @@ FN_NAME(wordexp)(const char *words, wordexp_t *we, int flags)
 #endif /* HAVE___INTERPOSE */
 }
 INTERPOSE(wordexp)
+
+/*
+ * On Linux we can use a seccomp() filter to disable exec.
+ */
+#if defined(__linux) && defined(HAVE_PRCTL)
+
+/* Older systems may not support execveat(2). */
+#ifndef __NR_execveat
+# define __NR_execveat -1
+#endif
+
+static void noexec_ctor(void) __attribute__((constructor));
+
+static void
+noexec_ctor(void)
+{
+    struct sock_filter exec_filter[] = {
+       /* Load syscall number into the accumulator */
+       BPF_STMT(BPF_LD | BPF_ABS, offsetof(struct seccomp_data, nr)),
+       /* Jump to deny for execve/execveat */
+       BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 2, 0),
+       BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execveat, 1, 0),
+       /* Allow non-matching syscalls */
+       BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
+       /* Deny execve/execveat syscall */
+       BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (EACCES & SECCOMP_RET_DATA))
+    };
+    const struct sock_fprog exec_fprog = {
+       nitems(exec_filter),
+       exec_filter
+    };
+
+    /*
+     * SECCOMP_MODE_FILTER will fail unless the process has
+     * CAP_SYS_ADMIN or the no_new_privs bit is set.
+     */
+    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0)
+       (void)prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &exec_fprog);
+}
+#endif /* __linux__ && HAVE_PRCTL */