From 15784261dfaece73ef53f5beb5d3917a95dc1ae4 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sat, 26 May 2012 01:44:40 +0100 Subject: Add a sandbox fallback mechanism, so that behaviour on Linux depends on whether the running system's kernel has seccomp_filter support, not the build system's kernel (forwarded upstream as https://bugzilla.mindrot.org/show_bug.cgi?id=2011). --- Makefile.in | 4 +- config.h.in | 3 - configure | 72 +-- configure.ac | 47 +- debian/changelog | 4 + debian/patches/sandbox-fallback.patch | 925 ++++++++++++++++++++++++++++++++++ debian/patches/series | 1 + sandbox-darwin.c | 54 +- sandbox-null.c | 35 +- sandbox-rlimit.c | 52 +- sandbox-seccomp-filter.c | 81 ++- sandbox-systrace.c | 55 +- sandbox.c | 82 +++ ssh-sandbox.h | 25 +- sshd.c | 2 +- 15 files changed, 1285 insertions(+), 157 deletions(-) create mode 100644 debian/patches/sandbox-fallback.patch create mode 100644 sandbox.c diff --git a/Makefile.in b/Makefile.in index 80155cc77..e2d040ad5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,8 +93,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ sftp-server.o sftp-common.o \ roaming_common.o roaming_serv.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ - sandbox-seccomp-filter.o + sandbox.o sandbox-null.o sandbox-rlimit.o sandbox-systrace.o \ + sandbox-darwin.o sandbox-seccomp-filter.o MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-vulnkey.1.out sshd_config.5.out ssh_config.5.out MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-vulnkey.1 sshd_config.5 ssh_config.5 diff --git a/config.h.in b/config.h.in index e51117b81..b977a3424 100644 --- a/config.h.in +++ b/config.h.in @@ -1365,9 +1365,6 @@ /* Sandbox using Darwin sandbox_init(3) */ #undef SANDBOX_DARWIN -/* no privsep sandboxing */ -#undef SANDBOX_NULL - /* Sandbox using setrlimit(2) */ #undef SANDBOX_RLIMIT diff --git a/configure b/configure index 4f4d596ab..dc98069c8 100755 --- a/configure +++ b/configure @@ -5597,48 +5597,6 @@ if test "x$ac_cv_have_decl_SECCOMP_MODE_FILTER" = xyes; then : have_seccomp_filter=1 fi -fi -if test "x$have_seccomp_filter" = "x1" ; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel for seccomp_filter support" >&5 -$as_echo_n "checking kernel for seccomp_filter support... " >&6; } -if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming yes" >&5 -$as_echo "cross-compiling, assuming yes" >&6; } - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - #include - #include - #include - -int -main () -{ - errno = 0; - prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0); - exit(errno == EFAULT ? 0 : 1); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - # Disable seccomp filter as a target - have_seccomp_filter=0 - -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - fi use_stack_protector=1 @@ -11898,25 +11856,28 @@ if test "${with_sandbox+set}" = set; then : fi +SANDBOX_STYLE="" if test "x$sandbox_arg" = "xsystrace" || \ ( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then test "x$have_systr_policy_kill" != "x1" && \ as_fn_error $? "systrace sandbox requires systrace headers and SYSTR_POLICY_KILL support" "$LINENO" 5 - SANDBOX_STYLE="systrace" + SANDBOX_STYLE="$SANDBOX_STYLE systrace" $as_echo "#define SANDBOX_SYSTRACE 1" >>confdefs.h -elif test "x$sandbox_arg" = "xdarwin" || \ +fi +if test "x$sandbox_arg" = "xdarwin" || \ ( test -z "$sandbox_arg" && test "x$ac_cv_func_sandbox_init" = "xyes" && \ test "x$ac_cv_header_sandbox_h" = "xyes") ; then test "x$ac_cv_func_sandbox_init" != "xyes" -o \ "x$ac_cv_header_sandbox_h" != "xyes" && \ as_fn_error $? "Darwin seatbelt sandbox requires sandbox.h and sandbox_init function" "$LINENO" 5 - SANDBOX_STYLE="darwin" + SANDBOX_STYLE="$SANDBOX_STYLE darwin" $as_echo "#define SANDBOX_DARWIN 1" >>confdefs.h -elif test "x$sandbox_arg" = "xseccomp_filter" || \ +fi +if test "x$sandbox_arg" = "xseccomp_filter" || \ ( test -z "$sandbox_arg" && \ test "x$have_seccomp_filter" = "x1" && \ test "x$ac_cv_header_linux_audit_h" = "xyes" && \ @@ -11931,27 +11892,28 @@ elif test "x$sandbox_arg" = "xseccomp_filter" || \ as_fn_error $? "seccomp_filter sandbox requires seccomp headers" "$LINENO" 5 test "x$ac_cv_func_prctl" != "xyes" && \ as_fn_error $? "seccomp_filter sandbox requires prctl function" "$LINENO" 5 - SANDBOX_STYLE="seccomp_filter" + SANDBOX_STYLE="$SANDBOX_STYLE seccomp_filter" $as_echo "#define SANDBOX_SECCOMP_FILTER 1" >>confdefs.h -elif test "x$sandbox_arg" = "xrlimit" || \ +fi +if test "x$sandbox_arg" = "xrlimit" || \ ( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" ) ; then test "x$ac_cv_func_setrlimit" != "xyes" && \ as_fn_error $? "rlimit sandbox requires setrlimit function" "$LINENO" 5 - SANDBOX_STYLE="rlimit" + SANDBOX_STYLE="$SANDBOX_STYLE rlimit" $as_echo "#define SANDBOX_RLIMIT 1" >>confdefs.h -elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ +fi +if test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then - SANDBOX_STYLE="none" - -$as_echo "#define SANDBOX_NULL 1" >>confdefs.h - -else + SANDBOX_STYLE="$SANDBOX_STYLE none" +fi +if test -z "$SANDBOX_STYLE" ; then as_fn_error $? "unsupported --with-sandbox" "$LINENO" 5 fi +SANDBOX_STYLE="${SANDBOX_STYLE# }" # Cheap hack to ensure NEWS-OS libraries are arranged right. if test ! -z "$SONY" ; then diff --git a/configure.ac b/configure.ac index 14d1d196b..dbbd6e857 100644 --- a/configure.ac +++ b/configure.ac @@ -126,25 +126,6 @@ AC_CHECK_DECL([SECCOMP_MODE_FILTER], [have_seccomp_filter=1], , [ #include ]) fi -if test "x$have_seccomp_filter" = "x1" ; then -AC_MSG_CHECKING([kernel for seccomp_filter support]) -AC_RUN_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - #include - #include - ]], - [[ errno = 0; - prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0); - exit(errno == EFAULT ? 0 : 1); ]])], - [ AC_MSG_RESULT([yes]) ], [ - AC_MSG_RESULT([no]) - # Disable seccomp filter as a target - have_seccomp_filter=0 - ], - [ AC_MSG_RESULT([cross-compiling, assuming yes]) ] -) -fi use_stack_protector=1 AC_ARG_WITH([stackprotect], @@ -2599,21 +2580,24 @@ AC_ARG_WITH([sandbox], fi ] ) +SANDBOX_STYLE="" if test "x$sandbox_arg" = "xsystrace" || \ ( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then test "x$have_systr_policy_kill" != "x1" && \ AC_MSG_ERROR([systrace sandbox requires systrace headers and SYSTR_POLICY_KILL support]) - SANDBOX_STYLE="systrace" + SANDBOX_STYLE="$SANDBOX_STYLE systrace" AC_DEFINE([SANDBOX_SYSTRACE], [1], [Sandbox using systrace(4)]) -elif test "x$sandbox_arg" = "xdarwin" || \ +fi +if test "x$sandbox_arg" = "xdarwin" || \ ( test -z "$sandbox_arg" && test "x$ac_cv_func_sandbox_init" = "xyes" && \ test "x$ac_cv_header_sandbox_h" = "xyes") ; then test "x$ac_cv_func_sandbox_init" != "xyes" -o \ "x$ac_cv_header_sandbox_h" != "xyes" && \ AC_MSG_ERROR([Darwin seatbelt sandbox requires sandbox.h and sandbox_init function]) - SANDBOX_STYLE="darwin" + SANDBOX_STYLE="$SANDBOX_STYLE darwin" AC_DEFINE([SANDBOX_DARWIN], [1], [Sandbox using Darwin sandbox_init(3)]) -elif test "x$sandbox_arg" = "xseccomp_filter" || \ +fi +if test "x$sandbox_arg" = "xseccomp_filter" || \ ( test -z "$sandbox_arg" && \ test "x$have_seccomp_filter" = "x1" && \ test "x$ac_cv_header_linux_audit_h" = "xyes" && \ @@ -2628,21 +2612,24 @@ elif test "x$sandbox_arg" = "xseccomp_filter" || \ AC_MSG_ERROR([seccomp_filter sandbox requires seccomp headers]) test "x$ac_cv_func_prctl" != "xyes" && \ AC_MSG_ERROR([seccomp_filter sandbox requires prctl function]) - SANDBOX_STYLE="seccomp_filter" + SANDBOX_STYLE="$SANDBOX_STYLE seccomp_filter" AC_DEFINE([SANDBOX_SECCOMP_FILTER], [1], [Sandbox using seccomp filter]) -elif test "x$sandbox_arg" = "xrlimit" || \ +fi +if test "x$sandbox_arg" = "xrlimit" || \ ( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" ) ; then test "x$ac_cv_func_setrlimit" != "xyes" && \ AC_MSG_ERROR([rlimit sandbox requires setrlimit function]) - SANDBOX_STYLE="rlimit" + SANDBOX_STYLE="$SANDBOX_STYLE rlimit" AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)]) -elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ +fi +if test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then - SANDBOX_STYLE="none" - AC_DEFINE([SANDBOX_NULL], [1], [no privsep sandboxing]) -else + SANDBOX_STYLE="$SANDBOX_STYLE none" +fi +if test -z "$SANDBOX_STYLE" ; then AC_MSG_ERROR([unsupported --with-sandbox]) fi +SANDBOX_STYLE="${SANDBOX_STYLE# }" # Cheap hack to ensure NEWS-OS libraries are arranged right. if test ! -z "$SONY" ; then diff --git a/debian/changelog b/debian/changelog index 0e1b026d2..476ae4334 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,10 @@ openssh (1:6.0p1-1) UNRELEASED; urgency=low seccomp sandbox, automatically enabled on platforms that support it. (Note: privilege separation sandboxing is still experimental.) * Fix a bashism in configure's seccomp_filter check. + * Add a sandbox fallback mechanism, so that behaviour on Linux depends on + whether the running system's kernel has seccomp_filter support, not the + build system's kernel (forwarded upstream as + https://bugzilla.mindrot.org/show_bug.cgi?id=2011). -- Colin Watson Sat, 21 Apr 2012 10:57:23 +0100 diff --git a/debian/patches/sandbox-fallback.patch b/debian/patches/sandbox-fallback.patch new file mode 100644 index 000000000..124504b36 --- /dev/null +++ b/debian/patches/sandbox-fallback.patch @@ -0,0 +1,925 @@ +Description: Add a sandbox fallback mechanism +Author: Colin Watson +Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=2011 +Forwarded: https://bugzilla.mindrot.org/show_bug.cgi?id=2011 +Last-Update: 2012-05-26 + +Index: b/Makefile.in +=================================================================== +--- a/Makefile.in ++++ b/Makefile.in +@@ -93,8 +93,8 @@ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ + sftp-server.o sftp-common.o \ + roaming_common.o roaming_serv.o \ +- sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ +- sandbox-seccomp-filter.o ++ sandbox.o sandbox-null.o sandbox-rlimit.o sandbox-systrace.o \ ++ sandbox-darwin.o sandbox-seccomp-filter.o + + MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-vulnkey.1.out sshd_config.5.out ssh_config.5.out + MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-vulnkey.1 sshd_config.5 ssh_config.5 +Index: b/configure.ac +=================================================================== +--- a/configure.ac ++++ b/configure.ac +@@ -126,25 +126,6 @@ + #include + ]) + fi +-if test "x$have_seccomp_filter" = "x1" ; then +-AC_MSG_CHECKING([kernel for seccomp_filter support]) +-AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +- #include +- #include +- #include +- #include +- ]], +- [[ errno = 0; +- prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0); +- exit(errno == EFAULT ? 0 : 1); ]])], +- [ AC_MSG_RESULT([yes]) ], [ +- AC_MSG_RESULT([no]) +- # Disable seccomp filter as a target +- have_seccomp_filter=0 +- ], +- [ AC_MSG_RESULT([cross-compiling, assuming yes]) ] +-) +-fi + + use_stack_protector=1 + AC_ARG_WITH([stackprotect], +@@ -2599,21 +2580,24 @@ + fi + ] + ) ++SANDBOX_STYLE="" + if test "x$sandbox_arg" = "xsystrace" || \ + ( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then + test "x$have_systr_policy_kill" != "x1" && \ + AC_MSG_ERROR([systrace sandbox requires systrace headers and SYSTR_POLICY_KILL support]) +- SANDBOX_STYLE="systrace" ++ SANDBOX_STYLE="$SANDBOX_STYLE systrace" + AC_DEFINE([SANDBOX_SYSTRACE], [1], [Sandbox using systrace(4)]) +-elif test "x$sandbox_arg" = "xdarwin" || \ ++fi ++if test "x$sandbox_arg" = "xdarwin" || \ + ( test -z "$sandbox_arg" && test "x$ac_cv_func_sandbox_init" = "xyes" && \ + test "x$ac_cv_header_sandbox_h" = "xyes") ; then + test "x$ac_cv_func_sandbox_init" != "xyes" -o \ + "x$ac_cv_header_sandbox_h" != "xyes" && \ + AC_MSG_ERROR([Darwin seatbelt sandbox requires sandbox.h and sandbox_init function]) +- SANDBOX_STYLE="darwin" ++ SANDBOX_STYLE="$SANDBOX_STYLE darwin" + AC_DEFINE([SANDBOX_DARWIN], [1], [Sandbox using Darwin sandbox_init(3)]) +-elif test "x$sandbox_arg" = "xseccomp_filter" || \ ++fi ++if test "x$sandbox_arg" = "xseccomp_filter" || \ + ( test -z "$sandbox_arg" && \ + test "x$have_seccomp_filter" = "x1" && \ + test "x$ac_cv_header_linux_audit_h" = "xyes" && \ +@@ -2628,21 +2612,24 @@ + AC_MSG_ERROR([seccomp_filter sandbox requires seccomp headers]) + test "x$ac_cv_func_prctl" != "xyes" && \ + AC_MSG_ERROR([seccomp_filter sandbox requires prctl function]) +- SANDBOX_STYLE="seccomp_filter" ++ SANDBOX_STYLE="$SANDBOX_STYLE seccomp_filter" + AC_DEFINE([SANDBOX_SECCOMP_FILTER], [1], [Sandbox using seccomp filter]) +-elif test "x$sandbox_arg" = "xrlimit" || \ ++fi ++if test "x$sandbox_arg" = "xrlimit" || \ + ( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" ) ; then + test "x$ac_cv_func_setrlimit" != "xyes" && \ + AC_MSG_ERROR([rlimit sandbox requires setrlimit function]) +- SANDBOX_STYLE="rlimit" ++ SANDBOX_STYLE="$SANDBOX_STYLE rlimit" + AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)]) +-elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ ++fi ++if test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ + test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then +- SANDBOX_STYLE="none" +- AC_DEFINE([SANDBOX_NULL], [1], [no privsep sandboxing]) +-else ++ SANDBOX_STYLE="$SANDBOX_STYLE none" ++fi ++if test -z "$SANDBOX_STYLE" ; then + AC_MSG_ERROR([unsupported --with-sandbox]) + fi ++SANDBOX_STYLE="${SANDBOX_STYLE# }" + + # Cheap hack to ensure NEWS-OS libraries are arranged right. + if test ! -z "$SONY" ; then +Index: b/configure +=================================================================== +--- a/configure ++++ b/configure +@@ -5598,48 +5598,6 @@ + fi + + fi +-if test "x$have_seccomp_filter" = "x1" ; then +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel for seccomp_filter support" >&5 +-$as_echo_n "checking kernel for seccomp_filter support... " >&6; } +-if test "$cross_compiling" = yes; then : +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming yes" >&5 +-$as_echo "cross-compiling, assuming yes" >&6; } +- +-else +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +- +- #include +- #include +- #include +- #include +- +-int +-main () +-{ +- errno = 0; +- prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0); +- exit(errno == EFAULT ? 0 : 1); +- ; +- return 0; +-} +-_ACEOF +-if ac_fn_c_try_run "$LINENO"; then : +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +-else +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +- # Disable seccomp filter as a target +- have_seccomp_filter=0 +- +-fi +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext +-fi +- +-fi + + use_stack_protector=1 + +@@ -11898,25 +11856,28 @@ + + fi + ++SANDBOX_STYLE="" + if test "x$sandbox_arg" = "xsystrace" || \ + ( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then + test "x$have_systr_policy_kill" != "x1" && \ + as_fn_error $? "systrace sandbox requires systrace headers and SYSTR_POLICY_KILL support" "$LINENO" 5 +- SANDBOX_STYLE="systrace" ++ SANDBOX_STYLE="$SANDBOX_STYLE systrace" + + $as_echo "#define SANDBOX_SYSTRACE 1" >>confdefs.h + +-elif test "x$sandbox_arg" = "xdarwin" || \ ++fi ++if test "x$sandbox_arg" = "xdarwin" || \ + ( test -z "$sandbox_arg" && test "x$ac_cv_func_sandbox_init" = "xyes" && \ + test "x$ac_cv_header_sandbox_h" = "xyes") ; then + test "x$ac_cv_func_sandbox_init" != "xyes" -o \ + "x$ac_cv_header_sandbox_h" != "xyes" && \ + as_fn_error $? "Darwin seatbelt sandbox requires sandbox.h and sandbox_init function" "$LINENO" 5 +- SANDBOX_STYLE="darwin" ++ SANDBOX_STYLE="$SANDBOX_STYLE darwin" + + $as_echo "#define SANDBOX_DARWIN 1" >>confdefs.h + +-elif test "x$sandbox_arg" = "xseccomp_filter" || \ ++fi ++if test "x$sandbox_arg" = "xseccomp_filter" || \ + ( test -z "$sandbox_arg" && \ + test "x$have_seccomp_filter" = "x1" && \ + test "x$ac_cv_header_linux_audit_h" = "xyes" && \ +@@ -11931,27 +11892,28 @@ + as_fn_error $? "seccomp_filter sandbox requires seccomp headers" "$LINENO" 5 + test "x$ac_cv_func_prctl" != "xyes" && \ + as_fn_error $? "seccomp_filter sandbox requires prctl function" "$LINENO" 5 +- SANDBOX_STYLE="seccomp_filter" ++ SANDBOX_STYLE="$SANDBOX_STYLE seccomp_filter" + + $as_echo "#define SANDBOX_SECCOMP_FILTER 1" >>confdefs.h + +-elif test "x$sandbox_arg" = "xrlimit" || \ ++fi ++if test "x$sandbox_arg" = "xrlimit" || \ + ( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" ) ; then + test "x$ac_cv_func_setrlimit" != "xyes" && \ + as_fn_error $? "rlimit sandbox requires setrlimit function" "$LINENO" 5 +- SANDBOX_STYLE="rlimit" ++ SANDBOX_STYLE="$SANDBOX_STYLE rlimit" + + $as_echo "#define SANDBOX_RLIMIT 1" >>confdefs.h + +-elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ ++fi ++if test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ + test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then +- SANDBOX_STYLE="none" +- +-$as_echo "#define SANDBOX_NULL 1" >>confdefs.h +- +-else ++ SANDBOX_STYLE="$SANDBOX_STYLE none" ++fi ++if test -z "$SANDBOX_STYLE" ; then + as_fn_error $? "unsupported --with-sandbox" "$LINENO" 5 + fi ++SANDBOX_STYLE="${SANDBOX_STYLE# }" + + # Cheap hack to ensure NEWS-OS libraries are arranged right. + if test ! -z "$SONY" ; then +Index: b/config.h.in +=================================================================== +--- a/config.h.in ++++ b/config.h.in +@@ -1365,9 +1365,6 @@ + /* Sandbox using Darwin sandbox_init(3) */ + #undef SANDBOX_DARWIN + +-/* no privsep sandboxing */ +-#undef SANDBOX_NULL +- + /* Sandbox using setrlimit(2) */ + #undef SANDBOX_RLIMIT + +Index: b/sandbox-darwin.c +=================================================================== +--- a/sandbox-darwin.c ++++ b/sandbox-darwin.c +@@ -16,10 +16,12 @@ + + #include "includes.h" + +-#ifdef SANDBOX_DARWIN +- + #include + ++#include "ssh-sandbox.h" ++ ++#ifdef SANDBOX_DARWIN ++ + #include + + #include +@@ -30,7 +32,6 @@ + #include + + #include "log.h" +-#include "sandbox.h" + #include "xmalloc.h" + + /* Darwin/OS X sandbox */ +@@ -39,8 +40,14 @@ + pid_t child_pid; + }; + +-struct ssh_sandbox * +-ssh_sandbox_init(void) ++static int ++sandbox_darwin_probe(void) ++{ ++ return 1; ++} ++ ++static void * ++sandbox_darwin_init(void) + { + struct ssh_sandbox *box; + +@@ -55,9 +62,10 @@ + return box; + } + +-void +-ssh_sandbox_child(struct ssh_sandbox *box) ++static void ++sandbox_darwin_child(void *vbox) + { ++ struct ssh_sandbox *box = vbox; + char *errmsg; + struct rlimit rl_zero; + +@@ -82,17 +90,39 @@ + __func__, strerror(errno)); + } + +-void +-ssh_sandbox_parent_finish(struct ssh_sandbox *box) ++static void ++sandbox_darwin_parent_finish(void *vbox) + { +- free(box); ++ free(vbox); + debug3("%s: finished", __func__); + } + +-void +-ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) ++static void ++sandbox_darwin_parent_preauth(void *box, pid_t child_pid) + { ++ struct ssh_sandbox *box = vbox; ++ + box->child_pid = child_pid; + } + ++Sandbox ssh_sandbox_darwin = { ++ "darwin", ++ sandbox_darwin_probe, ++ sandbox_darwin_init, ++ sandbox_darwin_child, ++ sandbox_darwin_parent_finish, ++ sandbox_darwin_parent_preauth ++}; ++ ++#else /* !SANDBOX_DARWIN */ ++ ++Sandbox ssh_sandbox_darwin = { ++ "darwin", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ + #endif /* SANDBOX_DARWIN */ +Index: b/sandbox-null.c +=================================================================== +--- a/sandbox-null.c ++++ b/sandbox-null.c +@@ -17,8 +17,6 @@ + + #include "includes.h" + +-#ifdef SANDBOX_NULL +- + #include + + #include +@@ -38,8 +36,14 @@ + int junk; + }; + +-struct ssh_sandbox * +-ssh_sandbox_init(void) ++static int ++sandbox_null_probe(void) ++{ ++ return 1; ++} ++ ++static void * ++sandbox_null_init(void) + { + struct ssh_sandbox *box; + +@@ -51,22 +55,29 @@ + return box; + } + +-void +-ssh_sandbox_child(struct ssh_sandbox *box) ++static void ++sandbox_null_child(void *vbox) + { + /* Nothing to do here */ + } + +-void +-ssh_sandbox_parent_finish(struct ssh_sandbox *box) ++static void ++sandbox_null_parent_finish(void *vbox) + { +- free(box); ++ free(vbox); + } + +-void +-ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) ++static void ++sandbox_null_parent_preauth(void *box, pid_t child_pid) + { + /* Nothing to do here */ + } + +-#endif /* SANDBOX_NULL */ ++Sandbox ssh_sandbox_null = { ++ "null", ++ sandbox_null_probe, ++ sandbox_null_init, ++ sandbox_null_child, ++ sandbox_null_parent_finish, ++ sandbox_null_parent_preauth ++}; +Index: b/sandbox-rlimit.c +=================================================================== +--- a/sandbox-rlimit.c ++++ b/sandbox-rlimit.c +@@ -17,9 +17,12 @@ + + #include "includes.h" + ++#include ++ ++#include "ssh-sandbox.h" ++ + #ifdef SANDBOX_RLIMIT + +-#include + #include + #include + #include +@@ -32,7 +35,6 @@ + #include + + #include "log.h" +-#include "ssh-sandbox.h" + #include "xmalloc.h" + + /* Minimal sandbox that sets zero nfiles, nprocs and filesize rlimits */ +@@ -41,8 +43,14 @@ + pid_t child_pid; + }; + +-struct ssh_sandbox * +-ssh_sandbox_init(void) ++static int ++sandbox_rlimit_probe(void) ++{ ++ return 1; ++} ++ ++static void * ++sandbox_rlimit_init(void) + { + struct ssh_sandbox *box; + +@@ -57,8 +65,8 @@ + return box; + } + +-void +-ssh_sandbox_child(struct ssh_sandbox *box) ++static void ++sandbox_rlimit_child(void *vbox) + { + struct rlimit rl_zero; + +@@ -77,17 +85,39 @@ + #endif + } + +-void +-ssh_sandbox_parent_finish(struct ssh_sandbox *box) ++static void ++sandbox_rlimit_parent_finish(void *vbox) + { +- free(box); ++ free(vbox); + debug3("%s: finished", __func__); + } + +-void +-ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) ++static void ++sandbox_rlimit_parent_preauth(void *vbox, pid_t child_pid) + { ++ struct ssh_sandbox *box = vbox; ++ + box->child_pid = child_pid; + } + ++Sandbox ssh_sandbox_rlimit = { ++ "rlimit", ++ sandbox_rlimit_probe, ++ sandbox_rlimit_init, ++ sandbox_rlimit_child, ++ sandbox_rlimit_parent_finish, ++ sandbox_rlimit_parent_preauth ++}; ++ ++#else /* !SANDBOX_RLIMIT */ ++ ++Sandbox ssh_sandbox_rlimit = { ++ "rlimit", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ + #endif /* SANDBOX_RLIMIT */ +Index: b/sandbox-seccomp-filter.c +=================================================================== +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -35,11 +35,15 @@ + + #include "includes.h" + ++#include ++ ++#include "ssh-sandbox.h" ++ + #ifdef SANDBOX_SECCOMP_FILTER + +-#include + #include + #include ++#include + + #include + #include +@@ -57,7 +61,6 @@ + #include + + #include "log.h" +-#include "ssh-sandbox.h" + #include "xmalloc.h" + + /* Linux seccomp_filter sandbox */ +@@ -122,8 +125,33 @@ + pid_t child_pid; + }; + +-struct ssh_sandbox * +-ssh_sandbox_init(void) ++static int ++sandbox_seccomp_filter_probe(void) ++{ ++ int status; ++ pid_t pid; ++ ++ pid = fork(); ++ if (pid == -1) { ++ fatal("fork of seccomp_filter probe child failed"); ++ } else if (pid != 0) { ++ /* parent */ ++ while (waitpid(pid, &status, 0) < 0) { ++ if (errno == EINTR) ++ continue; ++ fatal("%s: waitpid: %s", __func__, strerror(errno)); ++ } ++ return (WIFEXITED(status) && WEXITSTATUS(status) == 0); ++ } else { ++ /* child */ ++ errno = 0; ++ prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0); ++ _exit(errno == EFAULT ? 0 : 1); ++ } ++} ++ ++static void * ++sandbox_seccomp_filter_init(void) + { + struct ssh_sandbox *box; + +@@ -143,7 +171,8 @@ + void mm_log_handler(LogLevel level, const char *msg, void *ctx); + + static void +-ssh_sandbox_violation(int signum, siginfo_t *info, void *void_context) ++sandbox_seccomp_filter_violation(int signum, siginfo_t *info, ++ void *void_context) + { + char msg[256]; + +@@ -155,7 +184,7 @@ + } + + static void +-ssh_sandbox_child_debugging(void) ++sandbox_seccomp_filter_child_debugging(void) + { + struct sigaction act; + sigset_t mask; +@@ -165,7 +194,7 @@ + sigemptyset(&mask); + sigaddset(&mask, SIGSYS); + +- act.sa_sigaction = &ssh_sandbox_violation; ++ act.sa_sigaction = &sandbox_seccomp_filter_violation; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGSYS, &act, NULL) == -1) + fatal("%s: sigaction(SIGSYS): %s", __func__, strerror(errno)); +@@ -175,8 +204,8 @@ + } + #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ + +-void +-ssh_sandbox_child(struct ssh_sandbox *box) ++static void ++sandbox_seccomp_filter_child(void *vbox) + { + struct rlimit rl_zero; + +@@ -193,7 +222,7 @@ + __func__, strerror(errno)); + + #ifdef SANDBOX_SECCOMP_FILTER_DEBUG +- ssh_sandbox_child_debugging(); ++ sandbox_seccomp_filter_child_debugging(); + #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ + + debug3("%s: setting PR_SET_NO_NEW_PRIVS", __func__); +@@ -206,17 +235,39 @@ + __func__, strerror(errno)); + } + +-void +-ssh_sandbox_parent_finish(struct ssh_sandbox *box) ++static void ++sandbox_seccomp_filter_parent_finish(void *vbox) + { +- free(box); ++ free(vbox); + debug3("%s: finished", __func__); + } + +-void +-ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) ++static void ++sandbox_seccomp_filter_parent_preauth(void *vbox, pid_t child_pid) + { ++ struct ssh_sandbox *box = vbox; ++ + box->child_pid = child_pid; + } + ++Sandbox ssh_sandbox_seccomp_filter = { ++ "seccomp_filter", ++ sandbox_seccomp_filter_probe, ++ sandbox_seccomp_filter_init, ++ sandbox_seccomp_filter_child, ++ sandbox_seccomp_filter_parent_finish, ++ sandbox_seccomp_filter_parent_preauth ++}; ++ ++#else /* !SANDBOX_SECCOMP_FILTER */ ++ ++Sandbox ssh_sandbox_seccomp_filter = { ++ "seccomp_filter", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ + #endif /* SANDBOX_SECCOMP_FILTER */ +Index: b/sandbox-systrace.c +=================================================================== +--- a/sandbox-systrace.c ++++ b/sandbox-systrace.c +@@ -17,9 +17,12 @@ + + #include "includes.h" + ++#include ++ ++#include "ssh-sandbox.h" ++ + #ifdef SANDBOX_SYSTRACE + +-#include + #include + #include + #include +@@ -38,7 +41,6 @@ + + #include "atomicio.h" + #include "log.h" +-#include "ssh-sandbox.h" + #include "xmalloc.h" + + struct sandbox_policy { +@@ -74,8 +76,14 @@ + pid_t child_pid; + }; + +-struct ssh_sandbox * +-ssh_sandbox_init(void) ++static int ++sandbox_systrace_probe(void) ++{ ++ return 1; ++} ++ ++static void * ++sandbox_systrace_init(void) + { + struct ssh_sandbox *box; + int s[2]; +@@ -92,9 +100,10 @@ + return box; + } + +-void +-ssh_sandbox_child(struct ssh_sandbox *box) ++static void ++sandbox_systrace_child(void *vbox) + { ++ struct ssh_sandbox *box = vbox; + char whatever = 0; + + close(box->parent_sock); +@@ -110,7 +119,7 @@ + } + + static void +-ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid, ++sandbox_systrace_parent(struct ssh_sandbox *box, pid_t child_pid, + const struct sandbox_policy *allowed_syscalls) + { + int dev_systrace, i, j, found; +@@ -179,9 +188,11 @@ + close(box->parent_sock); + } + +-void +-ssh_sandbox_parent_finish(struct ssh_sandbox *box) ++static void ++sandbox_systrace_parent_finish(void *vbox) + { ++ struct ssh_sandbox *box = vbox; ++ + /* Closing this before the child exits will terminate it */ + close(box->systrace_fd); + +@@ -189,10 +200,32 @@ + debug3("%s: finished", __func__); + } + +-void +-ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) ++static void ++sandbox_systrace_parent_preauth(void *vbox, pid_t child_pid) + { ++ struct ssh_sandbox *box = vbox; ++ + ssh_sandbox_parent(box, child_pid, preauth_policy); + } + ++Sandbox ssh_sandbox_systrace = { ++ "systrace", ++ sandbox_systrace_probe, ++ sandbox_systrace_init, ++ sandbox_systrace_child, ++ sandbox_systrace_parent_finish, ++ sandbox_systrace_parent_preauth ++}; ++ ++#else /* !SANDBOX_SYSTRACE */ ++ ++Sandbox ssh_sandbox_systrace = { ++ "systrace", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ + #endif /* SANDBOX_SYSTRACE */ +Index: b/sandbox.c +=================================================================== +--- /dev/null ++++ b/sandbox.c +@@ -0,0 +1,82 @@ ++/* $Id$ */ ++/* ++ * Copyright (c) 2012 Colin Watson ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++ ++#include ++#include ++ ++#include "log.h" ++#include "ssh-sandbox.h" ++ ++static Sandbox *sandboxes[] = { ++ &ssh_sandbox_systrace, ++ &ssh_sandbox_darwin, ++ &ssh_sandbox_seccomp_filter, ++ &ssh_sandbox_rlimit, ++ &ssh_sandbox_null, ++ NULL ++}; ++ ++static Sandbox *selected; ++ ++static void ++sandbox_select(void) ++{ ++ Sandbox **sandbox; ++ ++ if (selected) ++ return; ++ ++ for (sandbox = sandboxes; sandbox; sandbox++) { ++ if ((*sandbox)->probe && (*sandbox)->probe()) { ++ selected = *sandbox; ++ return; ++ } ++ } ++ ++ /* should never happen, as ssh_sandbox_null always succeeds */ ++ fatal("no sandbox implementation found"); ++} ++ ++void * ++ssh_sandbox_init(void) ++{ ++ sandbox_select(); ++ return selected->init(); ++} ++ ++void ++ssh_sandbox_child(void *box) ++{ ++ sandbox_select(); ++ return selected->child(box); ++} ++ ++void ++ssh_sandbox_parent_finish(void *box) ++{ ++ sandbox_select(); ++ return selected->parent_finish(box); ++} ++ ++void ++ssh_sandbox_parent_preauth(void *box, pid_t child_pid) ++{ ++ sandbox_select(); ++ return selected->parent_preauth(box, child_pid); ++} +Index: b/ssh-sandbox.h +=================================================================== +--- a/ssh-sandbox.h ++++ b/ssh-sandbox.h +@@ -15,9 +15,24 @@ + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +-struct ssh_sandbox; ++typedef struct Sandbox Sandbox; + +-struct ssh_sandbox *ssh_sandbox_init(void); +-void ssh_sandbox_child(struct ssh_sandbox *); +-void ssh_sandbox_parent_finish(struct ssh_sandbox *); +-void ssh_sandbox_parent_preauth(struct ssh_sandbox *, pid_t); ++struct Sandbox { ++ const char *name; ++ int (*probe)(void); ++ void *(*init)(void); ++ void (*child)(void *); ++ void (*parent_finish)(void *); ++ void (*parent_preauth)(void *, pid_t); ++}; ++ ++void *ssh_sandbox_init(void); ++void ssh_sandbox_child(void *); ++void ssh_sandbox_parent_finish(void *); ++void ssh_sandbox_parent_preauth(void *, pid_t); ++ ++extern Sandbox ssh_sandbox_systrace; ++extern Sandbox ssh_sandbox_darwin; ++extern Sandbox ssh_sandbox_seccomp_filter; ++extern Sandbox ssh_sandbox_rlimit; ++extern Sandbox ssh_sandbox_null; +Index: b/sshd.c +=================================================================== +--- a/sshd.c ++++ b/sshd.c +@@ -631,7 +631,7 @@ + { + int status; + pid_t pid; +- struct ssh_sandbox *box = NULL; ++ void *box = NULL; + + /* Set up unprivileged child process to deal with network data */ + pmonitor = monitor_init(); diff --git a/debian/patches/series b/debian/patches/series index 772dadb61..d6bae11a0 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -39,6 +39,7 @@ doc-hash-tab-completion.patch auth-log-verbosity.patch cross-pkg-config.patch configure-bashism.patch +sandbox-fallback.patch # Debian-specific configuration gnome-ssh-askpass2-icon.patch diff --git a/sandbox-darwin.c b/sandbox-darwin.c index 69901ef14..49330642b 100644 --- a/sandbox-darwin.c +++ b/sandbox-darwin.c @@ -16,10 +16,12 @@ #include "includes.h" -#ifdef SANDBOX_DARWIN - #include +#include "ssh-sandbox.h" + +#ifdef SANDBOX_DARWIN + #include #include @@ -30,7 +32,6 @@ #include #include "log.h" -#include "sandbox.h" #include "xmalloc.h" /* Darwin/OS X sandbox */ @@ -39,8 +40,14 @@ struct ssh_sandbox { pid_t child_pid; }; -struct ssh_sandbox * -ssh_sandbox_init(void) +static int +sandbox_darwin_probe(void) +{ + return 1; +} + +static void * +sandbox_darwin_init(void) { struct ssh_sandbox *box; @@ -55,9 +62,10 @@ ssh_sandbox_init(void) return box; } -void -ssh_sandbox_child(struct ssh_sandbox *box) +static void +sandbox_darwin_child(void *vbox) { + struct ssh_sandbox *box = vbox; char *errmsg; struct rlimit rl_zero; @@ -82,17 +90,39 @@ ssh_sandbox_child(struct ssh_sandbox *box) __func__, strerror(errno)); } -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) +static void +sandbox_darwin_parent_finish(void *vbox) { - free(box); + free(vbox); debug3("%s: finished", __func__); } -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) +static void +sandbox_darwin_parent_preauth(void *box, pid_t child_pid) { + struct ssh_sandbox *box = vbox; + box->child_pid = child_pid; } +Sandbox ssh_sandbox_darwin = { + "darwin", + sandbox_darwin_probe, + sandbox_darwin_init, + sandbox_darwin_child, + sandbox_darwin_parent_finish, + sandbox_darwin_parent_preauth +}; + +#else /* !SANDBOX_DARWIN */ + +Sandbox ssh_sandbox_darwin = { + "darwin", + NULL, + NULL, + NULL, + NULL, + NULL +}; + #endif /* SANDBOX_DARWIN */ diff --git a/sandbox-null.c b/sandbox-null.c index 29fa9669f..f62ac4b07 100644 --- a/sandbox-null.c +++ b/sandbox-null.c @@ -17,8 +17,6 @@ #include "includes.h" -#ifdef SANDBOX_NULL - #include #include @@ -38,8 +36,14 @@ struct ssh_sandbox { int junk; }; -struct ssh_sandbox * -ssh_sandbox_init(void) +static int +sandbox_null_probe(void) +{ + return 1; +} + +static void * +sandbox_null_init(void) { struct ssh_sandbox *box; @@ -51,22 +55,29 @@ ssh_sandbox_init(void) return box; } -void -ssh_sandbox_child(struct ssh_sandbox *box) +static void +sandbox_null_child(void *vbox) { /* Nothing to do here */ } -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) +static void +sandbox_null_parent_finish(void *vbox) { - free(box); + free(vbox); } -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) +static void +sandbox_null_parent_preauth(void *box, pid_t child_pid) { /* Nothing to do here */ } -#endif /* SANDBOX_NULL */ +Sandbox ssh_sandbox_null = { + "null", + sandbox_null_probe, + sandbox_null_init, + sandbox_null_child, + sandbox_null_parent_finish, + sandbox_null_parent_preauth +}; diff --git a/sandbox-rlimit.c b/sandbox-rlimit.c index 761e9284f..bfd1d446e 100644 --- a/sandbox-rlimit.c +++ b/sandbox-rlimit.c @@ -17,9 +17,12 @@ #include "includes.h" +#include + +#include "ssh-sandbox.h" + #ifdef SANDBOX_RLIMIT -#include #include #include #include @@ -32,7 +35,6 @@ #include #include "log.h" -#include "ssh-sandbox.h" #include "xmalloc.h" /* Minimal sandbox that sets zero nfiles, nprocs and filesize rlimits */ @@ -41,8 +43,14 @@ struct ssh_sandbox { pid_t child_pid; }; -struct ssh_sandbox * -ssh_sandbox_init(void) +static int +sandbox_rlimit_probe(void) +{ + return 1; +} + +static void * +sandbox_rlimit_init(void) { struct ssh_sandbox *box; @@ -57,8 +65,8 @@ ssh_sandbox_init(void) return box; } -void -ssh_sandbox_child(struct ssh_sandbox *box) +static void +sandbox_rlimit_child(void *vbox) { struct rlimit rl_zero; @@ -77,17 +85,39 @@ ssh_sandbox_child(struct ssh_sandbox *box) #endif } -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) +static void +sandbox_rlimit_parent_finish(void *vbox) { - free(box); + free(vbox); debug3("%s: finished", __func__); } -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) +static void +sandbox_rlimit_parent_preauth(void *vbox, pid_t child_pid) { + struct ssh_sandbox *box = vbox; + box->child_pid = child_pid; } +Sandbox ssh_sandbox_rlimit = { + "rlimit", + sandbox_rlimit_probe, + sandbox_rlimit_init, + sandbox_rlimit_child, + sandbox_rlimit_parent_finish, + sandbox_rlimit_parent_preauth +}; + +#else /* !SANDBOX_RLIMIT */ + +Sandbox ssh_sandbox_rlimit = { + "rlimit", + NULL, + NULL, + NULL, + NULL, + NULL +}; + #endif /* SANDBOX_RLIMIT */ diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c index 686812957..a564b1316 100644 --- a/sandbox-seccomp-filter.c +++ b/sandbox-seccomp-filter.c @@ -35,11 +35,15 @@ #include "includes.h" +#include + +#include "ssh-sandbox.h" + #ifdef SANDBOX_SECCOMP_FILTER -#include #include #include +#include #include #include @@ -57,7 +61,6 @@ #include #include "log.h" -#include "ssh-sandbox.h" #include "xmalloc.h" /* Linux seccomp_filter sandbox */ @@ -122,8 +125,33 @@ struct ssh_sandbox { pid_t child_pid; }; -struct ssh_sandbox * -ssh_sandbox_init(void) +static int +sandbox_seccomp_filter_probe(void) +{ + int status; + pid_t pid; + + pid = fork(); + if (pid == -1) { + fatal("fork of seccomp_filter probe child failed"); + } else if (pid != 0) { + /* parent */ + while (waitpid(pid, &status, 0) < 0) { + if (errno == EINTR) + continue; + fatal("%s: waitpid: %s", __func__, strerror(errno)); + } + return (WIFEXITED(status) && WEXITSTATUS(status) == 0); + } else { + /* child */ + errno = 0; + prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0); + _exit(errno == EFAULT ? 0 : 1); + } +} + +static void * +sandbox_seccomp_filter_init(void) { struct ssh_sandbox *box; @@ -143,7 +171,8 @@ extern struct monitor *pmonitor; void mm_log_handler(LogLevel level, const char *msg, void *ctx); static void -ssh_sandbox_violation(int signum, siginfo_t *info, void *void_context) +sandbox_seccomp_filter_violation(int signum, siginfo_t *info, + void *void_context) { char msg[256]; @@ -155,7 +184,7 @@ ssh_sandbox_violation(int signum, siginfo_t *info, void *void_context) } static void -ssh_sandbox_child_debugging(void) +sandbox_seccomp_filter_child_debugging(void) { struct sigaction act; sigset_t mask; @@ -165,7 +194,7 @@ ssh_sandbox_child_debugging(void) sigemptyset(&mask); sigaddset(&mask, SIGSYS); - act.sa_sigaction = &ssh_sandbox_violation; + act.sa_sigaction = &sandbox_seccomp_filter_violation; act.sa_flags = SA_SIGINFO; if (sigaction(SIGSYS, &act, NULL) == -1) fatal("%s: sigaction(SIGSYS): %s", __func__, strerror(errno)); @@ -175,8 +204,8 @@ ssh_sandbox_child_debugging(void) } #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ -void -ssh_sandbox_child(struct ssh_sandbox *box) +static void +sandbox_seccomp_filter_child(void *vbox) { struct rlimit rl_zero; @@ -193,7 +222,7 @@ ssh_sandbox_child(struct ssh_sandbox *box) __func__, strerror(errno)); #ifdef SANDBOX_SECCOMP_FILTER_DEBUG - ssh_sandbox_child_debugging(); + sandbox_seccomp_filter_child_debugging(); #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ debug3("%s: setting PR_SET_NO_NEW_PRIVS", __func__); @@ -206,17 +235,39 @@ ssh_sandbox_child(struct ssh_sandbox *box) __func__, strerror(errno)); } -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) +static void +sandbox_seccomp_filter_parent_finish(void *vbox) { - free(box); + free(vbox); debug3("%s: finished", __func__); } -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) +static void +sandbox_seccomp_filter_parent_preauth(void *vbox, pid_t child_pid) { + struct ssh_sandbox *box = vbox; + box->child_pid = child_pid; } +Sandbox ssh_sandbox_seccomp_filter = { + "seccomp_filter", + sandbox_seccomp_filter_probe, + sandbox_seccomp_filter_init, + sandbox_seccomp_filter_child, + sandbox_seccomp_filter_parent_finish, + sandbox_seccomp_filter_parent_preauth +}; + +#else /* !SANDBOX_SECCOMP_FILTER */ + +Sandbox ssh_sandbox_seccomp_filter = { + "seccomp_filter", + NULL, + NULL, + NULL, + NULL, + NULL +}; + #endif /* SANDBOX_SECCOMP_FILTER */ diff --git a/sandbox-systrace.c b/sandbox-systrace.c index 5a39f4fe1..04f54a3b6 100644 --- a/sandbox-systrace.c +++ b/sandbox-systrace.c @@ -17,9 +17,12 @@ #include "includes.h" +#include + +#include "ssh-sandbox.h" + #ifdef SANDBOX_SYSTRACE -#include #include #include #include @@ -38,7 +41,6 @@ #include "atomicio.h" #include "log.h" -#include "ssh-sandbox.h" #include "xmalloc.h" struct sandbox_policy { @@ -74,8 +76,14 @@ struct ssh_sandbox { pid_t child_pid; }; -struct ssh_sandbox * -ssh_sandbox_init(void) +static int +sandbox_systrace_probe(void) +{ + return 1; +} + +static void * +sandbox_systrace_init(void) { struct ssh_sandbox *box; int s[2]; @@ -92,9 +100,10 @@ ssh_sandbox_init(void) return box; } -void -ssh_sandbox_child(struct ssh_sandbox *box) +static void +sandbox_systrace_child(void *vbox) { + struct ssh_sandbox *box = vbox; char whatever = 0; close(box->parent_sock); @@ -110,7 +119,7 @@ ssh_sandbox_child(struct ssh_sandbox *box) } static void -ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid, +sandbox_systrace_parent(struct ssh_sandbox *box, pid_t child_pid, const struct sandbox_policy *allowed_syscalls) { int dev_systrace, i, j, found; @@ -179,9 +188,11 @@ ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid, close(box->parent_sock); } -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) +static void +sandbox_systrace_parent_finish(void *vbox) { + struct ssh_sandbox *box = vbox; + /* Closing this before the child exits will terminate it */ close(box->systrace_fd); @@ -189,10 +200,32 @@ ssh_sandbox_parent_finish(struct ssh_sandbox *box) debug3("%s: finished", __func__); } -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) +static void +sandbox_systrace_parent_preauth(void *vbox, pid_t child_pid) { + struct ssh_sandbox *box = vbox; + ssh_sandbox_parent(box, child_pid, preauth_policy); } +Sandbox ssh_sandbox_systrace = { + "systrace", + sandbox_systrace_probe, + sandbox_systrace_init, + sandbox_systrace_child, + sandbox_systrace_parent_finish, + sandbox_systrace_parent_preauth +}; + +#else /* !SANDBOX_SYSTRACE */ + +Sandbox ssh_sandbox_systrace = { + "systrace", + NULL, + NULL, + NULL, + NULL, + NULL +}; + #endif /* SANDBOX_SYSTRACE */ diff --git a/sandbox.c b/sandbox.c new file mode 100644 index 000000000..20fd57d16 --- /dev/null +++ b/sandbox.c @@ -0,0 +1,82 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Colin Watson + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "log.h" +#include "ssh-sandbox.h" + +static Sandbox *sandboxes[] = { + &ssh_sandbox_systrace, + &ssh_sandbox_darwin, + &ssh_sandbox_seccomp_filter, + &ssh_sandbox_rlimit, + &ssh_sandbox_null, + NULL +}; + +static Sandbox *selected; + +static void +sandbox_select(void) +{ + Sandbox **sandbox; + + if (selected) + return; + + for (sandbox = sandboxes; sandbox; sandbox++) { + if ((*sandbox)->probe && (*sandbox)->probe()) { + selected = *sandbox; + return; + } + } + + /* should never happen, as ssh_sandbox_null always succeeds */ + fatal("no sandbox implementation found"); +} + +void * +ssh_sandbox_init(void) +{ + sandbox_select(); + return selected->init(); +} + +void +ssh_sandbox_child(void *box) +{ + sandbox_select(); + return selected->child(box); +} + +void +ssh_sandbox_parent_finish(void *box) +{ + sandbox_select(); + return selected->parent_finish(box); +} + +void +ssh_sandbox_parent_preauth(void *box, pid_t child_pid) +{ + sandbox_select(); + return selected->parent_preauth(box, child_pid); +} diff --git a/ssh-sandbox.h b/ssh-sandbox.h index dfecd5aa0..7ee4460d8 100644 --- a/ssh-sandbox.h +++ b/ssh-sandbox.h @@ -15,9 +15,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct ssh_sandbox; +typedef struct Sandbox Sandbox; -struct ssh_sandbox *ssh_sandbox_init(void); -void ssh_sandbox_child(struct ssh_sandbox *); -void ssh_sandbox_parent_finish(struct ssh_sandbox *); -void ssh_sandbox_parent_preauth(struct ssh_sandbox *, pid_t); +struct Sandbox { + const char *name; + int (*probe)(void); + void *(*init)(void); + void (*child)(void *); + void (*parent_finish)(void *); + void (*parent_preauth)(void *, pid_t); +}; + +void *ssh_sandbox_init(void); +void ssh_sandbox_child(void *); +void ssh_sandbox_parent_finish(void *); +void ssh_sandbox_parent_preauth(void *, pid_t); + +extern Sandbox ssh_sandbox_systrace; +extern Sandbox ssh_sandbox_darwin; +extern Sandbox ssh_sandbox_seccomp_filter; +extern Sandbox ssh_sandbox_rlimit; +extern Sandbox ssh_sandbox_null; diff --git a/sshd.c b/sshd.c index e032c1720..038fb2a56 100644 --- a/sshd.c +++ b/sshd.c @@ -631,7 +631,7 @@ privsep_preauth(Authctxt *authctxt) { int status; pid_t pid; - struct ssh_sandbox *box = NULL; + void *box = NULL; /* Set up unprivileged child process to deal with network data */ pmonitor = monitor_init(); -- cgit v1.2.3