Annotation of src/usr.bin/ssh/sandbox-systrace.c, Revision 1.1
1.1 ! djm 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 <sys/types.h>
! 18: #include <sys/param.h>
! 19: #include <sys/ioctl.h>
! 20: #include <sys/syscall.h>
! 21: #include <sys/socket.h>
! 22:
! 23: #include <dev/systrace.h>
! 24:
! 25: #include <errno.h>
! 26: #include <fcntl.h>
! 27: #include <limits.h>
! 28: #include <stdarg.h>
! 29: #include <stdio.h>
! 30: #include <stdlib.h>
! 31: #include <string.h>
! 32: #include <unistd.h>
! 33:
! 34: #include "atomicio.h"
! 35: #include "log.h"
! 36: #include "sandbox.h"
! 37: #include "xmalloc.h"
! 38:
! 39: static const int preauth_policy[] = {
! 40: SYS___sysctl,
! 41: SYS_close,
! 42: SYS_exit,
! 43: SYS_getpid,
! 44: SYS_gettimeofday,
! 45: SYS_madvise,
! 46: SYS_mmap,
! 47: SYS_mprotect,
! 48: SYS_poll,
! 49: SYS_munmap,
! 50: SYS_read,
! 51: SYS_select,
! 52: SYS_sigprocmask,
! 53: SYS_write,
! 54: -1
! 55: };
! 56:
! 57: struct ssh_sandbox {
! 58: int child_sock;
! 59: int parent_sock;
! 60: int systrace_fd;
! 61: pid_t child_pid;
! 62: struct systrace_policy policy;
! 63: };
! 64:
! 65: struct ssh_sandbox *
! 66: ssh_sandbox_init(void)
! 67: {
! 68: struct ssh_sandbox *box;
! 69: int s[2];
! 70:
! 71: debug3("%s: preparing systrace sandbox", __func__);
! 72: box = xcalloc(1, sizeof(*box));
! 73: if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1)
! 74: fatal("%s: socketpair: %s", __func__, strerror(errno));
! 75: box->child_sock = s[0];
! 76: box->parent_sock = s[1];
! 77: box->systrace_fd = -1;
! 78: box->child_pid = 0;
! 79:
! 80: return box;
! 81: }
! 82:
! 83: void
! 84: ssh_sandbox_child(struct ssh_sandbox *box)
! 85: {
! 86: char whatever = 0;
! 87:
! 88: close(box->parent_sock);
! 89: /* Signal parent that we are ready */
! 90: debug3("%s: ready", __func__);
! 91: if (atomicio(vwrite, box->child_sock, &whatever, 1) != 1)
! 92: fatal("%s: write: %s", __func__, strerror(errno));
! 93: /* Wait for parent to signal for us to go */
! 94: if (atomicio(read, box->child_sock, &whatever, 1) != 1)
! 95: fatal("%s: read: %s", __func__, strerror(errno));
! 96: debug3("%s: started", __func__);
! 97: close(box->child_sock);
! 98: }
! 99:
! 100: static void
! 101: ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid,
! 102: const int *allowed_syscalls)
! 103: {
! 104: int dev_systrace, i, j, found;
! 105: char whatever = 0;
! 106:
! 107: debug3("%s: wait for child %ld", __func__, (long)child_pid);
! 108: box->child_pid = child_pid;
! 109: close(box->child_sock);
! 110: /* Wait for child to signal that it is ready */
! 111: if (atomicio(read, box->parent_sock, &whatever, 1) != 1)
! 112: fatal("%s: read: %s", __func__, strerror(errno));
! 113: debug3("%s: child %ld ready", __func__, (long)child_pid);
! 114:
! 115: /* Set up systracing of child */
! 116: if ((dev_systrace = open("/dev/systrace", O_RDONLY)) == -1)
! 117: fatal("%s: open(\"/dev/systrace\"): %s", __func__,
! 118: strerror(errno));
! 119: if (ioctl(dev_systrace, STRIOCCLONE, &box->systrace_fd) == -1)
! 120: fatal("%s: ioctl(STRIOCCLONE, %d): %s", __func__,
! 121: dev_systrace, strerror(errno));
! 122: close(dev_systrace);
! 123: debug3("%s: systrace attach, fd=%d", __func__, box->systrace_fd);
! 124: if (ioctl(box->systrace_fd, STRIOCATTACH, &child_pid) == -1)
! 125: fatal("%s: ioctl(%d, STRIOCATTACH, %d): %s", __func__,
! 126: box->systrace_fd, child_pid, strerror(errno));
! 127:
! 128: /* Allocate and assign policy */
! 129: bzero(&box->policy, sizeof(box->policy));
! 130: box->policy.strp_op = SYSTR_POLICY_NEW;
! 131: box->policy.strp_maxents = SYS_MAXSYSCALL;
! 132: if (ioctl(box->systrace_fd, STRIOCPOLICY, &box->policy) == -1)
! 133: fatal("%s: ioctl(%d, STRIOCPOLICY (new)): %s", __func__,
! 134: box->systrace_fd, strerror(errno));
! 135:
! 136: box->policy.strp_op = SYSTR_POLICY_ASSIGN;
! 137: box->policy.strp_pid = box->child_pid;
! 138: if (ioctl(box->systrace_fd, STRIOCPOLICY, &box->policy) == -1)
! 139: fatal("%s: ioctl(%d, STRIOCPOLICY (assign)): %s",
! 140: __func__, box->systrace_fd, strerror(errno));
! 141:
! 142: /* Set per-syscall policy */
! 143: for (i = 0; i < SYS_MAXSYSCALL; i++) {
! 144: for (j = found = 0; allowed_syscalls[j] != -1 && !found; j++) {
! 145: if (allowed_syscalls[j] == i)
! 146: found = 1;
! 147: }
! 148: box->policy.strp_op = SYSTR_POLICY_MODIFY;
! 149: box->policy.strp_code = i;
! 150: box->policy.strp_policy = found ?
! 151: SYSTR_POLICY_PERMIT : SYSTR_POLICY_KILL;
! 152: if (found)
! 153: debug3("%s: policy: enable syscall %d", __func__, i);
! 154: if (ioctl(box->systrace_fd, STRIOCPOLICY,
! 155: &box->policy) == -1)
! 156: fatal("%s: ioctl(%d, STRIOCPOLICY (modify)): %s",
! 157: __func__, box->systrace_fd, strerror(errno));
! 158: }
! 159:
! 160: /* Signal the child to start running */
! 161: debug3("%s: start child %ld", __func__, (long)child_pid);
! 162: if (atomicio(vwrite, box->parent_sock, &whatever, 1) != 1)
! 163: fatal("%s: write: %s", __func__, strerror(errno));
! 164: close(box->parent_sock);
! 165: }
! 166:
! 167: void
! 168: ssh_sandbox_parent_finish(struct ssh_sandbox *box)
! 169: {
! 170: /* Closing this before the child exits will terminate it */
! 171: close(box->systrace_fd);
! 172:
! 173: free(box);
! 174: debug3("%s: finished", __func__);
! 175: }
! 176:
! 177: void
! 178: ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
! 179: {
! 180: ssh_sandbox_parent(box, child_pid, preauth_policy);
! 181: }