1 /* $OpenBSD: openbsd-syscalls.c,v 1.43 2013/04/29 00:28:23 okan Exp $ */
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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>
45 #include <kern/syscalls.c>
47 #include <compat/linux/linux_syscalls.c>
56 #include <sys/ioctl.h>
58 #include <dev/systrace.h>
68 #include "intercept.h"
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
},
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,
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 *);
124 obsd_attach(int fd
, pid_t pid
)
126 if (ioctl(fd
, STRIOCATTACH
, &pid
) == -1)
133 obsd_report(int fd
, pid_t pid
)
135 if (ioctl(fd
, STRIOCREPORT
, &pid
) == -1)
142 obsd_detach(int fd
, pid_t pid
)
144 if (ioctl(fd
, STRIOCDETACH
, &pid
) == -1)
153 char *path
= "/dev/systrace";
156 fd
= open(path
, O_RDONLY
, 0);
158 warn("open: %s", path
);
162 if (ioctl(fd
, STRIOCCLONE
, &cfd
) == -1) {
163 warn("ioctl(STRIOCCLONE)");
167 if (fcntl(cfd
, F_SETFD
, FD_CLOEXEC
) == -1)
168 warn("fcntl(F_SETFD)");
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
);
184 if (icpid
->data
!= NULL
)
187 if ((icpid
->data
= malloc(sizeof(struct obsd_data
))) == NULL
)
188 err(1, "%s:%d: malloc", __func__
, __LINE__
);
191 data
->current
= &emulations
[0];
198 obsd_freepid(struct intercept_pid
*ipid
)
200 if (ipid
->data
!= NULL
)
205 obsd_clonepid(struct intercept_pid
*opid
, struct intercept_pid
*npid
)
207 if (opid
->data
== NULL
) {
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
;
224 if (!strcmp(tmp
->name
, name
))
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
)
245 pid
= intercept_getpid(pidnr
);
255 static struct emulation
*
256 obsd_switch_emulation(struct obsd_data
*data
)
258 data
->current
= data
->commit
;
261 return (data
->current
);
265 obsd_syscall_name(pid_t pidnr
, int number
)
267 struct intercept_pid
*pid
;
268 struct emulation
*current
;
270 pid
= obsd_getpid(pidnr
);
273 current
= ((struct obsd_data
*)pid
->data
)->current
;
275 if (number
< 0 || number
>= current
->nsysnames
)
278 return (current
->sysnames
[number
]);
282 obsd_syscall_number(const char *emulation
, const char *name
)
284 struct emulation
*current
;
287 current
= obsd_find_emulation(emulation
);
291 for (i
= 0; i
< current
->nsysnames
; i
++)
292 if (!strcmp(name
, current
->sysnames
[i
]))
299 obsd_translate_policy(short policy
)
303 return (SYSTR_POLICY_ASK
);
304 case ICPOLICY_PERMIT
:
305 return (SYSTR_POLICY_PERMIT
);
308 return (SYSTR_POLICY_NEVER
);
313 obsd_translate_flags(short flags
)
317 return (SYSTR_FLAGS_RESULT
);
324 obsd_translate_errno(int nerrno
)
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
));
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)
360 obsd_scriptname(int fd
, pid_t pid
, char *scriptname
)
362 struct systrace_scriptname sn
;
365 strlcpy(sn
.sn_scriptname
, scriptname
, sizeof(sn
.sn_scriptname
));
367 return (ioctl(fd
, STRIOCSCRIPTNAME
, &sn
));
371 obsd_newpolicy(int fd
)
373 struct systrace_policy pol
;
375 pol
.strp_op
= SYSTR_POLICY_NEW
;
377 pol
.strp_maxents
= 512;
379 if (ioctl(fd
, STRIOCPOLICY
, &pol
) == -1)
382 return (pol
.strp_num
);
386 obsd_assignpolicy(int fd
, pid_t pid
, int num
)
388 struct systrace_policy pol
;
390 pol
.strp_op
= SYSTR_POLICY_ASSIGN
;
394 if (ioctl(fd
, STRIOCPOLICY
, &pol
) == -1)
401 obsd_modifypolicy(int fd
, int num
, int code
, short policy
)
403 struct systrace_policy pol
;
405 pol
.strp_op
= SYSTR_POLICY_MODIFY
;
407 pol
.strp_code
= code
;
408 pol
.strp_policy
= obsd_translate_policy(policy
);
410 if (ioctl(fd
, STRIOCPOLICY
, &pol
) == -1)
417 obsd_replace(int fd
, pid_t pid
, u_int16_t seqnr
,
418 struct intercept_replace
*repl
)
420 struct systrace_replace replace
;
424 memset(&replace
, 0, sizeof(replace
));
426 for (i
= 0, len
= 0; i
< repl
->num
; 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
];
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
;
452 replace
.strr_flags
[i
] = 0;
457 ret
= ioctl(fd
, STRIOCREPLACE
, &replace
);
458 if (ret
== -1 && errno
!= EBUSY
) {
459 warn("%s: ioctl", __func__
);
462 free(replace
.strr_base
);
468 obsd_io(int fd
, pid_t pid
, int op
, void *addr
, u_char
*buf
, size_t size
)
470 struct systrace_io io
;
473 memset(&io
, 0, sizeof(io
));
477 io
.strio_offs
= addr
;
478 io
.strio_op
= (op
== INTERCEPT_READ
? SYSTR_READ
: SYSTR_WRITE
);
479 if (ioctl(fd
, STRIOCIO
, &io
) == -1) {
489 obsd_setcwd(int fd
, pid_t pid
, int atfd
)
491 struct systrace_getcwd gd
;
493 gd
.strgd_atfd
= atfd
;
494 return (ioctl(fd
, STRIOCGETCWD
, &gd
));
501 if ((res
= ioctl(fd
, STRIOCRESCWD
, 0)) == -1)
502 warn("%s: ioctl", __func__
); /* XXX */
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
))
515 *pres
= (void *)args
[off
];
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];
534 if (read(fd
, &msg
, sizeof(msg
)) != sizeof(msg
))
537 icpid
= obsd_getpid(msg
.msg_pid
);
542 current
= data
->current
;
544 seqnr
= msg
.msg_seqnr
;
546 switch (msg
.msg_type
) {
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
);
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
);
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
,
595 if (obsd_answer(fd
, pid
, seqnr
, 0, 0, 0, NULL
) == -1)
596 err(1, "%s:%d: answer", __func__
, __LINE__
);
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__
);
610 case SYSTR_MSG_CHILD
:
611 intercept_child_info(msg
.msg_pid
,
612 msg
.msg_data
.msg_child
.new_pid
);
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__
);
627 #ifdef SYSTR_MSG_POLICYFREE
628 case SYSTR_MSG_POLICYFREE
:
629 intercept_policy_free(msg
.msg_policy
);
636 struct intercept_system intercept
= {