xref: /dflybsd-src/crypto/openssh/sandbox-systrace.c (revision ba1276acd1c8c22d225b1bcf370a14c878644f44)
1*ba1276acSMatthew Dillon /* $OpenBSD: sandbox-systrace.c,v 1.18 2015/10/02 01:39:26 deraadt Exp $ */
2*ba1276acSMatthew Dillon /*
3*ba1276acSMatthew Dillon  * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4*ba1276acSMatthew Dillon  *
5*ba1276acSMatthew Dillon  * Permission to use, copy, modify, and distribute this software for any
6*ba1276acSMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
7*ba1276acSMatthew Dillon  * copyright notice and this permission notice appear in all copies.
8*ba1276acSMatthew Dillon  *
9*ba1276acSMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*ba1276acSMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*ba1276acSMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*ba1276acSMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*ba1276acSMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*ba1276acSMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*ba1276acSMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*ba1276acSMatthew Dillon  */
17*ba1276acSMatthew Dillon 
18*ba1276acSMatthew Dillon #include "includes.h"
19*ba1276acSMatthew Dillon 
20*ba1276acSMatthew Dillon #ifdef SANDBOX_SYSTRACE
21*ba1276acSMatthew Dillon 
22*ba1276acSMatthew Dillon #include <sys/types.h>
23*ba1276acSMatthew Dillon #include <sys/ioctl.h>
24*ba1276acSMatthew Dillon #include <sys/syscall.h>
25*ba1276acSMatthew Dillon #include <sys/socket.h>
26*ba1276acSMatthew Dillon #include <sys/wait.h>
27*ba1276acSMatthew Dillon 
28*ba1276acSMatthew Dillon #include <dev/systrace.h>
29*ba1276acSMatthew Dillon 
30*ba1276acSMatthew Dillon #include <errno.h>
31*ba1276acSMatthew Dillon #include <fcntl.h>
32*ba1276acSMatthew Dillon #include <limits.h>
33*ba1276acSMatthew Dillon #include <signal.h>
34*ba1276acSMatthew Dillon #include <stdarg.h>
35*ba1276acSMatthew Dillon #include <stdio.h>
36*ba1276acSMatthew Dillon #include <stdlib.h>
37*ba1276acSMatthew Dillon #include <string.h>
38*ba1276acSMatthew Dillon #include <unistd.h>
39*ba1276acSMatthew Dillon 
40*ba1276acSMatthew Dillon #include "atomicio.h"
41*ba1276acSMatthew Dillon #include "log.h"
42*ba1276acSMatthew Dillon #include "ssh-sandbox.h"
43*ba1276acSMatthew Dillon #include "xmalloc.h"
44*ba1276acSMatthew Dillon 
45*ba1276acSMatthew Dillon struct sandbox_policy {
46*ba1276acSMatthew Dillon 	int syscall;
47*ba1276acSMatthew Dillon 	int action;
48*ba1276acSMatthew Dillon };
49*ba1276acSMatthew Dillon 
50*ba1276acSMatthew Dillon /* Permitted syscalls in preauth. Unlisted syscalls get SYSTR_POLICY_KILL */
51*ba1276acSMatthew Dillon static const struct sandbox_policy preauth_policy[] = {
52*ba1276acSMatthew Dillon 	{ SYS_exit, SYSTR_POLICY_PERMIT },
53*ba1276acSMatthew Dillon #ifdef SYS_kbind
54*ba1276acSMatthew Dillon 	{ SYS_kbind, SYSTR_POLICY_PERMIT },
55*ba1276acSMatthew Dillon #endif
56*ba1276acSMatthew Dillon 
57*ba1276acSMatthew Dillon 	{ SYS_getpid, SYSTR_POLICY_PERMIT },
58*ba1276acSMatthew Dillon 	{ SYS_getpgid, SYSTR_POLICY_PERMIT },
59*ba1276acSMatthew Dillon 	{ SYS_clock_gettime, SYSTR_POLICY_PERMIT },
60*ba1276acSMatthew Dillon 	{ SYS_gettimeofday, SYSTR_POLICY_PERMIT },
61*ba1276acSMatthew Dillon 	{ SYS_nanosleep, SYSTR_POLICY_PERMIT },
62*ba1276acSMatthew Dillon 	{ SYS_sigprocmask, SYSTR_POLICY_PERMIT },
63*ba1276acSMatthew Dillon 
64*ba1276acSMatthew Dillon #ifdef SYS_getentropy
65*ba1276acSMatthew Dillon 	/* OpenBSD 5.6 and newer use getentropy(2) to seed arc4random(3). */
66*ba1276acSMatthew Dillon 	{ SYS_getentropy, SYSTR_POLICY_PERMIT },
67*ba1276acSMatthew Dillon #else
68*ba1276acSMatthew Dillon 	/* Previous releases used sysctl(3)'s kern.arnd variable. */
69*ba1276acSMatthew Dillon 	{ SYS___sysctl, SYSTR_POLICY_PERMIT },
70*ba1276acSMatthew Dillon #endif
71*ba1276acSMatthew Dillon #ifdef SYS_sendsyslog
72*ba1276acSMatthew Dillon 	{ SYS_sendsyslog, SYSTR_POLICY_PERMIT },
73*ba1276acSMatthew Dillon #endif
74*ba1276acSMatthew Dillon 
75*ba1276acSMatthew Dillon 	{ SYS_madvise, SYSTR_POLICY_PERMIT },
76*ba1276acSMatthew Dillon 	{ SYS_mmap, SYSTR_POLICY_PERMIT },
77*ba1276acSMatthew Dillon 	{ SYS_mprotect, SYSTR_POLICY_PERMIT },
78*ba1276acSMatthew Dillon 	{ SYS_mquery, SYSTR_POLICY_PERMIT },
79*ba1276acSMatthew Dillon 	{ SYS_munmap, SYSTR_POLICY_PERMIT },
80*ba1276acSMatthew Dillon 
81*ba1276acSMatthew Dillon 	{ SYS_poll, SYSTR_POLICY_PERMIT },
82*ba1276acSMatthew Dillon 	{ SYS_select, SYSTR_POLICY_PERMIT },
83*ba1276acSMatthew Dillon 	{ SYS_read, SYSTR_POLICY_PERMIT },
84*ba1276acSMatthew Dillon 	{ SYS_write, SYSTR_POLICY_PERMIT },
85*ba1276acSMatthew Dillon 	{ SYS_shutdown, SYSTR_POLICY_PERMIT },
86*ba1276acSMatthew Dillon 	{ SYS_close, SYSTR_POLICY_PERMIT },
87*ba1276acSMatthew Dillon 
88*ba1276acSMatthew Dillon 	{ SYS_open, SYSTR_POLICY_NEVER },
89*ba1276acSMatthew Dillon 
90*ba1276acSMatthew Dillon 	{ -1, -1 }
91*ba1276acSMatthew Dillon };
92*ba1276acSMatthew Dillon 
93*ba1276acSMatthew Dillon struct ssh_sandbox {
94*ba1276acSMatthew Dillon 	int systrace_fd;
95*ba1276acSMatthew Dillon 	pid_t child_pid;
96*ba1276acSMatthew Dillon 	void (*osigchld)(int);
97*ba1276acSMatthew Dillon };
98*ba1276acSMatthew Dillon 
99*ba1276acSMatthew Dillon struct ssh_sandbox *
ssh_sandbox_init(struct monitor * monitor)100*ba1276acSMatthew Dillon ssh_sandbox_init(struct monitor *monitor)
101*ba1276acSMatthew Dillon {
102*ba1276acSMatthew Dillon 	struct ssh_sandbox *box;
103*ba1276acSMatthew Dillon 
104*ba1276acSMatthew Dillon 	debug3("%s: preparing systrace sandbox", __func__);
105*ba1276acSMatthew Dillon 	box = xcalloc(1, sizeof(*box));
106*ba1276acSMatthew Dillon 	box->systrace_fd = -1;
107*ba1276acSMatthew Dillon 	box->child_pid = 0;
108*ba1276acSMatthew Dillon 	box->osigchld = ssh_signal(SIGCHLD, SIG_IGN);
109*ba1276acSMatthew Dillon 
110*ba1276acSMatthew Dillon 	return box;
111*ba1276acSMatthew Dillon }
112*ba1276acSMatthew Dillon 
113*ba1276acSMatthew Dillon void
ssh_sandbox_child(struct ssh_sandbox * box)114*ba1276acSMatthew Dillon ssh_sandbox_child(struct ssh_sandbox *box)
115*ba1276acSMatthew Dillon {
116*ba1276acSMatthew Dillon 	debug3("%s: ready", __func__);
117*ba1276acSMatthew Dillon 	ssh_signal(SIGCHLD, box->osigchld);
118*ba1276acSMatthew Dillon 	if (kill(getpid(), SIGSTOP) != 0)
119*ba1276acSMatthew Dillon 		fatal("%s: kill(%d, SIGSTOP)", __func__, getpid());
120*ba1276acSMatthew Dillon 	debug3("%s: started", __func__);
121*ba1276acSMatthew Dillon }
122*ba1276acSMatthew Dillon 
123*ba1276acSMatthew Dillon static void
ssh_sandbox_parent(struct ssh_sandbox * box,pid_t child_pid,const struct sandbox_policy * allowed_syscalls)124*ba1276acSMatthew Dillon ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid,
125*ba1276acSMatthew Dillon     const struct sandbox_policy *allowed_syscalls)
126*ba1276acSMatthew Dillon {
127*ba1276acSMatthew Dillon 	int dev_systrace, i, j, found, status;
128*ba1276acSMatthew Dillon 	pid_t pid;
129*ba1276acSMatthew Dillon 	struct systrace_policy policy;
130*ba1276acSMatthew Dillon 
131*ba1276acSMatthew Dillon 	/* Wait for the child to send itself a SIGSTOP */
132*ba1276acSMatthew Dillon 	debug3("%s: wait for child %ld", __func__, (long)child_pid);
133*ba1276acSMatthew Dillon 	do {
134*ba1276acSMatthew Dillon 		pid = waitpid(child_pid, &status, WUNTRACED);
135*ba1276acSMatthew Dillon 	} while (pid == -1 && errno == EINTR);
136*ba1276acSMatthew Dillon 	ssh_signal(SIGCHLD, box->osigchld);
137*ba1276acSMatthew Dillon 	if (!WIFSTOPPED(status)) {
138*ba1276acSMatthew Dillon 		if (WIFSIGNALED(status))
139*ba1276acSMatthew Dillon 			fatal("%s: child terminated with signal %d",
140*ba1276acSMatthew Dillon 			    __func__, WTERMSIG(status));
141*ba1276acSMatthew Dillon 		if (WIFEXITED(status))
142*ba1276acSMatthew Dillon 			fatal("%s: child exited with status %d",
143*ba1276acSMatthew Dillon 			    __func__, WEXITSTATUS(status));
144*ba1276acSMatthew Dillon 		fatal("%s: child not stopped", __func__);
145*ba1276acSMatthew Dillon 	}
146*ba1276acSMatthew Dillon 	debug3("%s: child %ld stopped", __func__, (long)child_pid);
147*ba1276acSMatthew Dillon 	box->child_pid = child_pid;
148*ba1276acSMatthew Dillon 
149*ba1276acSMatthew Dillon 	/* Set up systracing of child */
150*ba1276acSMatthew Dillon 	if ((dev_systrace = open("/dev/systrace", O_RDONLY)) == -1)
151*ba1276acSMatthew Dillon 		fatal("%s: open(\"/dev/systrace\"): %s", __func__,
152*ba1276acSMatthew Dillon 		    strerror(errno));
153*ba1276acSMatthew Dillon 	if (ioctl(dev_systrace, STRIOCCLONE, &box->systrace_fd) == -1)
154*ba1276acSMatthew Dillon 		fatal("%s: ioctl(STRIOCCLONE, %d): %s", __func__,
155*ba1276acSMatthew Dillon 		    dev_systrace, strerror(errno));
156*ba1276acSMatthew Dillon 	close(dev_systrace);
157*ba1276acSMatthew Dillon 	debug3("%s: systrace attach, fd=%d", __func__, box->systrace_fd);
158*ba1276acSMatthew Dillon 	if (ioctl(box->systrace_fd, STRIOCATTACH, &child_pid) == -1)
159*ba1276acSMatthew Dillon 		fatal("%s: ioctl(%d, STRIOCATTACH, %d): %s", __func__,
160*ba1276acSMatthew Dillon 		    box->systrace_fd, child_pid, strerror(errno));
161*ba1276acSMatthew Dillon 
162*ba1276acSMatthew Dillon 	/* Allocate and assign policy */
163*ba1276acSMatthew Dillon 	memset(&policy, 0, sizeof(policy));
164*ba1276acSMatthew Dillon 	policy.strp_op = SYSTR_POLICY_NEW;
165*ba1276acSMatthew Dillon 	policy.strp_maxents = SYS_MAXSYSCALL;
166*ba1276acSMatthew Dillon 	if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1)
167*ba1276acSMatthew Dillon 		fatal("%s: ioctl(%d, STRIOCPOLICY (new)): %s", __func__,
168*ba1276acSMatthew Dillon 		    box->systrace_fd, strerror(errno));
169*ba1276acSMatthew Dillon 
170*ba1276acSMatthew Dillon 	policy.strp_op = SYSTR_POLICY_ASSIGN;
171*ba1276acSMatthew Dillon 	policy.strp_pid = box->child_pid;
172*ba1276acSMatthew Dillon 	if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1)
173*ba1276acSMatthew Dillon 		fatal("%s: ioctl(%d, STRIOCPOLICY (assign)): %s",
174*ba1276acSMatthew Dillon 		    __func__, box->systrace_fd, strerror(errno));
175*ba1276acSMatthew Dillon 
176*ba1276acSMatthew Dillon 	/* Set per-syscall policy */
177*ba1276acSMatthew Dillon 	for (i = 0; i < SYS_MAXSYSCALL; i++) {
178*ba1276acSMatthew Dillon 		found = 0;
179*ba1276acSMatthew Dillon 		for (j = 0; allowed_syscalls[j].syscall != -1; j++) {
180*ba1276acSMatthew Dillon 			if (allowed_syscalls[j].syscall == i) {
181*ba1276acSMatthew Dillon 				found = 1;
182*ba1276acSMatthew Dillon 				break;
183*ba1276acSMatthew Dillon 			}
184*ba1276acSMatthew Dillon 		}
185*ba1276acSMatthew Dillon 		policy.strp_op = SYSTR_POLICY_MODIFY;
186*ba1276acSMatthew Dillon 		policy.strp_code = i;
187*ba1276acSMatthew Dillon 		policy.strp_policy = found ?
188*ba1276acSMatthew Dillon 		    allowed_syscalls[j].action : SYSTR_POLICY_KILL;
189*ba1276acSMatthew Dillon 		if (found)
190*ba1276acSMatthew Dillon 			debug3("%s: policy: enable syscall %d", __func__, i);
191*ba1276acSMatthew Dillon 		if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1)
192*ba1276acSMatthew Dillon 			fatal("%s: ioctl(%d, STRIOCPOLICY (modify)): %s",
193*ba1276acSMatthew Dillon 			    __func__, box->systrace_fd, strerror(errno));
194*ba1276acSMatthew Dillon 	}
195*ba1276acSMatthew Dillon 
196*ba1276acSMatthew Dillon 	/* Signal the child to start running */
197*ba1276acSMatthew Dillon 	debug3("%s: start child %ld", __func__, (long)child_pid);
198*ba1276acSMatthew Dillon 	if (kill(box->child_pid, SIGCONT) != 0)
199*ba1276acSMatthew Dillon 		fatal("%s: kill(%d, SIGCONT)", __func__, box->child_pid);
200*ba1276acSMatthew Dillon }
201*ba1276acSMatthew Dillon 
202*ba1276acSMatthew Dillon void
ssh_sandbox_parent_finish(struct ssh_sandbox * box)203*ba1276acSMatthew Dillon ssh_sandbox_parent_finish(struct ssh_sandbox *box)
204*ba1276acSMatthew Dillon {
205*ba1276acSMatthew Dillon 	/* Closing this before the child exits will terminate it */
206*ba1276acSMatthew Dillon 	close(box->systrace_fd);
207*ba1276acSMatthew Dillon 
208*ba1276acSMatthew Dillon 	free(box);
209*ba1276acSMatthew Dillon 	debug3("%s: finished", __func__);
210*ba1276acSMatthew Dillon }
211*ba1276acSMatthew Dillon 
212*ba1276acSMatthew Dillon void
ssh_sandbox_parent_preauth(struct ssh_sandbox * box,pid_t child_pid)213*ba1276acSMatthew Dillon ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
214*ba1276acSMatthew Dillon {
215*ba1276acSMatthew Dillon 	ssh_sandbox_parent(box, child_pid, preauth_policy);
216*ba1276acSMatthew Dillon }
217*ba1276acSMatthew Dillon 
218*ba1276acSMatthew Dillon #endif /* SANDBOX_SYSTRACE */
219