1 /* $OpenBSD: systrace-translate.c,v 1.21 2006/07/02 12:34:15 sturm Exp $ */
2 /*
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4 * All rights reserved.
5 *
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.
19 *
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.
30 */
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <sys/tree.h>
35 #include <sys/socket.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <inttypes.h>
39 #include <limits.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <fcntl.h>
45 #include <pwd.h>
46 #include <err.h>
47
48 #include "../../sys/compat/linux/linux_types.h"
49 #include "../../sys/compat/linux/linux_fcntl.h"
50
51 #include "intercept.h"
52 #include "systrace.h"
53
54 #define FL(w,c) do { \
55 if (flags & (w) && p < str + sizeof str - 1) \
56 *p++ = (c); \
57 } while (0)
58
59 static int print_oflags(char *, size_t, struct intercept_translate *);
60 static int linux_print_oflags(char *, size_t, struct intercept_translate *);
61 static int print_modeflags(char *, size_t, struct intercept_translate *);
62 static int print_number(char *, size_t, struct intercept_translate *);
63 static int print_uname(char *, size_t, struct intercept_translate *);
64 static int print_pidname(char *, size_t, struct intercept_translate *);
65 static int print_signame(char *, size_t, struct intercept_translate *);
66 static int print_fcntlcmd(char *, size_t, struct intercept_translate *);
67 static int print_memprot(char *, size_t, struct intercept_translate *);
68 static int print_fileflags(char *, size_t, struct intercept_translate *);
69 static int get_argv(struct intercept_translate *, int, pid_t, void *);
70 static int print_argv(char *, size_t, struct intercept_translate *);
71
72 static int
print_oflags(char * buf,size_t buflen,struct intercept_translate * tl)73 print_oflags(char *buf, size_t buflen, struct intercept_translate *tl)
74 {
75 char str[32], *p;
76 int flags = (intptr_t)tl->trans_addr;
77 int isread = 0;
78
79 p = str;
80 switch (flags & O_ACCMODE) {
81 case O_RDONLY:
82 strlcpy(p, "ro", str + sizeof str - p);
83 isread = 1;
84 break;
85 case O_WRONLY:
86 strlcpy(p, "wo", str + sizeof str - p);
87 break;
88 case O_RDWR:
89 strlcpy(p, "rw", str + sizeof str - p);
90 break;
91 default:
92 strlcpy(p, "--", str + sizeof str - p);
93 break;
94 }
95
96 /* XXX - Open handling of alias */
97 if (isread)
98 systrace_switch_alias("native", "open", "native", "fsread");
99 else
100 systrace_switch_alias("native", "open", "native", "fswrite");
101
102 p += 2;
103
104 FL(O_NONBLOCK, 'n');
105 FL(O_APPEND, 'a');
106 FL(O_CREAT, 'c');
107 FL(O_TRUNC, 't');
108
109 *p = '\0';
110
111 strlcpy(buf, str, buflen);
112
113 return (0);
114 }
115
116 static int
linux_print_oflags(char * buf,size_t buflen,struct intercept_translate * tl)117 linux_print_oflags(char *buf, size_t buflen, struct intercept_translate *tl)
118 {
119 char str[32], *p;
120 int flags = (intptr_t)tl->trans_addr;
121 int isread = 0;
122
123 p = str;
124 switch (flags & LINUX_O_ACCMODE) {
125 case LINUX_O_RDONLY:
126 strlcpy(p, "ro", str + sizeof str - p);
127 isread = 1;
128 break;
129 case LINUX_O_WRONLY:
130 strlcpy(p, "wo", str + sizeof str - p);
131 break;
132 case LINUX_O_RDWR:
133 strlcpy(p, "rw", str + sizeof str - p);
134 break;
135 default:
136 strlcpy(p, "--", str + sizeof str - p);
137 break;
138 }
139
140 /* XXX - Open handling of alias */
141 if (isread)
142 systrace_switch_alias("linux", "open", "linux", "fsread");
143 else
144 systrace_switch_alias("linux", "open", "linux", "fswrite");
145
146 p += 2;
147
148 FL(LINUX_O_APPEND, 'a');
149 FL(LINUX_O_CREAT, 'c');
150 FL(LINUX_O_TRUNC, 't');
151
152 *p = '\0';
153
154 strlcpy(buf, str, buflen);
155
156 return (0);
157 }
158
159 static int
print_modeflags(char * buf,size_t buflen,struct intercept_translate * tl)160 print_modeflags(char *buf, size_t buflen, struct intercept_translate *tl)
161 {
162 int mode = (intptr_t)tl->trans_addr;
163
164 mode &= 00007777;
165 snprintf(buf, buflen, "%o", mode);
166
167 return (0);
168 }
169
170 static int
print_number(char * buf,size_t buflen,struct intercept_translate * tl)171 print_number(char *buf, size_t buflen, struct intercept_translate *tl)
172 {
173 int number = (intptr_t)tl->trans_addr;
174
175 snprintf(buf, buflen, "%d", number);
176
177 return (0);
178 }
179
180 static int
print_sockdom(char * buf,size_t buflen,struct intercept_translate * tl)181 print_sockdom(char *buf, size_t buflen, struct intercept_translate *tl)
182 {
183 int domain = (intptr_t)tl->trans_addr;
184 char *what = NULL;
185
186 switch (domain) {
187 case AF_UNIX:
188 what = "AF_UNIX";
189 break;
190 case AF_INET:
191 what = "AF_INET";
192 break;
193 case AF_INET6:
194 what = "AF_INET6";
195 break;
196 case AF_IPX:
197 what = "AF_IPX";
198 break;
199 case AF_ISO:
200 what = "AF_ISO";
201 break;
202 case AF_NS:
203 what = "AF_NS";
204 break;
205 case AF_IMPLINK:
206 what = "AF_IMPLINK";
207 break;
208 default:
209 snprintf(buf, buflen, "AF_UNKNOWN(%d)", domain);
210 break;
211 }
212
213 if (what != NULL)
214 strlcpy(buf, what, buflen);
215
216 return (0);
217 }
218
219 static int
print_socktype(char * buf,size_t buflen,struct intercept_translate * tl)220 print_socktype(char *buf, size_t buflen, struct intercept_translate *tl)
221 {
222 int type = (intptr_t)tl->trans_addr;
223 char *what = NULL;
224
225 switch (type) {
226 case SOCK_STREAM:
227 what = "SOCK_STREAM";
228 break;
229 case SOCK_DGRAM:
230 what = "SOCK_DGRAM";
231 break;
232 case SOCK_RAW:
233 what = "SOCK_RAW";
234 break;
235 case SOCK_SEQPACKET:
236 what = "SOCK_SEQPACKET";
237 break;
238 case SOCK_RDM:
239 what = "SOCK_RDM";
240 break;
241 default:
242 snprintf(buf, buflen, "SOCK_UNKNOWN(%d)", type);
243 break;
244 }
245
246 if (what != NULL)
247 strlcpy(buf, what, buflen);
248
249 return (0);
250 }
251
252 static int
print_uname(char * buf,size_t buflen,struct intercept_translate * tl)253 print_uname(char *buf, size_t buflen, struct intercept_translate *tl)
254 {
255 struct passwd *pw;
256 uid_t uid = (intptr_t)tl->trans_addr;
257
258 pw = getpwuid(uid);
259 strlcpy(buf, pw != NULL ? pw->pw_name : "<unknown>", buflen);
260
261 return (0);
262 }
263
264 static int
print_pidname(char * buf,size_t buflen,struct intercept_translate * tl)265 print_pidname(char *buf, size_t buflen, struct intercept_translate *tl)
266 {
267 struct intercept_pid *icpid;
268 pid_t pid = (intptr_t)tl->trans_addr;
269
270 if (pid > 0) {
271 icpid = intercept_findpid(pid);
272 strlcpy(buf, icpid != NULL ? icpid->name : "<unknown>", buflen);
273 } else if (pid == 0) {
274 strlcpy(buf, "<own process group>", buflen);
275 } else if (pid == -1) {
276 strlcpy(buf, "<every process: -1>", buflen);
277 } else {
278 /* pid is negative but not -1 - trying to signal pgroup */
279 pid = -pid;
280 icpid = intercept_findpid(pid);
281 strlcpy(buf, "pg:", buflen);
282 strlcat(buf, icpid != NULL ? icpid->name : "unknown", buflen);
283 }
284
285 return (0);
286 }
287
288 static int
print_signame(char * buf,size_t buflen,struct intercept_translate * tl)289 print_signame(char *buf, size_t buflen, struct intercept_translate *tl)
290 {
291 int sig = (intptr_t)tl->trans_addr;
292 char *name;
293
294 switch (sig) {
295 case SIGHUP:
296 name = "SIGHUP";
297 break;
298 case SIGINT:
299 name = "SIGINT";
300 break;
301 case SIGQUIT:
302 name = "SIGQUIT";
303 break;
304 case SIGILL:
305 name = "SIGILL";
306 break;
307 case SIGABRT:
308 name = "SIGABRT";
309 break;
310 case SIGFPE:
311 name = "SIGFPE";
312 break;
313 case SIGKILL:
314 name = "SIGKILL";
315 break;
316 case SIGBUS:
317 name = "SIGBUS";
318 break;
319 case SIGSEGV:
320 name = "SIGSEGV";
321 break;
322 case SIGSYS:
323 name = "SIGSYS";
324 break;
325 case SIGPIPE:
326 name = "SIGPIPE";
327 break;
328 case SIGALRM:
329 name = "SIGALRM";
330 break;
331 case SIGTERM:
332 name = "SIGTERM";
333 break;
334 case SIGURG:
335 name = "SIGURG";
336 break;
337 case SIGSTOP:
338 name = "SIGSTOP";
339 break;
340 case SIGTSTP:
341 name = "SIGTSTP";
342 break;
343 case SIGCONT:
344 name = "SIGCONT";
345 break;
346 case SIGCHLD:
347 name = "SIGCHLD";
348 break;
349 case SIGTTIN:
350 name = "SIGTTIN";
351 break;
352 case SIGTTOU:
353 name = "SIGTTOU";
354 break;
355 case SIGIO:
356 name = "SIGIO";
357 break;
358 case SIGPROF:
359 name = "SIGPROF";
360 break;
361 case SIGWINCH:
362 name = "SIGWINCH";
363 break;
364 #ifndef __linux__
365 case SIGINFO:
366 name = "SIGINFO";
367 break;
368 #endif /* !__linux__ */
369 case SIGUSR1:
370 name = "SIGUSR1";
371 break;
372 case SIGUSR2:
373 name = "SIGUSR2";
374 break;
375 default:
376 snprintf(buf, buflen, "<unknown>: %d", sig);
377 return (0);
378 }
379
380 strlcpy(buf, name, buflen);
381 return (0);
382 }
383
384 static int
print_fcntlcmd(char * buf,size_t buflen,struct intercept_translate * tl)385 print_fcntlcmd(char *buf, size_t buflen, struct intercept_translate *tl)
386 {
387 int cmd = (intptr_t)tl->trans_addr;
388 char *name;
389
390 switch (cmd) {
391 case F_DUPFD:
392 name = "F_DUPFD";
393 break;
394 case F_GETFD:
395 name = "F_GETFD";
396 break;
397 case F_SETFD:
398 name = "F_SETFD";
399 break;
400 case F_GETFL:
401 name = "F_GETFL";
402 break;
403 case F_SETFL:
404 name = "F_SETFL";
405 break;
406 case F_GETOWN:
407 name = "F_GETOWN";
408 break;
409 case F_SETOWN:
410 name = "F_SETOWN";
411 break;
412 case F_GETLK:
413 name = "F_GETLK";
414 break;
415 case F_SETLK:
416 name = "F_SETLK";
417 break;
418 case F_SETLKW:
419 name = "F_SETLKW";
420 break;
421 default:
422 snprintf(buf, buflen, "<unknown>: %d", cmd);
423 return (0);
424 }
425
426 snprintf(buf, buflen, "%s", name);
427 return (0);
428 }
429
430 struct linux_i386_mmap_arg_struct {
431 unsigned long addr;
432 unsigned long len;
433 unsigned long prot;
434 unsigned long flags;
435 unsigned long fd;
436 unsigned long offset;
437 };
438
439 static int
get_linux_memprot(struct intercept_translate * trans,int fd,pid_t pid,void * addr)440 get_linux_memprot(struct intercept_translate *trans, int fd, pid_t pid,
441 void *addr)
442 {
443 struct linux_i386_mmap_arg_struct arg;
444 size_t len = sizeof(arg);
445 extern struct intercept_system intercept;
446
447 if (intercept.io(fd, pid, INTERCEPT_READ, addr,
448 (void *)&arg, len) == -1)
449 return (-1);
450
451 trans->trans_addr = (void *)arg.prot;
452
453 return (0);
454 }
455
456 static int
print_memprot(char * buf,size_t buflen,struct intercept_translate * tl)457 print_memprot(char *buf, size_t buflen, struct intercept_translate *tl)
458 {
459 int prot = (intptr_t)tl->trans_addr;
460 char lbuf[64];
461
462 if (prot == PROT_NONE) {
463 strlcpy(buf, "PROT_NONE", buflen);
464 return (0);
465 } else
466 *buf = '\0';
467
468 while (prot) {
469 if (*buf)
470 strlcat(buf, "|", buflen);
471
472 if (prot & PROT_READ) {
473 strlcat(buf, "PROT_READ", buflen);
474 prot &= ~PROT_READ;
475 continue;
476 }
477
478 if (prot & PROT_WRITE) {
479 strlcat(buf, "PROT_WRITE", buflen);
480 prot &= ~PROT_WRITE;
481 continue;
482 }
483
484 if (prot & PROT_EXEC) {
485 strlcat(buf, "PROT_EXEC", buflen);
486 prot &= ~PROT_EXEC;
487 continue;
488 }
489
490 if (prot) {
491 snprintf(lbuf, sizeof(lbuf), "<unknown:0x%x>", prot);
492 strlcat(buf, lbuf, buflen);
493 prot = 0;
494 continue;
495 }
496 }
497
498 return (0);
499 }
500
501 static int
print_fileflags(char * buf,size_t buflen,struct intercept_translate * tl)502 print_fileflags(char *buf, size_t buflen, struct intercept_translate *tl)
503 {
504 unsigned int flags = (intptr_t)tl->trans_addr;
505 char lbuf[64];
506
507 *buf = '\0';
508
509 while (flags) {
510 if (*buf)
511 strlcat(buf, "|", buflen);
512
513 if (flags & UF_NODUMP) {
514 strlcat(buf, "UF_NODUMP", buflen);
515 flags &= ~UF_NODUMP;
516 continue;
517 }
518
519 if (flags & UF_IMMUTABLE) {
520 strlcat(buf, "UF_IMMUTABLE", buflen);
521 flags &= ~UF_IMMUTABLE;
522 continue;
523 }
524
525 if (flags & UF_APPEND) {
526 strlcat(buf, "UF_APPEND", buflen);
527 flags &= ~UF_APPEND;
528 continue;
529 }
530
531 if (flags & UF_OPAQUE) {
532 strlcat(buf, "UF_OPAQUE", buflen);
533 flags &= ~UF_OPAQUE;
534 continue;
535 }
536
537 if (flags & SF_ARCHIVED) {
538 strlcat(buf, "SF_ARCHIVED", buflen);
539 flags &= ~SF_ARCHIVED;
540 continue;
541 }
542
543 if (flags & SF_IMMUTABLE) {
544 strlcat(buf, "SF_IMMUTABLE", buflen);
545 flags &= ~SF_IMMUTABLE;
546 continue;
547 }
548
549 if (flags & SF_APPEND) {
550 strlcat(buf, "SF_APPEND", buflen);
551 flags &= ~SF_APPEND;
552 continue;
553 }
554
555 if (flags) {
556 snprintf(lbuf, sizeof(lbuf), "<unknown:0x%x>", flags);
557 strlcat(buf, lbuf, buflen);
558 flags = 0;
559 continue;
560 }
561 }
562
563 return (0);
564 }
565
566 static int
get_argv(struct intercept_translate * trans,int fd,pid_t pid,void * addr)567 get_argv(struct intercept_translate *trans, int fd, pid_t pid, void *addr)
568 {
569 char *arg;
570 char buf[_POSIX2_LINE_MAX], *p;
571 int i, off = 0;
572 size_t len;
573 extern struct intercept_system intercept;
574
575 i = 0;
576 buf[0] = '\0';
577 while (1) {
578 if (intercept.io(fd, pid, INTERCEPT_READ, (char *)addr + off,
579 (void *)&arg, sizeof(char *)) == -1) {
580 warn("%s: ioctl", __func__);
581 return (-1);
582 }
583 if (arg == NULL)
584 break;
585
586 p = intercept_get_string(fd, pid, arg);
587 if (p == NULL)
588 return (-1);
589
590 if (i > 0)
591 strlcat(buf, " ", sizeof(buf));
592 strlcat(buf, p, sizeof(buf));
593
594 off += sizeof(char *);
595 i++;
596 }
597
598 len = strlen(buf) + 1;
599 trans->trans_data = malloc(len);
600 if (trans->trans_data == NULL)
601 return (-1);
602
603 /* XXX - No argument replacement */
604 trans->trans_size = 0;
605 memcpy(trans->trans_data, buf, len);
606
607 return (0);
608 }
609
610 static int
print_argv(char * buf,size_t buflen,struct intercept_translate * tl)611 print_argv(char *buf, size_t buflen, struct intercept_translate *tl)
612 {
613 strlcpy(buf, (char *)tl->trans_data, buflen);
614
615 return (0);
616 }
617
618 struct intercept_translate ic_trargv = {
619 "argv",
620 get_argv, print_argv,
621 };
622
623 struct intercept_translate ic_oflags = {
624 "oflags",
625 NULL, print_oflags,
626 };
627
628 struct intercept_translate ic_linux_oflags = {
629 "oflags",
630 NULL, linux_print_oflags,
631 };
632
633 struct intercept_translate ic_modeflags = {
634 "mode",
635 NULL, print_modeflags,
636 };
637
638 struct intercept_translate ic_uidt = {
639 "uid",
640 NULL, print_number,
641 };
642
643 struct intercept_translate ic_uname = {
644 "uname",
645 NULL, print_uname,
646 };
647
648 struct intercept_translate ic_gidt = {
649 "gid",
650 NULL, print_number,
651 };
652
653 struct intercept_translate ic_fdt = {
654 "fd",
655 NULL, print_number,
656 };
657
658 struct intercept_translate ic_sockdom = {
659 "sockdom",
660 NULL, print_sockdom,
661 };
662
663 struct intercept_translate ic_socktype = {
664 "socktype",
665 NULL, print_socktype,
666 };
667
668 struct intercept_translate ic_pidname = {
669 "pidname",
670 NULL, print_pidname,
671 };
672
673 struct intercept_translate ic_signame = {
674 "signame",
675 NULL, print_signame,
676 };
677
678 struct intercept_translate ic_fcntlcmd = {
679 "cmd",
680 NULL, print_fcntlcmd,
681 };
682
683 struct intercept_translate ic_memprot = {
684 "prot",
685 NULL, print_memprot,
686 };
687
688 struct intercept_translate ic_linux_memprot = {
689 "prot",
690 get_linux_memprot, print_memprot,
691 };
692
693 struct intercept_translate ic_fileflags = {
694 "flags",
695 NULL, print_fileflags,
696 };
697