1 /* $NetBSD: kern_systrace.c,v 1.44.2.4 2006/10/16 20:36:50 ghen Exp $ */
2
3 /*
4 * Copyright 2002, 2003 Niels Provos <provos@citi.umich.edu>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Niels Provos.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: kern_systrace.c,v 1.44.2.4 2006/10/16 20:36:50 ghen Exp $");
35
36 #include "opt_systrace.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/tree.h>
41 #include <sys/malloc.h>
42 #include <sys/syscall.h>
43 #include <sys/vnode.h>
44 #include <sys/errno.h>
45 #include <sys/conf.h>
46 #include <sys/device.h>
47 #include <sys/proc.h>
48 #include <sys/file.h>
49 #include <sys/filedesc.h>
50 #include <sys/filio.h>
51 #include <sys/signalvar.h>
52 #include <sys/lock.h>
53 #include <sys/pool.h>
54 #include <sys/mount.h>
55 #include <sys/poll.h>
56 #include <sys/ptrace.h>
57 #include <sys/namei.h>
58 #include <sys/systrace.h>
59 #include <sys/sa.h>
60 #include <sys/savar.h>
61
62 #include <compat/common/compat_util.h>
63
64 #ifdef __NetBSD__
65 #define SYSTRACE_LOCK(fst, p) lockmgr(&fst->lock, LK_EXCLUSIVE, NULL)
66 #define SYSTRACE_UNLOCK(fst, p) lockmgr(&fst->lock, LK_RELEASE, NULL)
67 #else
68 #define SYSTRACE_LOCK(fst, p) lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p)
69 #define SYSTRACE_UNLOCK(fst, p) lockmgr(&fst->lock, LK_RELEASE, NULL, p)
70 #endif
71 #ifndef M_XDATA
72 MALLOC_DEFINE(M_SYSTR, "systrace", "systrace");
73 #define M_XDATA M_SYSTR
74 #endif
75
76 #ifdef __NetBSD__
77 dev_type_open(systraceopen);
78 #else
79 cdev_decl(systrace);
80 #endif
81
82 #ifdef __NetBSD__
83 int systracef_read(struct file *, off_t *, struct uio *, struct ucred *,
84 int);
85 int systracef_write(struct file *, off_t *, struct uio *, struct ucred *,
86 int);
87 int systracef_poll(struct file *, int, struct proc *);
88 #else
89 int systracef_read(struct file *, off_t *, struct uio *, struct ucred *);
90 int systracef_write(struct file *, off_t *, struct uio *, struct ucred *);
91 int systracef_select(struct file *, int, struct proc *);
92 #endif
93 int systracef_ioctl(struct file *, u_long, void *, struct proc *);
94 int systracef_close(struct file *, struct proc *);
95
96 struct str_policy {
97 TAILQ_ENTRY(str_policy) next;
98
99 int nr;
100
101 const struct emul *emul; /* Is only valid for this emulation */
102
103 int refcount;
104
105 int nsysent;
106 u_char *sysent;
107 };
108
109 #define STR_PROC_ONQUEUE 0x01
110 #define STR_PROC_WAITANSWER 0x02
111 #define STR_PROC_SYSCALLRES 0x04
112 #define STR_PROC_REPORT 0x08 /* Report emulation */
113 #define STR_PROC_NEEDSEQNR 0x10 /* Answer must quote seqnr */
114 #define STR_PROC_SETEUID 0x20 /* Elevate privileges */
115 #define STR_PROC_SETEGID 0x40
116 #define STR_PROC_DIDSETUGID 0x80
117
118 struct str_process {
119 TAILQ_ENTRY(str_process) next;
120
121 struct proc *proc;
122 const struct emul *oldemul;
123 uid_t olduid;
124 gid_t oldgid;
125
126 pid_t pid;
127
128 struct fsystrace *parent;
129 struct str_policy *policy;
130
131 struct systrace_replace *replace;
132 char *fname[SYSTR_MAXFNAME];
133 size_t nfname;
134
135 int flags;
136 short answer;
137 short error;
138 u_int16_t seqnr; /* expected reply sequence number */
139
140 uid_t seteuid;
141 uid_t saveuid;
142 gid_t setegid;
143 gid_t savegid;
144 };
145
146 uid_t systrace_seteuid(struct proc *, uid_t);
147 gid_t systrace_setegid(struct proc *, gid_t);
148 void systrace_lock(void);
149 void systrace_unlock(void);
150
151 /* Needs to be called with fst locked */
152
153 int systrace_attach(struct fsystrace *, pid_t);
154 int systrace_detach(struct str_process *);
155 int systrace_answer(struct str_process *, struct systrace_answer *);
156 int systrace_io(struct str_process *, struct systrace_io *);
157 int systrace_policy(struct fsystrace *, struct systrace_policy *);
158 int systrace_preprepl(struct str_process *, struct systrace_replace *);
159 int systrace_replace(struct str_process *, size_t, register_t []);
160 int systrace_getcwd(struct fsystrace *, struct str_process *);
161 int systrace_fname(struct str_process *, caddr_t, size_t);
162 void systrace_replacefree(struct str_process *);
163
164 int systrace_processready(struct str_process *);
165 struct proc *systrace_find(struct str_process *);
166 struct str_process *systrace_findpid(struct fsystrace *fst, pid_t pid);
167 void systrace_wakeup(struct fsystrace *);
168 void systrace_closepolicy(struct fsystrace *, struct str_policy *);
169 int systrace_insert_process(struct fsystrace *, struct proc *,
170 struct str_process **);
171 struct str_policy *systrace_newpolicy(struct fsystrace *, int);
172 int systrace_msg_child(struct fsystrace *, struct str_process *, pid_t);
173 int systrace_msg_policyfree(struct fsystrace *, struct str_policy *);
174 int systrace_msg_ask(struct fsystrace *, struct str_process *,
175 int, size_t, register_t []);
176 int systrace_msg_result(struct fsystrace *, struct str_process *,
177 int, int, size_t, register_t [], register_t []);
178 int systrace_msg_emul(struct fsystrace *, struct str_process *);
179 int systrace_msg_ugid(struct fsystrace *, struct str_process *);
180 int systrace_make_msg(struct str_process *, int, struct str_message *);
181
182 static const struct fileops systracefops = {
183 systracef_read,
184 systracef_write,
185 systracef_ioctl,
186 fnullop_fcntl,
187 systracef_poll,
188 fbadop_stat,
189 systracef_close,
190 fnullop_kqfilter
191 };
192
193 #ifdef __NetBSD__
194 POOL_INIT(systr_proc_pl, sizeof(struct str_process), 0, 0, 0, "strprocpl",
195 NULL);
196 POOL_INIT(systr_policy_pl, sizeof(struct str_policy), 0, 0, 0, "strpolpl",
197 NULL);
198 POOL_INIT(systr_msgcontainer_pl, sizeof(struct str_msgcontainer), 0, 0, 0,
199 "strmsgpl", NULL);
200 #else
201 struct pool systr_proc_pl;
202 struct pool systr_policy_pl;
203 struct pool systr_msgcontainer_pl;
204 #endif
205
206 int systrace_debug = 0;
207 struct lock systrace_lck;
208
209 #ifdef __NetBSD__
210 const struct cdevsw systrace_cdevsw = {
211 systraceopen, noclose, noread, nowrite, noioctl,
212 nostop, notty, nopoll, nommap, nokqfilter,
213 };
214 #endif
215
216 #define DPRINTF(y) if (systrace_debug) printf y;
217
218 /* ARGSUSED */
219 int
220 systracef_read(struct file *fp, off_t *poff, struct uio *uio,
221 struct ucred *cred
222 #ifdef __NetBSD__
223 , int flags
224 #endif
225 )
226 {
227 struct fsystrace *fst = (struct fsystrace *)fp->f_data;
228 struct str_msgcontainer *cont;
229 int error = 0;
230
231 if (uio->uio_resid != sizeof(struct str_message))
232 return (EINVAL);
233
234 again:
235 systrace_lock();
236 SYSTRACE_LOCK(fst, curlwp);
237 systrace_unlock();
238 if ((cont = TAILQ_FIRST(&fst->messages)) != NULL) {
239 error = uiomove((caddr_t)&cont->msg,
240 sizeof(struct str_message), uio);
241 if (!error) {
242 TAILQ_REMOVE(&fst->messages, cont, next);
243 if (!SYSTR_MSG_NOPROCESS(cont))
244 CLR(cont->strp->flags, STR_PROC_ONQUEUE);
245 pool_put(&systr_msgcontainer_pl, cont);
246
247 }
248 } else if (TAILQ_FIRST(&fst->processes) == NULL) {
249 /* EOF situation */
250 ;
251 } else {
252 if (fp->f_flag & FNONBLOCK)
253 error = EAGAIN;
254 else {
255 SYSTRACE_UNLOCK(fst, curlwp);
256 error = tsleep(fst, PWAIT|PCATCH, "systrrd", 0);
257 if (error)
258 goto out;
259 goto again;
260 }
261
262 }
263
264 SYSTRACE_UNLOCK(fst, curlwp);
265 out:
266 return (error);
267 }
268
269 /* ARGSUSED */
270 int
271 systracef_write(struct file *fp, off_t *poff, struct uio *uio,
272 struct ucred *cred
273 #ifdef __NetBSD__
274 , int flags
275 #endif
276 )
277 {
278 return (EIO);
279 }
280
281 #define POLICY_VALID(x) ((x) == SYSTR_POLICY_PERMIT || \
282 (x) == SYSTR_POLICY_ASK || \
283 (x) == SYSTR_POLICY_NEVER)
284
285 /* ARGSUSED */
286 int
287 systracef_ioctl(struct file *fp, u_long cmd, void *data, struct proc *p)
288 {
289 int ret = 0;
290 struct fsystrace *fst = (struct fsystrace *)fp->f_data;
291 #ifdef __NetBSD__
292 struct cwdinfo *cwdp;
293 #else
294 struct filedesc *fdp;
295 #endif
296 struct str_process *strp = NULL;
297 pid_t pid = 0;
298
299 switch (cmd) {
300 case FIONBIO:
301 case FIOASYNC:
302 return (0);
303
304 case STRIOCDETACH:
305 case STRIOCREPORT:
306 pid = *(pid_t *)data;
307 if (!pid)
308 ret = EINVAL;
309 break;
310 case STRIOCANSWER:
311 pid = ((struct systrace_answer *)data)->stra_pid;
312 if (!pid)
313 ret = EINVAL;
314 break;
315 case STRIOCIO:
316 pid = ((struct systrace_io *)data)->strio_pid;
317 if (!pid)
318 ret = EINVAL;
319 break;
320 case STRIOCGETCWD:
321 pid = *(pid_t *)data;
322 if (!pid)
323 ret = EINVAL;
324 break;
325 case STRIOCATTACH:
326 case STRIOCRESCWD:
327 case STRIOCPOLICY:
328 break;
329 case STRIOCREPLACE:
330 pid = ((struct systrace_replace *)data)->strr_pid;
331 if (!pid)
332 ret = EINVAL;
333 break;
334 default:
335 ret = EINVAL;
336 break;
337 }
338
339 if (ret)
340 return (ret);
341
342 systrace_lock();
343 SYSTRACE_LOCK(fst, curlwp);
344 systrace_unlock();
345 if (pid) {
346 strp = systrace_findpid(fst, pid);
347 if (strp == NULL) {
348 ret = ESRCH;
349 goto unlock;
350 }
351 }
352
353 switch (cmd) {
354 case STRIOCATTACH:
355 pid = *(pid_t *)data;
356 if (!pid)
357 ret = EINVAL;
358 else
359 ret = systrace_attach(fst, pid);
360 DPRINTF(("%s: attach to %u: %d\n", __func__, pid, ret));
361 break;
362 case STRIOCDETACH:
363 ret = systrace_detach(strp);
364 break;
365 case STRIOCREPORT:
366 SET(strp->flags, STR_PROC_REPORT);
367 break;
368 case STRIOCANSWER:
369 ret = systrace_answer(strp, (struct systrace_answer *)data);
370 break;
371 case STRIOCIO:
372 ret = systrace_io(strp, (struct systrace_io *)data);
373 break;
374 case STRIOCPOLICY:
375 ret = systrace_policy(fst, (struct systrace_policy *)data);
376 break;
377 case STRIOCREPLACE:
378 ret = systrace_preprepl(strp, (struct systrace_replace *)data);
379 break;
380 case STRIOCRESCWD:
381 if (!fst->fd_pid) {
382 ret = EINVAL;
383 break;
384 }
385 #ifdef __NetBSD__
386 cwdp = p->p_cwdi;
387
388 /* Release cwd from other process */
389 if (cwdp->cwdi_cdir)
390 vrele(cwdp->cwdi_cdir);
391 if (cwdp->cwdi_rdir)
392 vrele(cwdp->cwdi_rdir);
393 cwdp->cwdi_cdir = fst->fd_cdir;
394 cwdp->cwdi_rdir = fst->fd_rdir;
395 #else
396 fdp = p->p_fd;
397
398 /* Release cwd from other process */
399 if (fdp->fd_cdir)
400 vrele(fdp->fd_cdir);
401 if (fdp->fd_rdir)
402 vrele(fdp->fd_rdir);
403 /* This restores the cwd we had before */
404 fdp->fd_cdir = fst->fd_cdir;
405 fdp->fd_rdir = fst->fd_rdir;
406 #endif
407 /* Note that we are normal again */
408 fst->fd_pid = 0;
409 fst->fd_cdir = fst->fd_rdir = NULL;
410 break;
411 case STRIOCGETCWD:
412 ret = systrace_getcwd(fst, strp);
413 break;
414 default:
415 ret = EINVAL;
416 break;
417 }
418
419 unlock:
420 SYSTRACE_UNLOCK(fst, curlwp);
421
422 return (ret);
423 }
424
425 #ifdef __NetBSD__
426 int
427 systracef_poll(struct file *fp, int events, struct proc *p)
428 {
429 struct fsystrace *fst = (struct fsystrace *)fp->f_data;
430 int revents = 0;
431
432 if ((events & (POLLIN | POLLRDNORM)) == 0)
433 return (revents);
434
435 systrace_lock();
436 SYSTRACE_LOCK(fst, p);
437 systrace_unlock();
438 if (!TAILQ_EMPTY(&fst->messages))
439 revents |= events & (POLLIN | POLLRDNORM);
440 if (revents == 0)
441 selrecord(p, &fst->si);
442 SYSTRACE_UNLOCK(fst, p);
443
444 return (revents);
445 }
446 #else
447 int
448 systracef_select(struct file *fp, int which, struct proc *p)
449 {
450 struct fsystrace *fst = (struct fsystrace *)fp->f_data;
451 int ready = 0;
452
453 if (which != FREAD)
454 return (0);
455
456 systrace_lock();
457 SYSTRACE_LOCK(fst, p);
458 systrace_unlock();
459 ready = TAILQ_FIRST(&fst->messages) != NULL;
460 if (!ready)
461 selrecord(p, &fst->si);
462 SYSTRACE_UNLOCK(fst, p);
463
464 return (ready);
465 }
466 #endif /* __NetBSD__ */
467
468 /* ARGSUSED */
469 int
470 systracef_close(struct file *fp, struct proc *p)
471 {
472 struct fsystrace *fst = (struct fsystrace *)fp->f_data;
473 struct str_process *strp;
474 struct str_msgcontainer *cont;
475 struct str_policy *strpol;
476
477 systrace_lock();
478 SYSTRACE_LOCK(fst, curlwp);
479 systrace_unlock();
480
481 /* Untrace all processes */
482 for (strp = TAILQ_FIRST(&fst->processes); strp;
483 strp = TAILQ_FIRST(&fst->processes)) {
484 struct proc *q = strp->proc;
485
486 systrace_detach(strp);
487 psignal(q, SIGKILL);
488 }
489
490 /* Clean up fork and exit messages */
491 for (cont = TAILQ_FIRST(&fst->messages); cont;
492 cont = TAILQ_FIRST(&fst->messages)) {
493 TAILQ_REMOVE(&fst->messages, cont, next);
494 pool_put(&systr_msgcontainer_pl, cont);
495 }
496
497 /* Clean up all policies */
498 for (strpol = TAILQ_FIRST(&fst->policies); strpol;
499 strpol = TAILQ_FIRST(&fst->policies))
500 systrace_closepolicy(fst, strpol);
501
502 /* Release vnodes */
503 if (fst->fd_cdir)
504 vrele(fst->fd_cdir);
505 if (fst->fd_rdir)
506 vrele(fst->fd_rdir);
507 SYSTRACE_UNLOCK(fst, curlwp);
508
509 FREE(fp->f_data, M_XDATA);
510 fp->f_data = NULL;
511
512 return (0);
513 }
514
515 void
516 systrace_lock(void)
517 {
518 #ifdef __NetBSD__
519 lockmgr(&systrace_lck, LK_EXCLUSIVE, NULL);
520 #else
521 lockmgr(&systrace_lck, LK_EXCLUSIVE, NULL, curlwp);
522 #endif
523 }
524
525 void
526 systrace_unlock(void)
527 {
528 #ifdef __NetBSD__
529 lockmgr(&systrace_lck, LK_RELEASE, NULL);
530 #else
531 lockmgr(&systrace_lck, LK_RELEASE, NULL, curlwp);
532 #endif
533 }
534
535 void
536 systrace_init(void)
537 {
538
539 #ifndef __NetBSD__
540 pool_init(&systr_proc_pl, sizeof(struct str_process), 0, 0, 0,
541 "strprocpl", NULL);
542 pool_init(&systr_policy_pl, sizeof(struct str_policy), 0, 0, 0,
543 "strpolpl", NULL);
544 pool_init(&systr_msgcontainer_pl, sizeof(struct str_msgcontainer),
545 0, 0, 0, "strmsgpl", NULL);
546 #endif
547 lockinit(&systrace_lck, PLOCK, "systrace", 0, 0);
548 }
549
550 int
551 systraceopen(dev_t dev, int flag, int mode, struct proc *p)
552 {
553 struct fsystrace *fst;
554 struct file *fp;
555 int error, fd;
556
557 /* falloc() will use the descriptor for us. */
558 if ((error = falloc(p, &fp, &fd)) != 0)
559 return (error);
560
561 MALLOC(fst, struct fsystrace *, sizeof(*fst), M_XDATA, M_WAITOK);
562
563 memset(fst, 0, sizeof(struct fsystrace));
564 lockinit(&fst->lock, PLOCK, "systrace", 0, 0);
565
566 TAILQ_INIT(&fst->processes);
567 TAILQ_INIT(&fst->messages);
568 TAILQ_INIT(&fst->policies);
569
570 if (suser(p->p_ucred, &p->p_acflag) == 0)
571 fst->issuser = 1;
572 fst->p_ruid = p->p_cred->p_ruid;
573 fst->p_rgid = p->p_cred->p_rgid;
574
575 return fdclone(p, fp, fd, flag, &systracefops, fst);
576 }
577
578 void
579 systrace_wakeup(struct fsystrace *fst)
580 {
581 wakeup((caddr_t)fst);
582 selwakeup(&fst->si);
583 }
584
585 struct proc *
586 systrace_find(struct str_process *strp)
587 {
588 struct proc *proc;
589
590 if ((proc = pfind(strp->pid)) == NULL)
591 return (NULL);
592
593 if (proc != strp->proc)
594 return (NULL);
595
596 if (!ISSET(proc->p_flag, P_SYSTRACE))
597 return (NULL);
598
599 return (proc);
600 }
601
602 void
603 systrace_sys_exit(struct proc *proc)
604 {
605 struct str_process *strp;
606 struct fsystrace *fst;
607
608 systrace_lock();
609 strp = proc->p_systrace;
610 if (strp != NULL) {
611 fst = strp->parent;
612 SYSTRACE_LOCK(fst, curlwp);
613 systrace_unlock();
614
615 /* Insert Exit message */
616 systrace_msg_child(fst, strp, -1);
617
618 systrace_detach(strp);
619 SYSTRACE_UNLOCK(fst, curlwp);
620 } else
621 systrace_unlock();
622 CLR(proc->p_flag, P_SYSTRACE);
623 }
624
625 void
626 systrace_sys_fork(struct proc *oldproc, struct proc *p)
627 {
628 struct str_process *oldstrp, *strp;
629 struct fsystrace *fst;
630
631 systrace_lock();
632 oldstrp = oldproc->p_systrace;
633 if (oldstrp == NULL) {
634 systrace_unlock();
635 return;
636 }
637
638 fst = oldstrp->parent;
639 SYSTRACE_LOCK(fst, curlwp);
640 systrace_unlock();
641
642 if (systrace_insert_process(fst, p, &strp)) {
643 /* We need to kill the child */
644 psignal(p, SIGKILL);
645 goto out;
646 }
647
648 /* Reference policy */
649 if ((strp->policy = oldstrp->policy) != NULL)
650 strp->policy->refcount++;
651
652 /* Insert fork message */
653 systrace_msg_child(fst, oldstrp, p->p_pid);
654 out:
655 SYSTRACE_UNLOCK(fst, curlwp);
656 }
657
658 int
659 systrace_enter(struct proc *p, register_t code, void *v)
660 {
661 const struct sysent *callp;
662 struct str_process *strp;
663 struct str_policy *strpolicy;
664 struct fsystrace *fst;
665 struct pcred *pc;
666 int policy, error = 0, maycontrol = 0, issuser = 0;
667 size_t argsize;
668
669 systrace_lock();
670 strp = p->p_systrace;
671 if (strp == NULL) {
672 systrace_unlock();
673 return (EINVAL);
674 }
675
676 KASSERT(strp->proc == p);
677
678 fst = strp->parent;
679
680 SYSTRACE_LOCK(fst, p);
681 systrace_unlock();
682
683 /*
684 * We can not monitor a SUID process unless we are root,
685 * but we wait until it executes something unprivileged.
686 * A non-root user may only monitor if the real uid and
687 * real gid match the monitored process. Changing the
688 * uid or gid causes P_SUGID to be set.
689 */
690 if (fst->issuser) {
691 maycontrol = 1;
692 issuser = 1;
693 } else if (!(p->p_flag & P_SUGID)) {
694 maycontrol = fst->p_ruid == p->p_cred->p_ruid &&
695 fst->p_rgid == p->p_cred->p_rgid;
696 }
697
698 if (!maycontrol) {
699 policy = SYSTR_POLICY_PERMIT;
700 } else {
701 /* Find out current policy */
702 if ((strpolicy = strp->policy) == NULL)
703 policy = SYSTR_POLICY_ASK;
704 else {
705 if (code >= strpolicy->nsysent)
706 policy = SYSTR_POLICY_NEVER;
707 else
708 policy = strpolicy->sysent[code];
709 }
710 }
711
712 callp = p->p_emul->e_sysent + code;
713
714 /* Fast-path */
715 if (policy != SYSTR_POLICY_ASK) {
716 if (policy != SYSTR_POLICY_PERMIT) {
717 if (policy > 0)
718 error = policy;
719 else
720 error = EPERM;
721 }
722 strp->oldemul = NULL;
723 systrace_replacefree(strp);
724 SYSTRACE_UNLOCK(fst, p);
725 return (error);
726 }
727
728 /* Get the (adjusted) argsize */
729 argsize = callp->sy_argsize;
730 #ifdef _LP64
731 if (p->p_flag & P_32)
732 argsize = argsize << 1;
733 #endif
734
735 /* Puts the current process to sleep, return unlocked */
736 error = systrace_msg_ask(fst, strp, code, argsize, v);
737
738 /* lock has been released in systrace_msg_ask() */
739 fst = NULL;
740 /* We might have detached by now for some reason */
741 if (!error && (strp = p->p_systrace) != NULL) {
742 /* XXX - do I need to lock here? */
743 if (strp->answer == SYSTR_POLICY_NEVER) {
744 error = strp->error;
745 systrace_replacefree(strp);
746 } else {
747 if (ISSET(strp->flags, STR_PROC_SYSCALLRES)) {
748 #ifndef __NetBSD__
749 CLR(strp->flags, STR_PROC_SYSCALLRES);
750 #endif
751 }
752 /* Replace the arguments if necessary */
753 if (strp->replace != NULL) {
754 error = systrace_replace(strp, argsize, v);
755 }
756 }
757 }
758
759 systrace_lock();
760 if ((strp = p->p_systrace) == NULL)
761 goto out;
762
763 if (error) {
764 strp->oldemul = NULL;
765 goto out;
766 }
767
768 pc = p->p_cred;
769 strp->oldemul = p->p_emul;
770 strp->olduid = pc->p_ruid;
771 strp->oldgid = pc->p_rgid;
772
773 /* Elevate privileges as desired */
774 if (issuser) {
775 if (ISSET(strp->flags, STR_PROC_SETEUID)) {
776 strp->saveuid = systrace_seteuid(p, strp->seteuid);
777 SET(strp->flags, STR_PROC_DIDSETUGID);
778 }
779 if (ISSET(strp->flags, STR_PROC_SETEGID)) {
780 strp->savegid = systrace_setegid(p, strp->setegid);
781 SET(strp->flags, STR_PROC_DIDSETUGID);
782 }
783 } else
784 CLR(strp->flags,
785 STR_PROC_SETEUID|STR_PROC_SETEGID|STR_PROC_DIDSETUGID);
786
787 out:
788 systrace_unlock();
789 return (error);
790 }
791
792 void
793 systrace_exit(struct proc *p, register_t code, void *v, register_t retval[],
794 int error)
795 {
796 const struct sysent *callp;
797 struct str_process *strp;
798 struct fsystrace *fst;
799 struct pcred *pc;
800
801 /* Report change in emulation */
802 systrace_lock();
803 strp = p->p_systrace;
804 if (strp == NULL || strp->oldemul == NULL) {
805 systrace_unlock();
806 return;
807 }
808 DPRINTF(("exit syscall %lu, oldemul %p\n", (u_long)code, strp->oldemul));
809
810 /* Return to old privileges */
811 pc = p->p_cred;
812 if (ISSET(strp->flags, STR_PROC_DIDSETUGID)) {
813 if (ISSET(strp->flags, STR_PROC_SETEUID)) {
814 if (pc->pc_ucred->cr_uid == strp->seteuid)
815 systrace_seteuid(p, strp->saveuid);
816 }
817 if (ISSET(strp->flags, STR_PROC_SETEGID)) {
818 if (pc->pc_ucred->cr_gid == strp->setegid)
819 systrace_setegid(p, strp->savegid);
820 }
821 }
822 CLR(strp->flags,
823 STR_PROC_SETEUID|STR_PROC_SETEGID|STR_PROC_DIDSETUGID);
824
825 systrace_replacefree(strp);
826
827 if (p->p_flag & P_SUGID) {
828 if ((fst = strp->parent) == NULL || !fst->issuser) {
829 systrace_unlock();
830 return;
831 }
832 }
833
834 /* See if we should force a report */
835 if (ISSET(strp->flags, STR_PROC_REPORT)) {
836 CLR(strp->flags, STR_PROC_REPORT);
837 strp->oldemul = NULL;
838 }
839
840 if (p->p_emul != strp->oldemul && strp != NULL) {
841 fst = strp->parent;
842 SYSTRACE_LOCK(fst, p);
843 systrace_unlock();
844
845 /* Old policy is without meaning now */
846 if (strp->policy) {
847 systrace_closepolicy(fst, strp->policy);
848 strp->policy = NULL;
849 }
850 systrace_msg_emul(fst, strp);
851 } else
852 systrace_unlock();
853
854 /* Report if effective uid or gid changed */
855 systrace_lock();
856 strp = p->p_systrace;
857 if (strp != NULL && (strp->olduid != p->p_cred->p_ruid ||
858 strp->oldgid != p->p_cred->p_rgid)) {
859
860 fst = strp->parent;
861 SYSTRACE_LOCK(fst, p);
862 systrace_unlock();
863
864 systrace_msg_ugid(fst, strp);
865 } else
866 systrace_unlock();
867
868 /* Report result from system call */
869 systrace_lock();
870 strp = p->p_systrace;
871 if (strp != NULL && ISSET(strp->flags, STR_PROC_SYSCALLRES)) {
872 size_t argsize;
873
874 CLR(strp->flags, STR_PROC_SYSCALLRES);
875 fst = strp->parent;
876 SYSTRACE_LOCK(fst, p);
877 systrace_unlock();
878 DPRINTF(("will ask syscall %lu, strp %p\n", (u_long)code, strp));
879
880 /* Get the (adjusted) argsize */
881 callp = p->p_emul->e_sysent + code;
882 argsize = callp->sy_argsize;
883 #ifdef _LP64
884 if (p->p_flag & P_32)
885 argsize = argsize << 1;
886 #endif
887
888 systrace_msg_result(fst, strp, error, code, argsize, v, retval);
889 } else {
890 DPRINTF(("will not ask syscall %lu, strp %p\n", (u_long)code, strp));
891 systrace_unlock();
892 }
893 }
894
895 uid_t
896 systrace_seteuid(struct proc *p, uid_t euid)
897 {
898 struct pcred *pc = p->p_cred;
899 uid_t oeuid = pc->pc_ucred->cr_uid;
900
901 if (pc->pc_ucred->cr_uid == euid)
902 return (oeuid);
903
904 /*
905 * Copy credentials so other references do not see our changes.
906 */
907 pc->pc_ucred = crcopy(pc->pc_ucred);
908 pc->pc_ucred->cr_uid = euid;
909 p_sugid(p);
910
911 return (oeuid);
912 }
913
914 gid_t
915 systrace_setegid(struct proc *p, gid_t egid)
916 {
917 struct pcred *pc = p->p_cred;
918 gid_t oegid = pc->pc_ucred->cr_gid;
919
920 if (pc->pc_ucred->cr_gid == egid)
921 return (oegid);
922
923 /*
924 * Copy credentials so other references do not see our changes.
925 */
926 pc->pc_ucred = crcopy(pc->pc_ucred);
927 pc->pc_ucred->cr_gid = egid;
928 p_sugid(p);
929
930 return (oegid);
931 }
932
933 /* Called with fst locked */
934
935 int
936 systrace_answer(struct str_process *strp, struct systrace_answer *ans)
937 {
938 int error = 0;
939
940 DPRINTF(("%s: %u: policy %d\n", __func__,
941 ans->stra_pid, ans->stra_policy));
942
943 if (!POLICY_VALID(ans->stra_policy)) {
944 error = EINVAL;
945 goto out;
946 }
947
948 /* Check if answer is in sync with us */
949 if (ans->stra_seqnr != strp->seqnr) {
950 error = ESRCH;
951 goto out;
952 }
953
954 if ((error = systrace_processready(strp)) != 0)
955 goto out;
956
957 strp->answer = ans->stra_policy;
958 strp->error = ans->stra_error;
959 if (!strp->error)
960 strp->error = EPERM;
961 if (ISSET(ans->stra_flags, SYSTR_FLAGS_RESULT))
962 SET(strp->flags, STR_PROC_SYSCALLRES);
963
964 /* See if we should elevate privileges for this system call */
965 if (ISSET(ans->stra_flags, SYSTR_FLAGS_SETEUID)) {
966 SET(strp->flags, STR_PROC_SETEUID);
967 strp->seteuid = ans->stra_seteuid;
968 }
969 if (ISSET(ans->stra_flags, SYSTR_FLAGS_SETEGID)) {
970 SET(strp->flags, STR_PROC_SETEGID);
971 strp->setegid = ans->stra_setegid;
972 }
973
974
975 /* Clearing the flag indicates to the process that it woke up */
976 CLR(strp->flags, STR_PROC_WAITANSWER);
977 wakeup(strp);
978 out:
979
980 return (error);
981 }
982
983 int
984 systrace_policy(struct fsystrace *fst, struct systrace_policy *pol)
985 {
986 struct str_policy *strpol;
987 struct str_process *strp;
988
989 switch(pol->strp_op) {
990 case SYSTR_POLICY_NEW:
991 DPRINTF(("%s: new, ents %d\n", __func__,
992 pol->strp_maxents));
993 if (pol->strp_maxents <= 0 || pol->strp_maxents > 1024)
994 return (EINVAL);
995 strpol = systrace_newpolicy(fst, pol->strp_maxents);
996 if (strpol == NULL)
997 return (ENOBUFS);
998 pol->strp_num = strpol->nr;
999 break;
1000 case SYSTR_POLICY_ASSIGN:
1001 DPRINTF(("%s: %d -> pid %d\n", __func__,
1002 pol->strp_num, pol->strp_pid));
1003
1004 /* Find right policy by number */
1005 TAILQ_FOREACH(strpol, &fst->policies, next)
1006 if (strpol->nr == pol->strp_num)
1007 break;
1008 if (strpol == NULL)
1009 return (EINVAL);
1010
1011 strp = systrace_findpid(fst, pol->strp_pid);
1012 if (strp == NULL)
1013 return (EINVAL);
1014
1015 /* Check that emulation matches */
1016 if (strpol->emul && strpol->emul != strp->proc->p_emul)
1017 return (EINVAL);
1018
1019 if (strp->policy)
1020 systrace_closepolicy(fst, strp->policy);
1021 strp->policy = strpol;
1022 strpol->refcount++;
1023
1024 /* Record emulation for this policy */
1025 if (strpol->emul == NULL)
1026 strpol->emul = strp->proc->p_emul;
1027
1028 break;
1029 case SYSTR_POLICY_MODIFY:
1030 DPRINTF(("%s: %d: code %d -> policy %d\n", __func__,
1031 pol->strp_num, pol->strp_code, pol->strp_policy));
1032 if (!POLICY_VALID(pol->strp_policy))
1033 return (EINVAL);
1034 TAILQ_FOREACH(strpol, &fst->policies, next)
1035 if (strpol->nr == pol->strp_num)
1036 break;
1037 if (strpol == NULL)
1038 return (EINVAL);
1039 if (pol->strp_code < 0 || pol->strp_code >= strpol->nsysent)
1040 return (EINVAL);
1041 strpol->sysent[pol->strp_code] = pol->strp_policy;
1042 break;
1043 default:
1044 return (EINVAL);
1045 }
1046
1047 return (0);
1048 }
1049
1050 int
1051 systrace_processready(struct str_process *strp)
1052 {
1053 if (ISSET(strp->flags, STR_PROC_ONQUEUE))
1054 return (EBUSY);
1055
1056 if (!ISSET(strp->flags, STR_PROC_WAITANSWER))
1057 return (EBUSY);
1058
1059 /* XXX - ignore until systrace knows about lwps. :-(
1060 if (strp->proc->p_stat != LSSLEEP)
1061 return (EBUSY);
1062 */
1063 return (0);
1064 }
1065
1066 int
1067 systrace_getcwd(struct fsystrace *fst, struct str_process *strp)
1068 {
1069 #ifdef __NetBSD__
1070 struct cwdinfo *mycwdp, *cwdp;
1071 #else
1072 struct filedesc *myfdp, *fdp;
1073 #endif
1074 int error;
1075
1076 DPRINTF(("%s: %d\n", __func__, strp->pid));
1077
1078 error = systrace_processready(strp);
1079 if (error)
1080 return (error);
1081
1082 #ifdef __NetBSD__
1083 mycwdp = curproc->p_cwdi;
1084 cwdp = strp->proc->p_cwdi;
1085 if (mycwdp == NULL || cwdp == NULL)
1086 return (EINVAL);
1087
1088 /* Store our current values */
1089 fst->fd_pid = strp->pid;
1090 fst->fd_cdir = mycwdp->cwdi_cdir;
1091 fst->fd_rdir = mycwdp->cwdi_rdir;
1092
1093 if ((mycwdp->cwdi_cdir = cwdp->cwdi_cdir) != NULL)
1094 VREF(mycwdp->cwdi_cdir);
1095 if ((mycwdp->cwdi_rdir = cwdp->cwdi_rdir) != NULL)
1096 VREF(mycwdp->cwdi_rdir);
1097 #else
1098 myfdp = curlwp->p_fd;
1099 fdp = strp->proc->p_fd;
1100 if (myfdp == NULL || fdp == NULL)
1101 return (EINVAL);
1102
1103 /* Store our current values */
1104 fst->fd_pid = strp->pid;
1105 fst->fd_cdir = myfdp->fd_cdir;
1106 fst->fd_rdir = myfdp->fd_rdir;
1107
1108 if ((myfdp->fd_cdir = fdp->fd_cdir) != NULL)
1109 VREF(myfdp->fd_cdir);
1110 if ((myfdp->fd_rdir = fdp->fd_rdir) != NULL)
1111 VREF(myfdp->fd_rdir);
1112 #endif
1113
1114 return (0);
1115 }
1116
1117 int
1118 systrace_io(struct str_process *strp, struct systrace_io *io)
1119 {
1120 struct proc *p = curproc, *t = strp->proc;
1121 struct uio uio;
1122 struct iovec iov;
1123 int error = 0;
1124
1125 DPRINTF(("%s: %u: %p(%lu)\n", __func__,
1126 io->strio_pid, io->strio_offs, (u_long)io->strio_len));
1127
1128 switch (io->strio_op) {
1129 case SYSTR_READ:
1130 uio.uio_rw = UIO_READ;
1131 break;
1132 case SYSTR_WRITE:
1133 uio.uio_rw = UIO_WRITE;
1134 break;
1135 default:
1136 return (EINVAL);
1137 }
1138
1139 error = systrace_processready(strp);
1140 if (error)
1141 goto out;
1142
1143 iov.iov_base = io->strio_addr;
1144 iov.iov_len = io->strio_len;
1145 uio.uio_iov = &iov;
1146 uio.uio_iovcnt = 1;
1147 uio.uio_offset = (off_t)(unsigned long)io->strio_offs;
1148 uio.uio_resid = io->strio_len;
1149 uio.uio_segflg = UIO_USERSPACE;
1150 uio.uio_procp = p;
1151
1152 #ifdef __NetBSD__
1153 error = process_domem(p, t, &uio);
1154 #else
1155 error = procfs_domem(p, t, NULL, &uio);
1156 #endif
1157 io->strio_len -= uio.uio_resid;
1158 out:
1159
1160 return (error);
1161 }
1162
1163 int
1164 systrace_attach(struct fsystrace *fst, pid_t pid)
1165 {
1166 int error = 0;
1167 struct proc *proc, *p = curproc;
1168
1169 if ((proc = pfind(pid)) == NULL) {
1170 error = ESRCH;
1171 goto out;
1172 }
1173
1174 if (ISSET(proc->p_flag, P_INEXEC)) {
1175 error = EAGAIN;
1176 goto out;
1177 }
1178
1179 /*
1180 * You can't attach to a process if:
1181 * (1) it's the process that's doing the attaching,
1182 */
1183 if (proc->p_pid == p->p_pid) {
1184 error = EINVAL;
1185 goto out;
1186 }
1187
1188 /*
1189 * (2) it's a system process
1190 */
1191 if (ISSET(proc->p_flag, P_SYSTEM)) {
1192 error = EPERM;
1193 goto out;
1194 }
1195
1196 /*
1197 * (3) it's being traced already
1198 */
1199 if (ISSET(proc->p_flag, P_SYSTRACE)) {
1200 error = EBUSY;
1201 goto out;
1202 }
1203
1204 /*
1205 * (4) it's not owned by you, or the last exec
1206 * gave us setuid/setgid privs (unless
1207 * you're root), or...
1208 *
1209 * [Note: once P_SUGID gets set in execve(), it stays
1210 * set until the process does another execve(). Hence
1211 * this prevents a setuid process which revokes its
1212 * special privileges using setuid() from being
1213 * traced. This is good security.]
1214 */
1215 if ((proc->p_cred->p_ruid != p->p_cred->p_ruid ||
1216 ISSET(proc->p_flag, P_SUGID)) &&
1217 (error = suser(p->p_ucred, &p->p_acflag)) != 0)
1218 goto out;
1219
1220 /*
1221 * (5) ...it's init, which controls the security level
1222 * of the entire system, and the system was not
1223 * compiled with permanently insecure mode turned
1224 * on.
1225 */
1226 if ((proc->p_pid == 1) && (securelevel > -1)) {
1227 error = EPERM;
1228 goto out;
1229 }
1230
1231 error = systrace_insert_process(fst, proc, NULL);
1232
1233 #if defined(__NetBSD__) && defined(__HAVE_SYSCALL_INTERN)
1234 /*
1235 * Make sure we're using the version of the syscall handler that
1236 * has systrace hooks.
1237 */
1238 if (!error)
1239 (*proc->p_emul->e_syscall_intern)(proc);
1240 #endif
1241 out:
1242 return (error);
1243 }
1244
1245 /* Prepare to replace arguments */
1246
1247 int
1248 systrace_preprepl(struct str_process *strp, struct systrace_replace *repl)
1249 {
1250 size_t len;
1251 int i, ret = 0;
1252
1253 ret = systrace_processready(strp);
1254 if (ret)
1255 return (ret);
1256
1257 systrace_replacefree(strp);
1258
1259 if (repl->strr_nrepl < 0 || repl->strr_nrepl > SYSTR_MAXARGS)
1260 return (EINVAL);
1261
1262 for (i = 0, len = 0; i < repl->strr_nrepl; i++) {
1263 if (repl->strr_argind[i] < 0 ||
1264 repl->strr_argind[i] >= SYSTR_MAXARGS)
1265 return (EINVAL);
1266 if (repl->strr_offlen[i] == 0)
1267 continue;
1268 len += repl->strr_offlen[i];
1269 if (repl->strr_offlen[i] > SYSTR_MAXREPLEN ||
1270 repl->strr_off[i] > SYSTR_MAXREPLEN ||
1271 len > SYSTR_MAXREPLEN)
1272 return (EINVAL);
1273 if (repl->strr_offlen[i] + repl->strr_off[i] > len)
1274 return (EINVAL);
1275 }
1276
1277 /* Make sure that the length adds up */
1278 if (repl->strr_len != len)
1279 return (EINVAL);
1280
1281 /* Check against a maximum length */
1282 if (repl->strr_len > SYSTR_MAXREPLEN)
1283 return (EINVAL);
1284
1285 strp->replace = (struct systrace_replace *)
1286 malloc(sizeof(struct systrace_replace) + len, M_XDATA, M_WAITOK);
1287
1288 memcpy(strp->replace, repl, sizeof(struct systrace_replace));
1289 ret = copyin(repl->strr_base, strp->replace + 1, len);
1290 if (ret) {
1291 free(strp->replace, M_XDATA);
1292 strp->replace = NULL;
1293 return (ret);
1294 }
1295
1296 /* Adjust the offset */
1297 repl = strp->replace;
1298 repl->strr_base = (caddr_t)(repl + 1);
1299
1300 return (0);
1301 }
1302
1303 /*
1304 * Replace the arguments with arguments from the monitoring process.
1305 */
1306
1307 int
1308 systrace_replace(struct str_process *strp, size_t argsize, register_t args[])
1309 {
1310 struct proc *p = strp->proc;
1311 struct systrace_replace *repl = strp->replace;
1312 caddr_t sg, kdata, udata, kbase, ubase;
1313 int i, maxarg, ind, ret = 0;
1314
1315 maxarg = argsize/sizeof(register_t);
1316 #ifdef __NetBSD__
1317 sg = stackgap_init(p, 0);
1318 ubase = stackgap_alloc(p, &sg, repl->strr_len);
1319 #else
1320 sg = stackgap_init(p->p_emul);
1321 ubase = stackgap_alloc(&sg, repl->strr_len);
1322 #endif
1323 if (ubase == NULL) {
1324 ret = EINVAL;
1325 goto out;
1326 }
1327
1328 kbase = repl->strr_base;
1329 for (i = 0; i < maxarg && i < repl->strr_nrepl; i++) {
1330 ind = repl->strr_argind[i];
1331 if (ind < 0 || ind >= maxarg) {
1332 ret = EINVAL;
1333 goto out;
1334 }
1335 if (repl->strr_offlen[i] == 0) {
1336 args[ind] = repl->strr_off[i];
1337 continue;
1338 }
1339 kdata = kbase + repl->strr_off[i];
1340 udata = ubase + repl->strr_off[i];
1341 if (repl->strr_flags[i] & SYSTR_NOLINKS) {
1342 ret = systrace_fname(strp, kdata, repl->strr_offlen[i]);
1343 if (ret != 0)
1344 goto out;
1345 }
1346 if (copyout(kdata, udata, repl->strr_offlen[i])) {
1347 ret = EINVAL;
1348 goto out;
1349 }
1350
1351 /* Replace the argument with the new address */
1352 args[ind] = (register_t)(intptr_t)udata;
1353 }
1354
1355 out:
1356 return (ret);
1357 }
1358
1359 int
1360 systrace_fname(struct str_process *strp, caddr_t kdata, size_t len)
1361 {
1362
1363 if (strp->nfname >= SYSTR_MAXFNAME || len < 2)
1364 return EINVAL;
1365
1366 strp->fname[strp->nfname] = kdata;
1367 strp->fname[strp->nfname][len - 1] = '\0';
1368 strp->nfname++;
1369
1370 return 0;
1371 }
1372
1373 void
1374 systrace_replacefree(struct str_process *strp)
1375 {
1376
1377 if (strp->replace != NULL) {
1378 free(strp->replace, M_XDATA);
1379 strp->replace = NULL;
1380 }
1381 while (strp->nfname > 0) {
1382 strp->nfname--;
1383 strp->fname[strp->nfname] = NULL;
1384 }
1385 }
1386
1387 void
1388 systrace_namei(struct nameidata *ndp)
1389 {
1390 struct str_process *strp;
1391 struct fsystrace *fst;
1392 struct componentname *cnp = &ndp->ni_cnd;
1393 size_t i;
1394
1395 systrace_lock();
1396 strp = cnp->cn_proc->p_systrace;
1397 if (strp != NULL) {
1398 fst = strp->parent;
1399 SYSTRACE_LOCK(fst, curlwp);
1400 systrace_unlock();
1401
1402 for (i = 0; i < strp->nfname; i++) {
1403 if (strcmp(cnp->cn_pnbuf, strp->fname[i]) == 0) {
1404 /* ELOOP if namei() tries to readlink */
1405 ndp->ni_loopcnt = MAXSYMLINKS;
1406 cnp->cn_flags &= ~FOLLOW;
1407 cnp->cn_flags |= NOFOLLOW;
1408 break;
1409 }
1410 }
1411 SYSTRACE_UNLOCK(fst, curlwp);
1412 } else
1413 systrace_unlock();
1414 }
1415
1416 struct str_process *
1417 systrace_findpid(struct fsystrace *fst, pid_t pid)
1418 {
1419 struct str_process *strp;
1420 struct proc *proc = NULL;
1421
1422 TAILQ_FOREACH(strp, &fst->processes, next)
1423 if (strp->pid == pid)
1424 break;
1425
1426 if (strp == NULL)
1427 return (NULL);
1428
1429 proc = systrace_find(strp);
1430
1431 return (proc ? strp : NULL);
1432 }
1433
1434 int
1435 systrace_detach(struct str_process *strp)
1436 {
1437 struct proc *proc;
1438 struct fsystrace *fst = NULL;
1439 int error = 0;
1440
1441 DPRINTF(("%s: Trying to detach from %d\n", __func__, strp->pid));
1442
1443 if ((proc = systrace_find(strp)) != NULL) {
1444 CLR(proc->p_flag, P_SYSTRACE);
1445 proc->p_systrace = NULL;
1446 } else
1447 error = ESRCH;
1448
1449 if (ISSET(strp->flags, STR_PROC_WAITANSWER)) {
1450 CLR(strp->flags, STR_PROC_WAITANSWER);
1451 wakeup(strp);
1452 }
1453
1454 fst = strp->parent;
1455 systrace_wakeup(fst);
1456
1457 TAILQ_REMOVE(&fst->processes, strp, next);
1458 fst->nprocesses--;
1459
1460 if (strp->policy)
1461 systrace_closepolicy(fst, strp->policy);
1462 systrace_replacefree(strp);
1463 pool_put(&systr_proc_pl, strp);
1464
1465 return (error);
1466 }
1467
1468 void
1469 systrace_closepolicy(struct fsystrace *fst, struct str_policy *policy)
1470 {
1471 if (--policy->refcount)
1472 return;
1473
1474 fst->npolicies--;
1475
1476 if (policy->nsysent)
1477 free(policy->sysent, M_XDATA);
1478
1479 TAILQ_REMOVE(&fst->policies, policy, next);
1480
1481 pool_put(&systr_policy_pl, policy);
1482 }
1483
1484
1485 int
1486 systrace_insert_process(struct fsystrace *fst, struct proc *proc,
1487 struct str_process **pstrp)
1488 {
1489 struct str_process *strp;
1490
1491 strp = pool_get(&systr_proc_pl, PR_NOWAIT);
1492 if (strp == NULL)
1493 return (ENOBUFS);
1494
1495 memset((caddr_t)strp, 0, sizeof(struct str_process));
1496 strp->pid = proc->p_pid;
1497 strp->proc = proc;
1498 strp->parent = fst;
1499
1500 TAILQ_INSERT_TAIL(&fst->processes, strp, next);
1501 fst->nprocesses++;
1502
1503 proc->p_systrace = strp;
1504 SET(proc->p_flag, P_SYSTRACE);
1505
1506 /* Pass the new pointer back to the caller */
1507 if (pstrp != NULL)
1508 *pstrp = strp;
1509
1510 return (0);
1511 }
1512
1513 struct str_policy *
1514 systrace_newpolicy(struct fsystrace *fst, int maxents)
1515 {
1516 struct str_policy *pol;
1517 int i;
1518
1519 if (fst->npolicies > SYSTR_MAX_POLICIES && !fst->issuser) {
1520 struct str_policy *tmp;
1521
1522 /* Try to find a policy for freeing */
1523 TAILQ_FOREACH(tmp, &fst->policies, next) {
1524 if (tmp->refcount == 1)
1525 break;
1526 }
1527
1528 if (tmp == NULL)
1529 return (NULL);
1530
1531 /* Notify userland about freed policy */
1532 systrace_msg_policyfree(fst, tmp);
1533 /* Free this policy */
1534 systrace_closepolicy(fst, tmp);
1535 }
1536
1537 pol = pool_get(&systr_policy_pl, PR_NOWAIT);
1538 if (pol == NULL)
1539 return (NULL);
1540
1541 DPRINTF(("%s: allocating %d -> %lu\n", __func__,
1542 maxents, (u_long)maxents * sizeof(int)));
1543
1544 memset((caddr_t)pol, 0, sizeof(struct str_policy));
1545
1546 pol->sysent = (u_char *)malloc(maxents * sizeof(u_char),
1547 M_XDATA, M_WAITOK);
1548 pol->nsysent = maxents;
1549 for (i = 0; i < maxents; i++)
1550 pol->sysent[i] = SYSTR_POLICY_ASK;
1551
1552 fst->npolicies++;
1553 pol->nr = fst->npolicynr++;
1554 pol->refcount = 1;
1555
1556 TAILQ_INSERT_TAIL(&fst->policies, pol, next);
1557
1558 return (pol);
1559 }
1560
1561 int
1562 systrace_msg_ask(struct fsystrace *fst, struct str_process *strp,
1563 int code, size_t argsize, register_t args[])
1564 {
1565 struct str_message msg;
1566 struct str_msg_ask *msg_ask = &msg.msg_data.msg_ask;
1567 int i;
1568
1569 msg_ask->code = code;
1570 msg_ask->argsize = argsize;
1571 for (i = 0; i < (argsize/sizeof(register_t)) && i < SYSTR_MAXARGS; i++)
1572 msg_ask->args[i] = args[i];
1573
1574 return (systrace_make_msg(strp, SYSTR_MSG_ASK, &msg));
1575 }
1576
1577 int
1578 systrace_msg_result(struct fsystrace *fst, struct str_process *strp,
1579 int error, int code, size_t argsize, register_t args[], register_t rval[])
1580 {
1581 struct str_message msg;
1582 struct str_msg_ask *msg_ask = &msg.msg_data.msg_ask;
1583 int i;
1584
1585 msg_ask->code = code;
1586 msg_ask->argsize = argsize;
1587 msg_ask->result = error;
1588 for (i = 0; i < (argsize/sizeof(register_t)) && i < SYSTR_MAXARGS; i++)
1589 msg_ask->args[i] = args[i];
1590
1591 msg_ask->rval[0] = rval[0];
1592 msg_ask->rval[1] = rval[1];
1593
1594 return (systrace_make_msg(strp, SYSTR_MSG_RES, &msg));
1595 }
1596
1597 int
1598 systrace_msg_emul(struct fsystrace *fst, struct str_process *strp)
1599 {
1600 struct str_message msg;
1601 struct str_msg_emul *msg_emul = &msg.msg_data.msg_emul;
1602 struct proc *p = strp->proc;
1603
1604 memcpy(msg_emul->emul, p->p_emul->e_name, SYSTR_EMULEN);
1605
1606 return (systrace_make_msg(strp, SYSTR_MSG_EMUL, &msg));
1607 }
1608
1609 int
1610 systrace_msg_ugid(struct fsystrace *fst, struct str_process *strp)
1611 {
1612 struct str_message msg;
1613 struct str_msg_ugid *msg_ugid = &msg.msg_data.msg_ugid;
1614 struct proc *p = strp->proc;
1615
1616 msg_ugid->uid = p->p_cred->p_ruid;
1617 msg_ugid->gid = p->p_cred->p_rgid;
1618
1619 return (systrace_make_msg(strp, SYSTR_MSG_UGID, &msg));
1620 }
1621
1622 int
1623 systrace_make_msg(struct str_process *strp, int type, struct str_message *tmsg)
1624 {
1625 struct str_msgcontainer *cont;
1626 struct str_message *msg;
1627 struct fsystrace *fst = strp->parent;
1628 int st;
1629
1630 cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK);
1631 memset(cont, 0, sizeof(struct str_msgcontainer));
1632 cont->strp = strp;
1633
1634 msg = &cont->msg;
1635
1636 /* Copy the already filled in fields */
1637 memcpy(&msg->msg_data, &tmsg->msg_data, sizeof(msg->msg_data));
1638
1639 /* Add the extra fields to the message */
1640 msg->msg_seqnr = ++strp->seqnr;
1641 msg->msg_type = type;
1642 msg->msg_pid = strp->pid;
1643 if (strp->policy)
1644 msg->msg_policy = strp->policy->nr;
1645 else
1646 msg->msg_policy = -1;
1647
1648 SET(strp->flags, STR_PROC_WAITANSWER);
1649 if (ISSET(strp->flags, STR_PROC_ONQUEUE))
1650 goto out;
1651
1652 TAILQ_INSERT_TAIL(&fst->messages, cont, next);
1653 SET(strp->flags, STR_PROC_ONQUEUE);
1654
1655 out:
1656 systrace_wakeup(fst);
1657
1658 /* Release the lock - XXX */
1659 SYSTRACE_UNLOCK(fst, strp->proc);
1660
1661 while (1) {
1662 int f;
1663 f = curlwp->l_flag & L_SA;
1664 curlwp->l_flag &= ~L_SA;
1665 st = tsleep(strp, PWAIT, "systrmsg", 0);
1666 curlwp->l_flag |= f;
1667 if (st != 0)
1668 return (ERESTART);
1669 /* If we detach, then everything is permitted */
1670 if ((strp = curproc->p_systrace) == NULL)
1671 return (0);
1672 if (!ISSET(strp->flags, STR_PROC_WAITANSWER))
1673 break;
1674 }
1675
1676 return (0);
1677 }
1678
1679 int
1680 systrace_msg_child(struct fsystrace *fst, struct str_process *strp, pid_t npid)
1681 {
1682 struct str_msgcontainer *cont;
1683 struct str_message *msg;
1684 struct str_msg_child *msg_child;
1685
1686 cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK);
1687 memset(cont, 0, sizeof(struct str_msgcontainer));
1688 cont->strp = strp;
1689
1690 msg = &cont->msg;
1691
1692 DPRINTF(("%s: %p: pid %d -> pid %d\n", __func__,
1693 msg, strp->pid, npid));
1694
1695 msg_child = &msg->msg_data.msg_child;
1696
1697 msg->msg_type = SYSTR_MSG_CHILD;
1698 msg->msg_pid = strp->pid;
1699 if (strp->policy)
1700 msg->msg_policy = strp->policy->nr;
1701 else
1702 msg->msg_policy = -1;
1703 msg_child->new_pid = npid;
1704
1705 TAILQ_INSERT_TAIL(&fst->messages, cont, next);
1706
1707 systrace_wakeup(fst);
1708
1709 return (0);
1710 }
1711
1712 int
1713 systrace_msg_policyfree(struct fsystrace *fst, struct str_policy *strpol)
1714 {
1715 struct str_msgcontainer *cont;
1716 struct str_message *msg;
1717
1718 cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK);
1719 memset(cont, 0, sizeof(struct str_msgcontainer));
1720
1721 msg = &cont->msg;
1722
1723 DPRINTF(("%s: free %d\n", __func__, strpol->nr));
1724
1725 msg->msg_type = SYSTR_MSG_POLICYFREE;
1726 msg->msg_policy = strpol->nr;
1727
1728 TAILQ_INSERT_TAIL(&fst->messages, cont, next);
1729
1730 systrace_wakeup(fst);
1731
1732 return (0);
1733 }
Cache object: acd88e03c4ad9bed2eff9b6aab3124f0
|