From 237e2f964d7a3b1d1337bfaac70a2a1910e37a41 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 8 Oct 2016 19:09:17 -0600 Subject: [PATCH] Use a seccomp filter on Linux to disable execve(2) and execveat(2). 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 | 3 +++ configure | 17 +++++++++++++++++ configure.ac | 2 ++ src/sudo_noexec.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/config.h.in b/config.h.in index 3ca005678..1e7858fa7 100644 --- a/config.h.in +++ b/config.h.in @@ -526,6 +526,9 @@ /* 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 diff --git a/configure b/configure index 576ca1028..d54692966 100755 --- a/configure +++ b/configure @@ -15223,6 +15223,23 @@ fi *-*-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 diff --git a/configure.ac b/configure.ac index 2479b54dc..64a3fc080 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/sudo_noexec.c b/src/sudo_noexec.c index 43392da68..b2c3c3829 100644 --- a/src/sudo_noexec.c +++ b/src/sudo_noexec.c @@ -18,6 +18,14 @@ #include +#if defined(__linux__) && defined(HAVE_PRCTL) +# include +# include +# include +# include +# include +#endif + #include #include #include @@ -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 */ -- 2.50.1