summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2011-06-23 08:30:03 +1000
committerDamien Miller <djm@mindrot.org>2011-06-23 08:30:03 +1000
commit69ff1df952eebf0489b775a60ede094eaf596a05 (patch)
tree6eb76b4632b7c131e0fbb52d8ce7cccf658b6bfa
parent82c558761d0fa42dc954d62812b9e4b4a94f64bd (diff)
- djm@cvs.openbsd.org 2011/06/22 21:57:01
[servconf.c servconf.h sshd.c sshd_config.5 sandbox-rlimit.c] [sandbox-systrace.c sandbox.h configure.ac Makefile.in] introduce sandboxing of the pre-auth privsep child using systrace(4). This introduces a new "UsePrivilegeSeparation=sandbox" option for sshd_config that applies mandatory restrictions on the syscalls the privsep child can perform. This prevents a compromised privsep child from being used to attack other hosts (by opening sockets and proxying) or probing local kernel attack surface. The sandbox is implemented using systrace(4) in unsupervised "fast-path" mode, where a list of permitted syscalls is supplied. Any syscall not on the list results in SIGKILL being sent to the privsep child. Note that this requires a kernel with the new SYSTR_POLICY_KILL option. UsePrivilegeSeparation=sandbox will become the default in the future so please start testing it now. feedback dtucker@; ok markus@
-rw-r--r--ChangeLog20
-rw-r--r--Makefile.in5
-rw-r--r--configure.ac43
-rw-r--r--sandbox-rlimit.c92
-rw-r--r--sandbox-systrace.c187
-rwxr-xr-xsandbox.h23
-rw-r--r--servconf.c15
-rw-r--r--servconf.h7
-rw-r--r--sshd.c30
-rw-r--r--sshd_config.510
10 files changed, 417 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index b8adb8a87..6a18e7193 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,26 @@
3 - djm@cvs.openbsd.org 2011/06/22 21:47:28 3 - djm@cvs.openbsd.org 2011/06/22 21:47:28
4 [servconf.c] 4 [servconf.c]
5 reuse the multistate option arrays to pretty-print options for "sshd -T" 5 reuse the multistate option arrays to pretty-print options for "sshd -T"
6 - djm@cvs.openbsd.org 2011/06/22 21:57:01
7 [servconf.c servconf.h sshd.c sshd_config.5]
8 [configure.ac Makefile.in]
9 introduce sandboxing of the pre-auth privsep child using systrace(4).
10
11 This introduces a new "UsePrivilegeSeparation=sandbox" option for
12 sshd_config that applies mandatory restrictions on the syscalls the
13 privsep child can perform. This prevents a compromised privsep child
14 from being used to attack other hosts (by opening sockets and proxying)
15 or probing local kernel attack surface.
16
17 The sandbox is implemented using systrace(4) in unsupervised "fast-path"
18 mode, where a list of permitted syscalls is supplied. Any syscall not
19 on the list results in SIGKILL being sent to the privsep child. Note
20 that this requires a kernel with the new SYSTR_POLICY_KILL option.
21
22 UsePrivilegeSeparation=sandbox will become the default in the future
23 so please start testing it now.
24
25 feedback dtucker@; ok markus@
6 26
720110620 2720110620
8 - OpenBSD CVS Sync 28 - OpenBSD CVS Sync
diff --git a/Makefile.in b/Makefile.in
index f5b147619..f64aaac94 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.322 2011/05/05 03:48:37 djm Exp $ 1# $Id: Makefile.in,v 1.323 2011/06/22 22:30:03 djm Exp $
2 2
3# uncomment if you run a non bourne compatable shell. Ie. csh 3# uncomment if you run a non bourne compatable shell. Ie. csh
4#SHELL = @SH@ 4#SHELL = @SH@
@@ -89,7 +89,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
89 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 89 auth2-gss.o gss-serv.o gss-serv-krb5.o \
90 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 90 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
91 sftp-server.o sftp-common.o \ 91 sftp-server.o sftp-common.o \
92 roaming_common.o roaming_serv.o 92 roaming_common.o roaming_serv.o \
93 sandbox-null.o sandbox-rlimit.o sandbox-systrace.o
93 94
94MANPAGES = 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 95MANPAGES = 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
95MANPAGES_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 96MANPAGES_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
diff --git a/configure.ac b/configure.ac
index 8f36338ff..380a8b949 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
1# $Id: configure.ac,v 1.476 2011/06/03 02:11:38 djm Exp $ 1# $Id: configure.ac,v 1.477 2011/06/22 22:30:03 djm Exp $
2# 2#
3# Copyright (c) 1999-2004 Damien Miller 3# Copyright (c) 1999-2004 Damien Miller
4# 4#
@@ -15,7 +15,7 @@
15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 16
17AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org]) 17AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
18AC_REVISION($Revision: 1.476 $) 18AC_REVISION($Revision: 1.477 $)
19AC_CONFIG_SRCDIR([ssh.c]) 19AC_CONFIG_SRCDIR([ssh.c])
20AC_LANG([C]) 20AC_LANG([C])
21 21
@@ -106,6 +106,16 @@ AC_SUBST([LD])
106AC_C_INLINE 106AC_C_INLINE
107 107
108AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include <limits.h>]) 108AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include <limits.h>])
109AC_CHECK_DECL([SYSTR_POLICY_KILL], [have_systr_policy_kill=1], , [
110 #include <sys/types.h>
111 #include <sys/param.h>
112 #include <dev/systrace.h>
113])
114AC_CHECK_DECL([RLIMIT_NPROC],
115 [AC_DEFINE([HAVE_RLIMIT_NPROC], [], [sys/resource.h has RLIMIT_NPROC])], , [
116 #include <sys/types.h>
117 #include <sys/resource.h>
118])
109 119
110use_stack_protector=1 120use_stack_protector=1
111AC_ARG_WITH([stackprotect], 121AC_ARG_WITH([stackprotect],
@@ -2461,6 +2471,34 @@ AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], ["$SSH_PRIVSEP_USER"],
2461 [non-privileged user for privilege separation]) 2471 [non-privileged user for privilege separation])
2462AC_SUBST([SSH_PRIVSEP_USER]) 2472AC_SUBST([SSH_PRIVSEP_USER])
2463 2473
2474# Decide which sandbox style to use
2475sandbox_arg=""
2476AC_ARG_WITH([sandbox],
2477 [ --with-sandbox=style Specify privilege separation sandbox (no, rlimit, systrace)],
2478 [
2479 if test "x$withval" = "xyes" ; then
2480 sandbox_arg=""
2481 else
2482 sandbox_arg="$withval"
2483 fi
2484 ]
2485)
2486if test "x$sandbox_arg" = "xsystrace" || \
2487 ( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then
2488 SANDBOX_STYLE="systrace"
2489 AC_DEFINE([SANDBOX_SYSTRACE], [1], [Sandbox using systrace(4)])
2490elif test "x$sandbox_arg" = "xrlimit" || \
2491 ( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" ) ; then
2492 SANDBOX_STYLE="rlimit"
2493 AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)])
2494elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
2495 test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
2496 SANDBOX_STYLE="none"
2497 AC_DEFINE([SANDBOX_NULL], [1], [no privsep sandboxing])
2498else
2499 AC_MSG_ERROR([unsupported -with-sandbox])
2500fi
2501
2464# Cheap hack to ensure NEWS-OS libraries are arranged right. 2502# Cheap hack to ensure NEWS-OS libraries are arranged right.
2465if test ! -z "$SONY" ; then 2503if test ! -z "$SONY" ; then
2466 LIBS="$LIBS -liberty"; 2504 LIBS="$LIBS -liberty";
@@ -4191,6 +4229,7 @@ echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
4191echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" 4229echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
4192echo " BSD Auth support: $BSD_AUTH_MSG" 4230echo " BSD Auth support: $BSD_AUTH_MSG"
4193echo " Random number source: $RAND_MSG" 4231echo " Random number source: $RAND_MSG"
4232echo " Privsep sandbox style: $SANDBOX_STYLE"
4194 4233
4195echo "" 4234echo ""
4196 4235
diff --git a/sandbox-rlimit.c b/sandbox-rlimit.c
new file mode 100644
index 000000000..4d832fc3d
--- /dev/null
+++ b/sandbox-rlimit.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "includes.h"
18
19#ifdef SANDBOX_RLIMIT
20
21#include <sys/types.h>
22#include <sys/param.h>
23#include <sys/time.h>
24#include <sys/resource.h>
25
26#include <errno.h>
27#include <stdarg.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "log.h"
34#include "sandbox.h"
35#include "xmalloc.h"
36
37/* Minimal sandbox that sets zero nfiles, nprocs and filesize rlimits */
38
39struct ssh_sandbox {
40 pid_t child_pid;
41};
42
43struct ssh_sandbox *
44ssh_sandbox_init(void)
45{
46 struct ssh_sandbox *box;
47
48 /*
49 * Strictly, we don't need to maintain any state here but we need
50 * to return non-NULL to satisfy the API.
51 */
52 debug3("%s: preparing rlimit sandbox", __func__);
53 box = xcalloc(1, sizeof(*box));
54 box->child_pid = 0;
55
56 return box;
57}
58
59void
60ssh_sandbox_child(struct ssh_sandbox *box)
61{
62 struct rlimit rl_zero;
63
64 rl_zero.rlim_cur = rl_zero.rlim_max = 0;
65
66 if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
67 fatal("%s: setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s",
68 __func__, strerror(errno));
69 if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
70 fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s",
71 __func__, strerror(errno));
72#ifdef HAVE_RLIMIT_NPROC
73 if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
74 fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s",
75 __func__, strerror(errno));
76#endif
77}
78
79void
80ssh_sandbox_parent_finish(struct ssh_sandbox *box)
81{
82 free(box);
83 debug3("%s: finished", __func__);
84}
85
86void
87ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
88{
89 box->child_pid = child_pid;
90}
91
92#endif /* SANDBOX_RLIMIT */
diff --git a/sandbox-systrace.c b/sandbox-systrace.c
new file mode 100644
index 000000000..5d0b7fb86
--- /dev/null
+++ b/sandbox-systrace.c
@@ -0,0 +1,187 @@
1/*
2 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "includes.h"
18
19#ifdef SANDBOX_SYSTRACE
20
21#include <sys/types.h>
22#include <sys/param.h>
23#include <sys/ioctl.h>
24#include <sys/syscall.h>
25#include <sys/socket.h>
26
27#include <dev/systrace.h>
28
29#include <errno.h>
30#include <fcntl.h>
31#include <limits.h>
32#include <stdarg.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37
38#include "atomicio.h"
39#include "log.h"
40#include "sandbox.h"
41#include "xmalloc.h"
42
43static const int preauth_policy[] = {
44 SYS___sysctl,
45 SYS_close,
46 SYS_exit,
47 SYS_getpid,
48 SYS_gettimeofday,
49 SYS_madvise,
50 SYS_mmap,
51 SYS_mprotect,
52 SYS_poll,
53 SYS_munmap,
54 SYS_read,
55 SYS_select,
56 SYS_sigprocmask,
57 SYS_write,
58 -1
59};
60
61struct ssh_sandbox {
62 int child_sock;
63 int parent_sock;
64 int systrace_fd;
65 pid_t child_pid;
66 struct systrace_policy policy;
67};
68
69struct ssh_sandbox *
70ssh_sandbox_init(void)
71{
72 struct ssh_sandbox *box;
73 int s[2];
74
75 debug3("%s: preparing systrace sandbox", __func__);
76 box = xcalloc(1, sizeof(*box));
77 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1)
78 fatal("%s: socketpair: %s", __func__, strerror(errno));
79 box->child_sock = s[0];
80 box->parent_sock = s[1];
81 box->systrace_fd = -1;
82 box->child_pid = 0;
83
84 return box;
85}
86
87void
88ssh_sandbox_child(struct ssh_sandbox *box)
89{
90 char whatever = 0;
91
92 close(box->parent_sock);
93 /* Signal parent that we are ready */
94 debug3("%s: ready", __func__);
95 if (atomicio(vwrite, box->child_sock, &whatever, 1) != 1)
96 fatal("%s: write: %s", __func__, strerror(errno));
97 /* Wait for parent to signal for us to go */
98 if (atomicio(read, box->child_sock, &whatever, 1) != 1)
99 fatal("%s: read: %s", __func__, strerror(errno));
100 debug3("%s: started", __func__);
101 close(box->child_sock);
102}
103
104static void
105ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid,
106 const int *allowed_syscalls)
107{
108 int dev_systrace, i, j, found;
109 char whatever = 0;
110
111 debug3("%s: wait for child %ld", __func__, (long)child_pid);
112 box->child_pid = child_pid;
113 close(box->child_sock);
114 /* Wait for child to signal that it is ready */
115 if (atomicio(read, box->parent_sock, &whatever, 1) != 1)
116 fatal("%s: read: %s", __func__, strerror(errno));
117 debug3("%s: child %ld ready", __func__, (long)child_pid);
118
119 /* Set up systracing of child */
120 if ((dev_systrace = open("/dev/systrace", O_RDONLY)) == -1)
121 fatal("%s: open(\"/dev/systrace\"): %s", __func__,
122 strerror(errno));
123 if (ioctl(dev_systrace, STRIOCCLONE, &box->systrace_fd) == -1)
124 fatal("%s: ioctl(STRIOCCLONE, %d): %s", __func__,
125 dev_systrace, strerror(errno));
126 close(dev_systrace);
127 debug3("%s: systrace attach, fd=%d", __func__, box->systrace_fd);
128 if (ioctl(box->systrace_fd, STRIOCATTACH, &child_pid) == -1)
129 fatal("%s: ioctl(%d, STRIOCATTACH, %d): %s", __func__,
130 box->systrace_fd, child_pid, strerror(errno));
131
132 /* Allocate and assign policy */
133 bzero(&box->policy, sizeof(box->policy));
134 box->policy.strp_op = SYSTR_POLICY_NEW;
135 box->policy.strp_maxents = SYS_MAXSYSCALL;
136 if (ioctl(box->systrace_fd, STRIOCPOLICY, &box->policy) == -1)
137 fatal("%s: ioctl(%d, STRIOCPOLICY (new)): %s", __func__,
138 box->systrace_fd, strerror(errno));
139
140 box->policy.strp_op = SYSTR_POLICY_ASSIGN;
141 box->policy.strp_pid = box->child_pid;
142 if (ioctl(box->systrace_fd, STRIOCPOLICY, &box->policy) == -1)
143 fatal("%s: ioctl(%d, STRIOCPOLICY (assign)): %s",
144 __func__, box->systrace_fd, strerror(errno));
145
146 /* Set per-syscall policy */
147 for (i = 0; i < SYS_MAXSYSCALL; i++) {
148 for (j = found = 0; allowed_syscalls[j] != -1 && !found; j++) {
149 if (allowed_syscalls[j] == i)
150 found = 1;
151 }
152 box->policy.strp_op = SYSTR_POLICY_MODIFY;
153 box->policy.strp_code = i;
154 box->policy.strp_policy = found ?
155 SYSTR_POLICY_PERMIT : SYSTR_POLICY_KILL;
156 if (found)
157 debug3("%s: policy: enable syscall %d", __func__, i);
158 if (ioctl(box->systrace_fd, STRIOCPOLICY,
159 &box->policy) == -1)
160 fatal("%s: ioctl(%d, STRIOCPOLICY (modify)): %s",
161 __func__, box->systrace_fd, strerror(errno));
162 }
163
164 /* Signal the child to start running */
165 debug3("%s: start child %ld", __func__, (long)child_pid);
166 if (atomicio(vwrite, box->parent_sock, &whatever, 1) != 1)
167 fatal("%s: write: %s", __func__, strerror(errno));
168 close(box->parent_sock);
169}
170
171void
172ssh_sandbox_parent_finish(struct ssh_sandbox *box)
173{
174 /* Closing this before the child exits will terminate it */
175 close(box->systrace_fd);
176
177 free(box);
178 debug3("%s: finished", __func__);
179}
180
181void
182ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
183{
184 ssh_sandbox_parent(box, child_pid, preauth_policy);
185}
186
187#endif /* SANDBOX_SYSTRACE */
diff --git a/sandbox.h b/sandbox.h
new file mode 100755
index 000000000..5fe30644d
--- /dev/null
+++ b/sandbox.h
@@ -0,0 +1,23 @@
1/* $OpenBSD: sandbox.h,v 1.2 2011/06/22 22:14:05 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18struct ssh_sandbox;
19
20struct ssh_sandbox *ssh_sandbox_init(void);
21void ssh_sandbox_child(struct ssh_sandbox *);
22void ssh_sandbox_parent_finish(struct ssh_sandbox *);
23void ssh_sandbox_parent_preauth(struct ssh_sandbox *, pid_t);
diff --git a/servconf.c b/servconf.c
index 03b974617..91986e55d 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.c,v 1.221 2011/06/22 21:47:28 djm Exp $ */ 1/* $OpenBSD: servconf.c,v 1.222 2011/06/22 21:57:01 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -280,7 +280,7 @@ fill_default_server_options(ServerOptions *options)
280 280
281 /* Turn privilege separation on by default */ 281 /* Turn privilege separation on by default */
282 if (use_privsep == -1) 282 if (use_privsep == -1)
283 use_privsep = 1; 283 use_privsep = PRIVSEP_ON;
284 284
285#ifndef HAVE_MMAP 285#ifndef HAVE_MMAP
286 if (use_privsep && options->compression == 1) { 286 if (use_privsep && options->compression == 1) {
@@ -701,6 +701,12 @@ static const struct multistate multistate_gatewayports[] = {
701 { "no", 0 }, 701 { "no", 0 },
702 { NULL, -1 } 702 { NULL, -1 }
703}; 703};
704static const struct multistate multistate_privsep[] = {
705 { "sandbox", PRIVSEP_SANDBOX },
706 { "yes", PRIVSEP_ON },
707 { "no", PRIVSEP_OFF },
708 { NULL, -1 }
709};
704 710
705int 711int
706process_server_config_line(ServerOptions *options, char *line, 712process_server_config_line(ServerOptions *options, char *line,
@@ -1066,7 +1072,8 @@ process_server_config_line(ServerOptions *options, char *line,
1066 1072
1067 case sUsePrivilegeSeparation: 1073 case sUsePrivilegeSeparation:
1068 intptr = &use_privsep; 1074 intptr = &use_privsep;
1069 goto parse_flag; 1075 multistate_ptr = multistate_privsep;
1076 goto parse_multistate;
1070 1077
1071 case sAllowUsers: 1078 case sAllowUsers:
1072 while ((arg = strdelim(&cp)) && *arg != '\0') { 1079 while ((arg = strdelim(&cp)) && *arg != '\0') {
@@ -1574,6 +1581,8 @@ fmt_intarg(ServerOpCodes code, int val)
1574 return fmt_multistate_int(val, multistate_gatewayports); 1581 return fmt_multistate_int(val, multistate_gatewayports);
1575 case sCompression: 1582 case sCompression:
1576 return fmt_multistate_int(val, multistate_compression); 1583 return fmt_multistate_int(val, multistate_compression);
1584 case sUsePrivilegeSeparation:
1585 return fmt_multistate_int(val, multistate_privsep);
1577 case sProtocol: 1586 case sProtocol:
1578 switch (val) { 1587 switch (val) {
1579 case SSH_PROTO_1: 1588 case SSH_PROTO_1:
diff --git a/servconf.h b/servconf.h
index 31e621bde..89f38e20f 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.98 2011/05/23 03:30:07 djm Exp $ */ 1/* $OpenBSD: servconf.h,v 1.99 2011/06/22 21:57:01 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -36,6 +36,11 @@
36#define PERMIT_NO_PASSWD 2 36#define PERMIT_NO_PASSWD 2
37#define PERMIT_YES 3 37#define PERMIT_YES 3
38 38
39/* use_privsep */
40#define PRIVSEP_OFF 0
41#define PRIVSEP_ON 1
42#define PRIVSEP_SANDBOX 2
43
39#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ 44#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */
40#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ 45#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */
41 46
diff --git a/sshd.c b/sshd.c
index 6e15522b3..bebcb9bf5 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.383 2011/06/17 21:44:31 djm Exp $ */ 1/* $OpenBSD: sshd.c,v 1.384 2011/06/22 21:57:01 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -118,6 +118,7 @@
118#endif 118#endif
119#include "monitor_wrap.h" 119#include "monitor_wrap.h"
120#include "roaming.h" 120#include "roaming.h"
121#include "sandbox.h"
121#include "version.h" 122#include "version.h"
122 123
123#ifdef LIBWRAP 124#ifdef LIBWRAP
@@ -624,18 +625,23 @@ privsep_preauth(Authctxt *authctxt)
624{ 625{
625 int status; 626 int status;
626 pid_t pid; 627 pid_t pid;
628 struct ssh_sandbox *box = NULL;
627 629
628 /* Set up unprivileged child process to deal with network data */ 630 /* Set up unprivileged child process to deal with network data */
629 pmonitor = monitor_init(); 631 pmonitor = monitor_init();
630 /* Store a pointer to the kex for later rekeying */ 632 /* Store a pointer to the kex for later rekeying */
631 pmonitor->m_pkex = &xxx_kex; 633 pmonitor->m_pkex = &xxx_kex;
632 634
635 if (use_privsep == PRIVSEP_SANDBOX)
636 box = ssh_sandbox_init();
633 pid = fork(); 637 pid = fork();
634 if (pid == -1) { 638 if (pid == -1) {
635 fatal("fork of unprivileged child failed"); 639 fatal("fork of unprivileged child failed");
636 } else if (pid != 0) { 640 } else if (pid != 0) {
637 debug2("Network child is on pid %ld", (long)pid); 641 debug2("Network child is on pid %ld", (long)pid);
638 642
643 if (box != NULL)
644 ssh_sandbox_parent_preauth(box, pid);
639 pmonitor->m_pid = pid; 645 pmonitor->m_pid = pid;
640 monitor_child_preauth(authctxt, pmonitor); 646 monitor_child_preauth(authctxt, pmonitor);
641 647
@@ -643,10 +649,21 @@ privsep_preauth(Authctxt *authctxt)
643 monitor_sync(pmonitor); 649 monitor_sync(pmonitor);
644 650
645 /* Wait for the child's exit status */ 651 /* Wait for the child's exit status */
646 while (waitpid(pid, &status, 0) < 0) 652 while (waitpid(pid, &status, 0) < 0) {
647 if (errno != EINTR) 653 if (errno != EINTR)
648 break; 654 fatal("%s: waitpid: %s", __func__,
649 return (1); 655 strerror(errno));
656 }
657 if (WIFEXITED(status)) {
658 if (WEXITSTATUS(status) != 0)
659 fatal("%s: preauth child exited with status %d",
660 __func__, WEXITSTATUS(status));
661 } else if (WIFSIGNALED(status))
662 fatal("%s: preauth child terminated by signal %d",
663 __func__, WTERMSIG(status));
664 if (box != NULL)
665 ssh_sandbox_parent_finish(box);
666 return 1;
650 } else { 667 } else {
651 /* child */ 668 /* child */
652 close(pmonitor->m_sendfd); 669 close(pmonitor->m_sendfd);
@@ -659,8 +676,11 @@ privsep_preauth(Authctxt *authctxt)
659 if (getuid() == 0 || geteuid() == 0) 676 if (getuid() == 0 || geteuid() == 0)
660 privsep_preauth_child(); 677 privsep_preauth_child();
661 setproctitle("%s", "[net]"); 678 setproctitle("%s", "[net]");
679 if (box != NULL)
680 ssh_sandbox_child(box);
681
682 return 0;
662 } 683 }
663 return (0);
664} 684}
665 685
666static void 686static void
diff --git a/sshd_config.5 b/sshd_config.5
index 70a53b3a9..f78452c85 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: sshd_config.5,v 1.133 2011/05/23 07:10:21 jmc Exp $ 36.\" $OpenBSD: sshd_config.5,v 1.134 2011/06/22 21:57:01 djm Exp $
37.Dd $Mdocdate: May 23 2011 $ 37.Dd $Mdocdate: June 22 2011 $
38.Dt SSHD_CONFIG 5 38.Dt SSHD_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -1071,6 +1071,12 @@ The goal of privilege separation is to prevent privilege
1071escalation by containing any corruption within the unprivileged processes. 1071escalation by containing any corruption within the unprivileged processes.
1072The default is 1072The default is
1073.Dq yes . 1073.Dq yes .
1074If
1075.Cm UsePrivilegeSeparation
1076is set to
1077.Dq sandbox
1078then the pre-authentication unprivileged process is subject to additional
1079restrictions.
1074.It Cm X11DisplayOffset 1080.It Cm X11DisplayOffset
1075Specifies the first display number available for 1081Specifies the first display number available for
1076.Xr sshd 8 Ns 's 1082.Xr sshd 8 Ns 's