sync
[bitrig.git] / bin / systrace / openbsd-syscalls.c
blobe3bdc48fc28051a41efd1e0fc2eb8894b56e7dfa
1 /* $OpenBSD: openbsd-syscalls.c,v 1.43 2013/04/29 00:28:23 okan Exp $ */
2 /*
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Niels Provos.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/types.h>
32 #include <sys/param.h>
34 #include <sys/syscall.h>
36 #include <compat/linux/linux_syscall.h>
38 #define KTRACE
39 #define PTRACE
40 #define NFSCLIENT
41 #define NFSSERVER
42 #define SYSVSEM
43 #define SYSVMSG
44 #define SYSVSHM
45 #include <kern/syscalls.c>
47 #include <compat/linux/linux_syscalls.c>
48 #undef KTRACE
49 #undef PTRACE
50 #undef NFSCLIENT
51 #undef NFSSERVER
52 #undef SYSVSEM
53 #undef SYSVMSG
54 #undef SYSVSHM
56 #include <sys/ioctl.h>
57 #include <sys/tree.h>
58 #include <dev/systrace.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <fcntl.h>
63 #include <unistd.h>
64 #include <string.h>
65 #include <errno.h>
66 #include <err.h>
68 #include "intercept.h"
70 struct emulation {
71 const char *name; /* Emulation name */
72 char **sysnames; /* Array of system call names */
73 int nsysnames; /* Number of */
76 static struct emulation emulations[] = {
77 { "native", syscallnames, SYS_MAXSYSCALL },
78 { "aout", syscallnames, SYS_MAXSYSCALL },
79 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL },
80 { NULL, NULL, 0 }
83 struct obsd_data {
84 struct emulation *current;
85 struct emulation *commit;
88 static int obsd_init(void);
89 static int obsd_attach(int, pid_t);
90 static int obsd_report(int, pid_t);
91 static int obsd_detach(int, pid_t);
92 static int obsd_open(void);
93 static struct intercept_pid *obsd_getpid(pid_t);
94 static void obsd_freepid(struct intercept_pid *);
95 static void obsd_clonepid(struct intercept_pid *, struct intercept_pid *);
96 static struct emulation *obsd_find_emulation(const char *);
97 static int obsd_set_emulation(pid_t, const char *);
98 static struct emulation *obsd_switch_emulation(struct obsd_data *);
99 static const char *obsd_syscall_name(pid_t, int);
100 static int obsd_syscall_number(const char *, const char *);
101 static short obsd_translate_policy(short);
102 static short obsd_translate_flags(short);
103 static int obsd_translate_errno(int);
104 static int obsd_answer(int, pid_t, u_int16_t, short, int, short,
105 struct elevate *);
106 static int obsd_newpolicy(int);
107 static int obsd_assignpolicy(int, pid_t, int);
108 static int obsd_modifypolicy(int, int, int, short);
109 static int obsd_replace(int, pid_t, u_int16_t, struct intercept_replace *);
110 static int obsd_io(int, pid_t, int, void *, u_char *, size_t);
111 static int obsd_setcwd(int, pid_t, int);
112 static int obsd_restcwd(int);
113 static int obsd_argument(int, void *, int, void **);
114 static int obsd_read(int);
115 static int obsd_scriptname(int, pid_t, char *);
117 static int
118 obsd_init(void)
120 return (0);
123 static int
124 obsd_attach(int fd, pid_t pid)
126 if (ioctl(fd, STRIOCATTACH, &pid) == -1)
127 return (-1);
129 return (0);
132 static int
133 obsd_report(int fd, pid_t pid)
135 if (ioctl(fd, STRIOCREPORT, &pid) == -1)
136 return (-1);
138 return (0);
141 static int
142 obsd_detach(int fd, pid_t pid)
144 if (ioctl(fd, STRIOCDETACH, &pid) == -1)
145 return (-1);
147 return (0);
150 static int
151 obsd_open(void)
153 char *path = "/dev/systrace";
154 int fd, cfd = -1;
156 fd = open(path, O_RDONLY, 0);
157 if (fd == -1) {
158 warn("open: %s", path);
159 return (-1);
162 if (ioctl(fd, STRIOCCLONE, &cfd) == -1) {
163 warn("ioctl(STRIOCCLONE)");
164 goto out;
167 if (fcntl(cfd, F_SETFD, FD_CLOEXEC) == -1)
168 warn("fcntl(F_SETFD)");
170 out:
171 close (fd);
172 return (cfd);
175 static struct intercept_pid *
176 obsd_getpid(pid_t pid)
178 struct intercept_pid *icpid;
179 struct obsd_data *data;
181 icpid = intercept_getpid(pid);
182 if (icpid == NULL)
183 return (NULL);
184 if (icpid->data != NULL)
185 return (icpid);
187 if ((icpid->data = malloc(sizeof(struct obsd_data))) == NULL)
188 err(1, "%s:%d: malloc", __func__, __LINE__);
190 data = icpid->data;
191 data->current = &emulations[0];
192 data->commit = NULL;
194 return (icpid);
197 static void
198 obsd_freepid(struct intercept_pid *ipid)
200 if (ipid->data != NULL)
201 free(ipid->data);
204 static void
205 obsd_clonepid(struct intercept_pid *opid, struct intercept_pid *npid)
207 if (opid->data == NULL) {
208 npid->data = NULL;
209 return;
212 if ((npid->data = malloc(sizeof(struct obsd_data))) == NULL)
213 err(1, "%s:%d: malloc", __func__, __LINE__);
214 memcpy(npid->data, opid->data, sizeof(struct obsd_data));
217 static struct emulation *
218 obsd_find_emulation(const char *name)
220 struct emulation *tmp;
222 tmp = emulations;
223 while (tmp->name) {
224 if (!strcmp(tmp->name, name))
225 break;
226 tmp++;
229 if (!tmp->name)
230 return (NULL);
232 return (tmp);
235 static int
236 obsd_set_emulation(pid_t pidnr, const char *name)
238 struct emulation *tmp;
239 struct intercept_pid *pid;
240 struct obsd_data *data;
242 if ((tmp = obsd_find_emulation(name)) == NULL)
243 return (-1);
245 pid = intercept_getpid(pidnr);
246 if (pid == NULL)
247 return (-1);
248 data = pid->data;
250 data->commit = tmp;
252 return (0);
255 static struct emulation *
256 obsd_switch_emulation(struct obsd_data *data)
258 data->current = data->commit;
259 data->commit = NULL;
261 return (data->current);
264 static const char *
265 obsd_syscall_name(pid_t pidnr, int number)
267 struct intercept_pid *pid;
268 struct emulation *current;
270 pid = obsd_getpid(pidnr);
271 if (pid == NULL)
272 return (NULL);
273 current = ((struct obsd_data *)pid->data)->current;
275 if (number < 0 || number >= current->nsysnames)
276 return (NULL);
278 return (current->sysnames[number]);
281 static int
282 obsd_syscall_number(const char *emulation, const char *name)
284 struct emulation *current;
285 int i;
287 current = obsd_find_emulation(emulation);
288 if (current == NULL)
289 return (-1);
291 for (i = 0; i < current->nsysnames; i++)
292 if (!strcmp(name, current->sysnames[i]))
293 return (i);
295 return (-1);
298 static short
299 obsd_translate_policy(short policy)
301 switch (policy) {
302 case ICPOLICY_ASK:
303 return (SYSTR_POLICY_ASK);
304 case ICPOLICY_PERMIT:
305 return (SYSTR_POLICY_PERMIT);
306 case ICPOLICY_NEVER:
307 default:
308 return (SYSTR_POLICY_NEVER);
312 static short
313 obsd_translate_flags(short flags)
315 switch (flags) {
316 case ICFLAGS_RESULT:
317 return (SYSTR_FLAGS_RESULT);
318 default:
319 return (0);
323 static int
324 obsd_translate_errno(int nerrno)
326 return (nerrno);
329 static int
330 obsd_answer(int fd, pid_t pid, u_int16_t seqnr, short policy, int nerrno,
331 short flags, struct elevate *elevate)
333 struct systrace_answer ans;
335 memset(&ans, 0, sizeof(ans));
336 ans.stra_pid = pid;
337 ans.stra_seqnr = seqnr;
338 ans.stra_policy = obsd_translate_policy(policy);
339 ans.stra_flags = obsd_translate_flags(flags);
340 ans.stra_error = obsd_translate_errno(nerrno);
342 if (elevate != NULL) {
343 if (elevate->e_flags & ELEVATE_UID) {
344 ans.stra_flags |= SYSTR_FLAGS_SETEUID;
345 ans.stra_seteuid = elevate->e_uid;
347 if (elevate->e_flags & ELEVATE_GID) {
348 ans.stra_flags |= SYSTR_FLAGS_SETEGID;
349 ans.stra_setegid = elevate->e_gid;
353 if (ioctl(fd, STRIOCANSWER, &ans) == -1)
354 return (-1);
356 return (0);
359 static int
360 obsd_scriptname(int fd, pid_t pid, char *scriptname)
362 struct systrace_scriptname sn;
364 sn.sn_pid = pid;
365 strlcpy(sn.sn_scriptname, scriptname, sizeof(sn.sn_scriptname));
367 return (ioctl(fd, STRIOCSCRIPTNAME, &sn));
370 static int
371 obsd_newpolicy(int fd)
373 struct systrace_policy pol;
375 pol.strp_op = SYSTR_POLICY_NEW;
376 pol.strp_num = -1;
377 pol.strp_maxents = 512;
379 if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
380 return (-1);
382 return (pol.strp_num);
385 static int
386 obsd_assignpolicy(int fd, pid_t pid, int num)
388 struct systrace_policy pol;
390 pol.strp_op = SYSTR_POLICY_ASSIGN;
391 pol.strp_num = num;
392 pol.strp_pid = pid;
394 if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
395 return (-1);
397 return (0);
400 static int
401 obsd_modifypolicy(int fd, int num, int code, short policy)
403 struct systrace_policy pol;
405 pol.strp_op = SYSTR_POLICY_MODIFY;
406 pol.strp_num = num;
407 pol.strp_code = code;
408 pol.strp_policy = obsd_translate_policy(policy);
410 if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
411 return (-1);
413 return (0);
416 static int
417 obsd_replace(int fd, pid_t pid, u_int16_t seqnr,
418 struct intercept_replace *repl)
420 struct systrace_replace replace;
421 size_t len, off;
422 int i, ret;
424 memset(&replace, 0, sizeof(replace));
426 for (i = 0, len = 0; i < repl->num; i++) {
427 len += repl->len[i];
430 replace.strr_pid = pid;
431 replace.strr_seqnr = seqnr;
432 replace.strr_nrepl = repl->num;
433 replace.strr_base = malloc(len);
434 replace.strr_len = len;
435 if (replace.strr_base == NULL)
436 err(1, "%s: malloc", __func__);
438 for (i = 0, off = 0; i < repl->num; i++) {
439 replace.strr_argind[i] = repl->ind[i];
440 replace.strr_offlen[i] = repl->len[i];
441 if (repl->len[i] == 0) {
442 replace.strr_off[i] = (size_t)repl->address[i];
443 continue;
446 replace.strr_off[i] = off;
447 memcpy(replace.strr_base + off,
448 repl->address[i], repl->len[i]);
449 if (repl->flags[i] & ICTRANS_NOLINKS) {
450 replace.strr_flags[i] = SYSTR_NOLINKS;
451 } else
452 replace.strr_flags[i] = 0;
454 off += repl->len[i];
457 ret = ioctl(fd, STRIOCREPLACE, &replace);
458 if (ret == -1 && errno != EBUSY) {
459 warn("%s: ioctl", __func__);
462 free(replace.strr_base);
464 return (ret);
467 static int
468 obsd_io(int fd, pid_t pid, int op, void *addr, u_char *buf, size_t size)
470 struct systrace_io io;
471 extern int ic_abort;
473 memset(&io, 0, sizeof(io));
474 io.strio_pid = pid;
475 io.strio_addr = buf;
476 io.strio_len = size;
477 io.strio_offs = addr;
478 io.strio_op = (op == INTERCEPT_READ ? SYSTR_READ : SYSTR_WRITE);
479 if (ioctl(fd, STRIOCIO, &io) == -1) {
480 if (errno == EBUSY)
481 ic_abort = 1;
482 return (-1);
485 return (0);
488 static int
489 obsd_setcwd(int fd, pid_t pid, int atfd)
491 struct systrace_getcwd gd;
492 gd.strgd_pid = pid;
493 gd.strgd_atfd = atfd;
494 return (ioctl(fd, STRIOCGETCWD, &gd));
497 static int
498 obsd_restcwd(int fd)
500 int res;
501 if ((res = ioctl(fd, STRIOCRESCWD, 0)) == -1)
502 warn("%s: ioctl", __func__); /* XXX */
504 return (res);
507 static int
508 obsd_argument(int off, void *pargs, int argsize, void **pres)
510 register_t *args = (register_t *)pargs;
512 if (off >= argsize / sizeof(register_t))
513 return (-1);
515 *pres = (void *)args[off];
517 return (0);
520 static int
521 obsd_read(int fd)
523 struct str_message msg;
524 struct intercept_pid *icpid;
525 struct obsd_data *data;
526 struct emulation *current;
528 char name[SYSTR_EMULEN+1];
529 const char *sysname;
530 u_int16_t seqnr;
531 pid_t pid;
532 int code;
534 if (read(fd, &msg, sizeof(msg)) != sizeof(msg))
535 return (-1);
537 icpid = obsd_getpid(msg.msg_pid);
538 if (icpid == NULL)
539 return (-1);
540 data = icpid->data;
542 current = data->current;
544 seqnr = msg.msg_seqnr;
545 pid = msg.msg_pid;
546 switch (msg.msg_type) {
547 case SYSTR_MSG_ASK:
548 code = msg.msg_data.msg_ask.code;
549 sysname = obsd_syscall_name(pid, code);
551 intercept_syscall(fd, pid, seqnr, msg.msg_policy,
552 sysname, code, current->name,
553 (void *)msg.msg_data.msg_ask.args,
554 msg.msg_data.msg_ask.argsize);
555 break;
557 case SYSTR_MSG_RES:
558 code = msg.msg_data.msg_ask.code;
559 sysname = obsd_syscall_name(pid, code);
561 /* Switch emulation around at the right time */
562 if (data->commit != NULL) {
563 current = obsd_switch_emulation(data);
566 intercept_syscall_result(fd, pid, seqnr, msg.msg_policy,
567 sysname, code, current->name,
568 (void *)msg.msg_data.msg_ask.args,
569 msg.msg_data.msg_ask.argsize,
570 msg.msg_data.msg_ask.result,
571 msg.msg_data.msg_ask.rval);
572 break;
574 case SYSTR_MSG_EMUL:
575 memcpy(name, msg.msg_data.msg_emul.emul, SYSTR_EMULEN);
576 name[SYSTR_EMULEN] = '\0';
578 if (obsd_set_emulation(pid, name) == -1)
579 errx(1, "%s:%d: set_emulation(%s)",
580 __func__, __LINE__, name);
582 if (icpid->execve_code == -1) {
583 icpid->execve_code = 0;
585 /* A running attach fake a exec cb */
586 current = obsd_switch_emulation(data);
588 intercept_syscall_result(fd,
589 pid, seqnr, msg.msg_policy,
590 "execve", 0, current->name,
591 NULL, 0, 0, NULL);
592 break;
595 if (obsd_answer(fd, pid, seqnr, 0, 0, 0, NULL) == -1)
596 err(1, "%s:%d: answer", __func__, __LINE__);
597 break;
599 case SYSTR_MSG_UGID: {
600 struct str_msg_ugid *msg_ugid;
602 msg_ugid = &msg.msg_data.msg_ugid;
604 intercept_ugid(icpid, msg_ugid->uid, msg_ugid->uid);
606 if (obsd_answer(fd, pid, seqnr, 0, 0, 0, NULL) == -1)
607 err(1, "%s:%d: answer", __func__, __LINE__);
608 break;
610 case SYSTR_MSG_CHILD:
611 intercept_child_info(msg.msg_pid,
612 msg.msg_data.msg_child.new_pid);
613 break;
614 #ifdef SYSTR_MSG_EXECVE
615 case SYSTR_MSG_EXECVE: {
616 struct str_msg_execve *msg_execve = &msg.msg_data.msg_execve;
618 intercept_newimage(fd, pid, msg.msg_policy, current->name,
619 msg_execve->path, NULL);
621 if (obsd_answer(fd, pid, seqnr, 0, 0, 0, NULL) == -1)
622 err(1, "%s:%d: answer", __func__, __LINE__);
623 break;
625 #endif
627 #ifdef SYSTR_MSG_POLICYFREE
628 case SYSTR_MSG_POLICYFREE:
629 intercept_policy_free(msg.msg_policy);
630 break;
631 #endif
633 return (0);
636 struct intercept_system intercept = {
637 "openbsd",
638 obsd_init,
639 obsd_open,
640 obsd_attach,
641 obsd_detach,
642 obsd_report,
643 obsd_read,
644 obsd_syscall_number,
645 obsd_setcwd,
646 obsd_restcwd,
647 obsd_io,
648 obsd_argument,
649 obsd_answer,
650 obsd_newpolicy,
651 obsd_assignpolicy,
652 obsd_modifypolicy,
653 obsd_replace,
654 obsd_clonepid,
655 obsd_freepid,
656 obsd_scriptname,