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