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