sandbox-systrace.c revision 255767
119370Spst/* $OpenBSD: sandbox-systrace.c,v 1.7 2013/06/01 13:15:52 dtucker Exp $ */
2130803Smarcel/*
398944Sobrien * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4130803Smarcel *
519370Spst * Permission to use, copy, modify, and distribute this software for any
698944Sobrien * purpose with or without fee is hereby granted, provided that the above
719370Spst * copyright notice and this permission notice appear in all copies.
898944Sobrien *
998944Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1098944Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1198944Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1219370Spst * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1398944Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1498944Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1598944Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1698944Sobrien */
1719370Spst
1898944Sobrien#include "includes.h"
1998944Sobrien
2098944Sobrien#ifdef SANDBOX_SYSTRACE
2198944Sobrien
2219370Spst#include <sys/types.h>
2319370Spst#include <sys/param.h>
2419370Spst#include <sys/ioctl.h>
2519370Spst#include <sys/syscall.h>
2619370Spst#include <sys/socket.h>
2719370Spst#include <sys/wait.h>
2819370Spst
2919370Spst#include <dev/systrace.h>
30130803Smarcel
31130803Smarcel#include <errno.h>
32130803Smarcel#include <fcntl.h>
33130803Smarcel#include <limits.h>
3419370Spst#include <signal.h>
3546283Sdfr#include <stdarg.h>
3646283Sdfr#include <stdio.h>
3746283Sdfr#include <stdlib.h>
3846283Sdfr#include <string.h>
3919370Spst#include <unistd.h>
4098944Sobrien
4119370Spst#include "atomicio.h"
4219370Spst#include "log.h"
4319370Spst#include "ssh-sandbox.h"
4419370Spst#include "xmalloc.h"
4519370Spst
4619370Spststruct sandbox_policy {
4719370Spst	int syscall;
4819370Spst	int action;
4919370Spst};
5019370Spst
51130803Smarcel/* Permitted syscalls in preauth. Unlisted syscalls get SYSTR_POLICY_KILL */
52130803Smarcelstatic const struct sandbox_policy preauth_policy[] = {
5398944Sobrien	{ SYS_open, SYSTR_POLICY_NEVER },
5419370Spst
55130803Smarcel	{ SYS___sysctl, SYSTR_POLICY_PERMIT },
56130803Smarcel	{ SYS_close, SYSTR_POLICY_PERMIT },
57130803Smarcel	{ SYS_exit, SYSTR_POLICY_PERMIT },
58130803Smarcel	{ SYS_getpid, SYSTR_POLICY_PERMIT },
59130803Smarcel	{ SYS_gettimeofday, SYSTR_POLICY_PERMIT },
60130803Smarcel	{ SYS_clock_gettime, SYSTR_POLICY_PERMIT },
61130803Smarcel	{ SYS_madvise, SYSTR_POLICY_PERMIT },
62130803Smarcel	{ SYS_mmap, SYSTR_POLICY_PERMIT },
63130803Smarcel	{ SYS_mprotect, SYSTR_POLICY_PERMIT },
64130803Smarcel	{ SYS_mquery, SYSTR_POLICY_PERMIT },
65130803Smarcel	{ SYS_poll, SYSTR_POLICY_PERMIT },
66130803Smarcel	{ SYS_munmap, SYSTR_POLICY_PERMIT },
6719370Spst	{ SYS_read, SYSTR_POLICY_PERMIT },
68130803Smarcel	{ SYS_select, SYSTR_POLICY_PERMIT },
6919370Spst	{ SYS_sigprocmask, SYSTR_POLICY_PERMIT },
7019370Spst	{ SYS_write, SYSTR_POLICY_PERMIT },
7119370Spst	{ -1, -1 }
7219370Spst};
7319370Spst
7498944Sobrienstruct ssh_sandbox {
7519370Spst	int systrace_fd;
7619370Spst	pid_t child_pid;
7719370Spst	void (*osigchld)(int);
7819370Spst};
7919370Spst
8019370Spststruct ssh_sandbox *
8119370Spstssh_sandbox_init(void)
8298944Sobrien{
8319370Spst	struct ssh_sandbox *box;
8419370Spst
8519370Spst	debug3("%s: preparing systrace sandbox", __func__);
8619370Spst	box = xcalloc(1, sizeof(*box));
8719370Spst	box->systrace_fd = -1;
8819370Spst	box->child_pid = 0;
8919370Spst	box->osigchld = signal(SIGCHLD, SIG_IGN);
9019370Spst
9119370Spst	return box;
9219370Spst}
9319370Spst
9419370Spstvoid
9519370Spstssh_sandbox_child(struct ssh_sandbox *box)
9619370Spst{
9719370Spst	debug3("%s: ready", __func__);
9819370Spst	signal(SIGCHLD, box->osigchld);
9919370Spst	if (kill(getpid(), SIGSTOP) != 0)
10019370Spst		fatal("%s: kill(%d, SIGSTOP)", __func__, getpid());
10119370Spst	debug3("%s: started", __func__);
10219370Spst}
10319370Spst
10419370Spststatic void
10519370Spstssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid,
10619370Spst    const struct sandbox_policy *allowed_syscalls)
10719370Spst{
10819370Spst	int dev_systrace, i, j, found, status;
10919370Spst	pid_t pid;
11019370Spst	struct systrace_policy policy;
11119370Spst
11219370Spst	/* Wait for the child to send itself a SIGSTOP */
11319370Spst	debug3("%s: wait for child %ld", __func__, (long)child_pid);
11419370Spst	do {
115130803Smarcel		pid = waitpid(child_pid, &status, WUNTRACED);
11619370Spst	} while (pid == -1 && errno == EINTR);
117130803Smarcel	signal(SIGCHLD, box->osigchld);
11819370Spst	if (!WIFSTOPPED(status)) {
11919370Spst		if (WIFSIGNALED(status))
120130803Smarcel			fatal("%s: child terminated with signal %d",
12119370Spst			    __func__, WTERMSIG(status));
12219370Spst		if (WIFEXITED(status))
12319370Spst			fatal("%s: child exited with status %d",
12419370Spst			    __func__, WEXITSTATUS(status));
12519370Spst		fatal("%s: child not stopped", __func__);
12619370Spst	}
12719370Spst	debug3("%s: child %ld stopped", __func__, (long)child_pid);
12819370Spst	box->child_pid = child_pid;
12919370Spst
13019370Spst	/* Set up systracing of child */
131130803Smarcel	if ((dev_systrace = open("/dev/systrace", O_RDONLY)) == -1)
132130803Smarcel		fatal("%s: open(\"/dev/systrace\"): %s", __func__,
133130803Smarcel		    strerror(errno));
134130803Smarcel	if (ioctl(dev_systrace, STRIOCCLONE, &box->systrace_fd) == -1)
135130803Smarcel		fatal("%s: ioctl(STRIOCCLONE, %d): %s", __func__,
136130803Smarcel		    dev_systrace, strerror(errno));
137130803Smarcel	close(dev_systrace);
138130803Smarcel	debug3("%s: systrace attach, fd=%d", __func__, box->systrace_fd);
13919370Spst	if (ioctl(box->systrace_fd, STRIOCATTACH, &child_pid) == -1)
14019370Spst		fatal("%s: ioctl(%d, STRIOCATTACH, %d): %s", __func__,
14119370Spst		    box->systrace_fd, child_pid, strerror(errno));
14219370Spst
14319370Spst	/* Allocate and assign policy */
14419370Spst	bzero(&policy, sizeof(policy));
14519370Spst	policy.strp_op = SYSTR_POLICY_NEW;
14619370Spst	policy.strp_maxents = SYS_MAXSYSCALL;
14719370Spst	if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1)
14819370Spst		fatal("%s: ioctl(%d, STRIOCPOLICY (new)): %s", __func__,
14919370Spst		    box->systrace_fd, strerror(errno));
15098944Sobrien
15119370Spst	policy.strp_op = SYSTR_POLICY_ASSIGN;
15219370Spst	policy.strp_pid = box->child_pid;
15319370Spst	if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1)
15419370Spst		fatal("%s: ioctl(%d, STRIOCPOLICY (assign)): %s",
15519370Spst		    __func__, box->systrace_fd, strerror(errno));
15619370Spst
15719370Spst	/* Set per-syscall policy */
15819370Spst	for (i = 0; i < SYS_MAXSYSCALL; i++) {
15919370Spst		found = 0;
16019370Spst		for (j = 0; allowed_syscalls[j].syscall != -1; j++) {
16119370Spst			if (allowed_syscalls[j].syscall == i) {
16219370Spst				found = 1;
16319370Spst				break;
16419370Spst			}
16519370Spst		}
16619370Spst		policy.strp_op = SYSTR_POLICY_MODIFY;
16719370Spst		policy.strp_code = i;
16819370Spst		policy.strp_policy = found ?
16998944Sobrien		    allowed_syscalls[j].action : SYSTR_POLICY_KILL;
17019370Spst		if (found)
17119370Spst			debug3("%s: policy: enable syscall %d", __func__, i);
17219370Spst		if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1)
17319370Spst			fatal("%s: ioctl(%d, STRIOCPOLICY (modify)): %s",
17419370Spst			    __func__, box->systrace_fd, strerror(errno));
17598944Sobrien	}
17619370Spst
17719370Spst	/* Signal the child to start running */
17898944Sobrien	debug3("%s: start child %ld", __func__, (long)child_pid);
17998944Sobrien	if (kill(box->child_pid, SIGCONT) != 0)
18046283Sdfr		fatal("%s: kill(%d, SIGCONT)", __func__, box->child_pid);
18119370Spst}
18219370Spst
18319370Spstvoid
18498944Sobrienssh_sandbox_parent_finish(struct ssh_sandbox *box)
18519370Spst{
18619370Spst	/* Closing this before the child exits will terminate it */
18746283Sdfr	close(box->systrace_fd);
18819370Spst
18919370Spst	free(box);
190130803Smarcel	debug3("%s: finished", __func__);
191130803Smarcel}
192130803Smarcel
193130803Smarcelvoid
194130803Smarcelssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
195130803Smarcel{
196130803Smarcel	ssh_sandbox_parent(box, child_pid, preauth_policy);
197130803Smarcel}
198130803Smarcel
199130803Smarcel#endif /* SANDBOX_SYSTRACE */
200130803Smarcel