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