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