From 868ea1ea1c1bfdbee5dbad78f81999c5983ecf31 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 17 Jan 2014 16:47:04 +1100 Subject: [PATCH] - (djm) [Makefile.in configure.ac sandbox-capsicum.c sandbox-darwin.c] [sandbox-null.c sandbox-rlimit.c sandbox-seccomp-filter.c] [sandbox-systrace.c ssh-sandbox.h sshd.c] Support preauth sandboxing using the Capsicum API introduced in FreeBSD 10. Patch by Dag-Erling Smorgrav, updated by Loganaden Velvindron @ AfriNIC; ok dtucker@ --- ChangeLog | 5 ++ Makefile.in | 5 +- configure.ac | 17 +++++- sandbox-capsicum.c | 118 +++++++++++++++++++++++++++++++++++++++ sandbox-darwin.c | 2 +- sandbox-null.c | 2 +- sandbox-rlimit.c | 2 +- sandbox-seccomp-filter.c | 2 +- sandbox-systrace.c | 2 +- ssh-sandbox.h | 3 +- sshd.c | 2 +- 11 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 sandbox-capsicum.c diff --git a/ChangeLog b/ChangeLog index 257a36ba2..1bf7e0dca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,11 @@ - dtucker@cvs.openbsd.org 2014/01/17 05:26:41 [digest.c] remove unused includes. ok djm@ + - (djm) [Makefile.in configure.ac sandbox-capsicum.c sandbox-darwin.c] + [sandbox-null.c sandbox-rlimit.c sandbox-seccomp-filter.c] + [sandbox-systrace.c ssh-sandbox.h sshd.c] Support preauth sandboxing + using the Capsicum API introduced in FreeBSD 10. Patch by Dag-Erling + Smorgrav, updated by Loganaden Velvindron @ AfriNIC; ok dtucker@ 20140118 - (djm) OpenBSD CVS Sync diff --git a/Makefile.in b/Makefile.in index 4a930c665..f5dd3b834 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.349 2014/01/09 23:58:53 djm Exp $ +# $Id: Makefile.in,v 1.350 2014/01/17 05:47:04 djm Exp $ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -96,7 +96,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.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-seccomp-filter.o sandbox-capsicum.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 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 sshd_config.5 ssh_config.5 @@ -472,4 +472,3 @@ package: $(CONFIGFILES) $(MANPAGES) $(TARGETS) if [ "@MAKE_PACKAGE_SUPPORTED@" = yes ]; then \ sh buildpkg.sh; \ fi - diff --git a/configure.ac b/configure.ac index abd912f5a..f14e177fc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -# $Id: configure.ac,v 1.549 2014/01/17 04:12:16 dtucker Exp $ +# $Id: configure.ac,v 1.550 2014/01/17 05:47:04 djm Exp $ # # Copyright (c) 1999-2004 Damien Miller # @@ -15,7 +15,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org]) -AC_REVISION($Revision: 1.549 $) +AC_REVISION($Revision: 1.550 $) AC_CONFIG_SRCDIR([ssh.c]) AC_LANG([C]) @@ -120,6 +120,10 @@ AC_CHECK_DECL([PR_SET_NO_NEW_PRIVS], [have_linux_no_new_privs=1], , [ #include #include ]) +AC_CHECK_DECL([cap_enter], [have_cap_enter=1], , [ + #include +]) + use_stack_protector=1 use_toolchain_hardening=1 AC_ARG_WITH([stackprotect], @@ -2835,7 +2839,7 @@ fi # Decide which sandbox style to use sandbox_arg="" AC_ARG_WITH([sandbox], - [ --with-sandbox=style Specify privilege separation sandbox (no, darwin, rlimit, systrace, seccomp_filter)], + [ --with-sandbox=style Specify privilege separation sandbox (no, darwin, rlimit, systrace, seccomp_filter, capsicum)], [ if test "x$withval" = "xyes" ; then sandbox_arg="" @@ -2974,6 +2978,13 @@ elif test "x$sandbox_arg" = "xrlimit" || \ AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit]) SANDBOX_STYLE="rlimit" AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)]) +elif test "x$sandbox_arg" = "xcapsicum" || \ + ( test -z "$sandbox_arg" && \ + test "x$have_cap_enter" = "x1") ; then + test "x$have_cap_enter" != "x1" && \ + AC_MSG_ERROR([capsicum sandbox requires cap_enter function]) + SANDBOX_STYLE="capsicum" + AC_DEFINE([SANDBOX_CAPSICUM], [1], [Sandbox using capsicum]) elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then SANDBOX_STYLE="none" diff --git a/sandbox-capsicum.c b/sandbox-capsicum.c new file mode 100644 index 000000000..5853a13ef --- /dev/null +++ b/sandbox-capsicum.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2011 Dag-Erling Smorgrav + * + * 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 "includes.h" + +#ifdef SANDBOX_CAPSICUM + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "monitor.h" +#include "ssh-sandbox.h" +#include "xmalloc.h" + +/* + * Capsicum sandbox that sets zero nfiles, nprocs and filesize rlimits, + * limits rights on stdout, stdin, stderr, monitor and switches to + * capability mode. + */ + +struct ssh_sandbox { + struct monitor *monitor; + pid_t child_pid; +}; + +struct ssh_sandbox * +ssh_sandbox_init(struct monitor *monitor) +{ + struct ssh_sandbox *box; + + /* + * Strictly, we don't need to maintain any state here but we need + * to return non-NULL to satisfy the API. + */ + debug3("%s: preparing capsicum sandbox", __func__); + box = xcalloc(1, sizeof(*box)); + box->monitor = monitor; + box->child_pid = 0; + + return box; +} + +void +ssh_sandbox_child(struct ssh_sandbox *box) +{ + struct rlimit rl_zero; + cap_rights_t rights; + + rl_zero.rlim_cur = rl_zero.rlim_max = 0; + + if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1) + fatal("%s: setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s", + __func__, strerror(errno)); + if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1) + fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s", + __func__, strerror(errno)); + if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1) + fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s", + __func__, strerror(errno)); + + cap_rights_init(&rights); + + if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) + fatal("can't limit stdin: %m"); + if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) + fatal("can't limit stdin: %m"); + if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) + fatal("can't limit stdin: %m"); + + cap_rights_init(&rights, CAP_READ, CAP_WRITE); + if (cap_rights_limit(box->monitor->m_recvfd, &rights) == -1) + fatal("%s: failed to limit the network socket", __func__); + cap_rights_init(&rights, CAP_WRITE); + if (cap_rights_limit(box->monitor->m_log_sendfd, &rights) == -1) + fatal("%s: failed to limit the logging socket", __func__); + if (cap_enter() != 0 && errno != ENOSYS) + fatal("%s: failed to enter capability mode", __func__); + +} + +void +ssh_sandbox_parent_finish(struct ssh_sandbox *box) +{ + free(box); + debug3("%s: finished", __func__); +} + +void +ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) +{ + box->child_pid = child_pid; +} + +#endif /* SANDBOX_CAPSICUM */ diff --git a/sandbox-darwin.c b/sandbox-darwin.c index 69901ef14..35f0c4d1a 100644 --- a/sandbox-darwin.c +++ b/sandbox-darwin.c @@ -40,7 +40,7 @@ struct ssh_sandbox { }; struct ssh_sandbox * -ssh_sandbox_init(void) +ssh_sandbox_init(struct monitor *monitor) { struct ssh_sandbox *box; diff --git a/sandbox-null.c b/sandbox-null.c index 29fa9669f..d4cb9188b 100644 --- a/sandbox-null.c +++ b/sandbox-null.c @@ -39,7 +39,7 @@ struct ssh_sandbox { }; struct ssh_sandbox * -ssh_sandbox_init(void) +ssh_sandbox_init(struct monitor *monitor) { struct ssh_sandbox *box; diff --git a/sandbox-rlimit.c b/sandbox-rlimit.c index a00386337..da91eb1b9 100644 --- a/sandbox-rlimit.c +++ b/sandbox-rlimit.c @@ -42,7 +42,7 @@ struct ssh_sandbox { }; struct ssh_sandbox * -ssh_sandbox_init(void) +ssh_sandbox_init(struct monitor *monitor) { struct ssh_sandbox *box; diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c index cc1465305..2f73067e1 100644 --- a/sandbox-seccomp-filter.c +++ b/sandbox-seccomp-filter.c @@ -132,7 +132,7 @@ struct ssh_sandbox { }; struct ssh_sandbox * -ssh_sandbox_init(void) +ssh_sandbox_init(struct monitor *monitor) { struct ssh_sandbox *box; diff --git a/sandbox-systrace.c b/sandbox-systrace.c index cc0db46c4..53fbd47cb 100644 --- a/sandbox-systrace.c +++ b/sandbox-systrace.c @@ -78,7 +78,7 @@ struct ssh_sandbox { }; struct ssh_sandbox * -ssh_sandbox_init(void) +ssh_sandbox_init(struct monitor *monitor) { struct ssh_sandbox *box; diff --git a/ssh-sandbox.h b/ssh-sandbox.h index dfecd5aa0..bd5fd8372 100644 --- a/ssh-sandbox.h +++ b/ssh-sandbox.h @@ -15,9 +15,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +struct monitor; struct ssh_sandbox; -struct ssh_sandbox *ssh_sandbox_init(void); +struct ssh_sandbox *ssh_sandbox_init(struct monitor *); 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); diff --git a/sshd.c b/sshd.c index 60b416e30..a5d4218b3 100644 --- a/sshd.c +++ b/sshd.c @@ -660,7 +660,7 @@ privsep_preauth(Authctxt *authctxt) pmonitor->m_pkex = &xxx_kex; if (use_privsep == PRIVSEP_ON) - box = ssh_sandbox_init(); + box = ssh_sandbox_init(pmonitor); pid = fork(); if (pid == -1) { fatal("fork of unprivileged child failed");