1 /*        $NetBSD: procfs_vfsops.c,v 1.120 2024/09/14 01:37:42 pgoyette Exp $   */
2 
3 /*
4  * Copyright (c) 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Jan-Simon Pendry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *        @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95
35  */
36 
37 /*
38  * Copyright (c) 1993 Jan-Simon Pendry
39  *
40  * This code is derived from software contributed to Berkeley by
41  * Jan-Simon Pendry.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *        This product includes software developed by the University of
54  *        California, Berkeley and its contributors.
55  * 4. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  *
71  *        @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95
72  */
73 
74 /*
75  * procfs VFS interface
76  */
77 
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: procfs_vfsops.c,v 1.120 2024/09/14 01:37:42 pgoyette Exp $");
80 
81 #if defined(_KERNEL_OPT)
82 #include "opt_compat_netbsd.h"
83 #include "opt_sysv_ipc.h"
84 #include "opt_mqueue.h"
85 #endif
86 
87 #include <sys/param.h>
88 #include <sys/atomic.h>
89 #include <sys/buf.h>
90 #include <sys/dirent.h>
91 #include <sys/file.h>
92 #include <sys/filedesc.h>
93 #include <sys/fstrans.h>
94 #include <sys/kauth.h>
95 #include <sys/kernel.h>
96 #include <sys/module.h>
97 #include <sys/mount.h>
98 #include <sys/proc.h>
99 #include <sys/signalvar.h>
100 #include <sys/sysctl.h>
101 #include <sys/syslog.h>
102 #include <sys/systm.h>
103 #include <sys/time.h>
104 #include <sys/vnode.h>
105 
106 #include <miscfs/genfs/genfs.h>
107 
108 #include <miscfs/procfs/procfs.h>
109 
110 #include <uvm/uvm_extern.h>                       /* for PAGE_SIZE */
111 
112 MODULE(MODULE_CLASS_VFS, procfs, "ptrace_common"
113 #if defined(MQUEUE)
114                                          ",mqueue"
115 #endif
116 #if defined(SYSVSHM) || defined(SYSVSEM) || defined(SYSVMSG)
117                                          ",sysv_ipc"
118 #endif
119 );
120 
121 VFS_PROTOS(procfs);
122 
123 #define PROCFS_HASHSIZE       256
124 #define PROCFS_EXEC_HOOK ((void *)1)
125 #define PROCFS_EXIT_HOOK ((void *)2)
126 
127 static kauth_listener_t procfs_listener;
128 static void *procfs_exechook;
129 static void *procfs_exithook;
130 LIST_HEAD(hashhead, pfsnode);
131 static u_long procfs_hashmask;
132 static struct hashhead *procfs_hashtab;
133 static kmutex_t procfs_hashlock;
134 
135 static struct hashhead *
procfs_hashhead(pid_t pid)136 procfs_hashhead(pid_t pid)
137 {
138 
139           return &procfs_hashtab[pid & procfs_hashmask];
140 }
141 
142 void
procfs_hashrem(struct pfsnode * pfs)143 procfs_hashrem(struct pfsnode *pfs)
144 {
145 
146           mutex_enter(&procfs_hashlock);
147           LIST_REMOVE(pfs, pfs_hash);
148           mutex_exit(&procfs_hashlock);
149 }
150 
151 /*
152  * VFS Operations.
153  *
154  * mount system call
155  */
156 /* ARGSUSED */
157 int
procfs_mount(struct mount * mp,const char * path,void * data,size_t * data_len)158 procfs_mount(
159     struct mount *mp,
160     const char *path,
161     void *data,
162     size_t *data_len)
163 {
164           struct lwp *l = curlwp;
165           struct procfsmount *pmnt;
166           struct procfs_args *args = data;
167           int error;
168 
169           if (args == NULL)
170                     return EINVAL;
171 
172           if (UIO_MX & (UIO_MX-1)) {
173                     log(LOG_ERR, "procfs: invalid directory entry size");
174                     return (EINVAL);
175           }
176 
177           if (mp->mnt_flag & MNT_GETARGS) {
178                     if (*data_len < sizeof *args)
179                               return EINVAL;
180 
181                     pmnt = VFSTOPROC(mp);
182                     if (pmnt == NULL)
183                               return EIO;
184                     args->version = PROCFS_ARGSVERSION;
185                     args->flags = pmnt->pmnt_flags;
186                     *data_len = sizeof *args;
187                     return 0;
188           }
189 
190           if (mp->mnt_flag & MNT_UPDATE)
191                     return (EOPNOTSUPP);
192 
193           if (*data_len >= sizeof *args && args->version != PROCFS_ARGSVERSION)
194                     return EINVAL;
195 
196           pmnt = kmem_zalloc(sizeof(struct procfsmount), KM_SLEEP);
197 
198           mp->mnt_stat.f_namemax = PROCFS_MAXNAMLEN;
199           mp->mnt_flag |= MNT_LOCAL;
200           mp->mnt_data = pmnt;
201           vfs_getnewfsid(mp);
202 
203           error = set_statvfs_info(path, UIO_USERSPACE, "procfs", UIO_SYSSPACE,
204               mp->mnt_op->vfs_name, mp, l);
205           if (*data_len >= sizeof *args)
206                     pmnt->pmnt_flags = args->flags;
207           else
208                     pmnt->pmnt_flags = 0;
209 
210           mp->mnt_iflag |= IMNT_MPSAFE | IMNT_SHRLOOKUP;
211           return error;
212 }
213 
214 /*
215  * unmount system call
216  */
217 int
procfs_unmount(struct mount * mp,int mntflags)218 procfs_unmount(struct mount *mp, int mntflags)
219 {
220           int error;
221           int flags = 0;
222 
223           if (mntflags & MNT_FORCE)
224                     flags |= FORCECLOSE;
225 
226           if ((error = vflush(mp, 0, flags)) != 0)
227                     return (error);
228 
229           kmem_free(mp->mnt_data, sizeof(struct procfsmount));
230           mp->mnt_data = NULL;
231 
232           return 0;
233 }
234 
235 int
procfs_root(struct mount * mp,int lktype,struct vnode ** vpp)236 procfs_root(struct mount *mp, int lktype, struct vnode **vpp)
237 {
238           int error;
239 
240           error = procfs_allocvp(mp, vpp, 0, PFSroot, -1);
241           if (error == 0) {
242                     error = vn_lock(*vpp, lktype);
243                     if (error != 0) {
244                               vrele(*vpp);
245                               *vpp = NULL;
246                     }
247           }
248 
249           return error;
250 }
251 
252 /* ARGSUSED */
253 int
procfs_start(struct mount * mp,int flags)254 procfs_start(struct mount *mp, int flags)
255 {
256 
257           return (0);
258 }
259 
260 /*
261  * Get file system statistics.
262  */
263 int
procfs_statvfs(struct mount * mp,struct statvfs * sbp)264 procfs_statvfs(struct mount *mp, struct statvfs *sbp)
265 {
266 
267           genfs_statvfs(mp, sbp);
268 
269           sbp->f_bsize = PAGE_SIZE;
270           sbp->f_frsize = PAGE_SIZE;
271           sbp->f_iosize = PAGE_SIZE;
272           sbp->f_blocks = 1;
273           sbp->f_files = maxproc;                                               /* approx */
274           sbp->f_ffree = maxproc - atomic_load_relaxed(&nprocs);      /* approx */
275           sbp->f_favail = maxproc - atomic_load_relaxed(&nprocs);     /* approx */
276 
277           return (0);
278 }
279 
280 /*ARGSUSED*/
281 int
procfs_sync(struct mount * mp,int waitfor,kauth_cred_t uc)282 procfs_sync(
283     struct mount *mp,
284     int waitfor,
285     kauth_cred_t uc)
286 {
287 
288           return (0);
289 }
290 
291 /*ARGSUSED*/
292 int
procfs_vget(struct mount * mp,ino_t ino,int lktype,struct vnode ** vpp)293 procfs_vget(struct mount *mp, ino_t ino, int lktype,
294     struct vnode **vpp)
295 {
296           return (EOPNOTSUPP);
297 }
298 
299 int
procfs_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)300 procfs_loadvnode(struct mount *mp, struct vnode *vp,
301     const void *key, size_t key_len, const void **new_key)
302 {
303           int error;
304           struct pfskey pfskey;
305           struct pfsnode *pfs;
306 
307           KASSERT(key_len == sizeof(pfskey));
308           memcpy(&pfskey, key, key_len);
309 
310           pfs = kmem_alloc(sizeof(*pfs), KM_SLEEP);
311           pfs->pfs_pid = pfskey.pk_pid;
312           pfs->pfs_type = pfskey.pk_type;
313           pfs->pfs_fd = pfskey.pk_fd;
314           pfs->pfs_vnode = vp;
315           pfs->pfs_mount = mp;
316           pfs->pfs_flags = 0;
317           pfs->pfs_fileno =
318               PROCFS_FILENO(pfs->pfs_pid, pfs->pfs_type, pfs->pfs_fd);
319           vp->v_tag = VT_PROCFS;
320           vp->v_op = procfs_vnodeop_p;
321           vp->v_data = pfs;
322 
323           switch (pfs->pfs_type) {
324           case PFSroot:       /* /proc = dr-xr-xr-x */
325                     vp->v_vflag |= VV_ROOT;
326                     /*FALLTHROUGH*/
327           case PFSproc:       /* /proc/N = dr-xr-xr-x */
328                     pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
329                     vp->v_type = VDIR;
330                     break;
331 
332           case PFStask:       /* /proc/N/task = dr-xr-xr-x */
333                     if (pfs->pfs_fd == -1) {
334                               pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|
335                                   S_IROTH|S_IXOTH;
336                               vp->v_type = VDIR;
337                               break;
338                     }
339                     /*FALLTHROUGH*/
340           case PFScurproc:    /* /proc/curproc = lr-xr-xr-x */
341           case PFSself:       /* /proc/self    = lr-xr-xr-x */
342           case PFScwd:        /* /proc/N/cwd = lr-xr-xr-x */
343           case PFSchroot:     /* /proc/N/chroot = lr-xr-xr-x */
344           case PFSexe:        /* /proc/N/exe = lr-xr-xr-x */
345                     pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
346                     vp->v_type = VLNK;
347                     break;
348 
349           case PFSfd:
350                     if (pfs->pfs_fd == -1) {      /* /proc/N/fd = dr-x------ */
351                               pfs->pfs_mode = S_IRUSR|S_IXUSR;
352                               vp->v_type = VDIR;
353                     } else {  /* /proc/N/fd/M = [ps-]rw------- */
354                               file_t *fp;
355                               vnode_t *vxp;
356                               struct proc *p;
357 
358                               mutex_enter(&proc_lock);
359                               p = procfs_proc_find(mp, pfs->pfs_pid);
360                               mutex_exit(&proc_lock);
361                               if (p == NULL) {
362                                         error = ENOENT;
363                                         goto bad;
364                               }
365                               KASSERT(rw_read_held(&p->p_reflock));
366                               if ((fp = fd_getfile2(p, pfs->pfs_fd)) == NULL) {
367                                         error = EBADF;
368                                         goto bad;
369                               }
370 
371                               pfs->pfs_mode = S_IRUSR|S_IWUSR;
372                               switch (fp->f_type) {
373                               case DTYPE_VNODE:
374                                         vxp = fp->f_vnode;
375 
376                                         /*
377                                          * We make symlinks for directories
378                                          * to avoid cycles.
379                                          */
380                                         if (vxp->v_type == VDIR ||
381                                             procfs_proc_is_linux_compat())
382                                                   goto symlink;
383                                         vp->v_type = vxp->v_type;
384                                         break;
385                               case DTYPE_PIPE:
386                                         vp->v_type = VFIFO;
387                                         break;
388                               case DTYPE_SOCKET:
389                                         vp->v_type = VSOCK;
390                                         break;
391                               case DTYPE_KQUEUE:
392                               case DTYPE_MISC:
393                               case DTYPE_SEM:
394                               symlink:
395                                         pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|
396                                             S_IXGRP|S_IROTH|S_IXOTH;
397                                         vp->v_type = VLNK;
398                                         break;
399                               default:
400                                         error = EOPNOTSUPP;
401                                         closef(fp);
402                                         goto bad;
403                               }
404                               closef(fp);
405                     }
406                     break;
407 
408           case PFSfile:       /* /proc/N/file = -rw------- */
409           case PFSmem:        /* /proc/N/mem = -rw------- */
410           case PFSregs:       /* /proc/N/regs = -rw------- */
411           case PFSfpregs:     /* /proc/N/fpregs = -rw------- */
412                     pfs->pfs_mode = S_IRUSR|S_IWUSR;
413                     vp->v_type = VREG;
414                     break;
415 
416           case PFSnote:       /* /proc/N/note = --w------ */
417           case PFSnotepg:     /* /proc/N/notepg = --w------ */
418                     pfs->pfs_mode = S_IWUSR;
419                     vp->v_type = VREG;
420                     break;
421 
422           case PFSmap:                  /* /proc/N/map = -r-------- */
423           case PFSmaps:                 /* /proc/N/maps = -r-------- */
424           case PFSauxv:                 /* /proc/N/auxv = -r-------- */
425           case PFSenviron:    /* /proc/N/environ = -r-------- */
426                     pfs->pfs_mode = S_IRUSR;
427                     vp->v_type = VREG;
428                     break;
429 
430           case PFSstatus:               /* /proc/N/status = -r--r--r-- */
431           case PFSstat:                 /* /proc/N/stat = -r--r--r-- */
432           case PFScmdline:    /* /proc/N/cmdline = -r--r--r-- */
433           case PFSemul:                 /* /proc/N/emul = -r--r--r-- */
434           case PFSmeminfo:    /* /proc/meminfo = -r--r--r-- */
435           case PFScpustat:    /* /proc/stat = -r--r--r-- */
436           case PFSdevices:    /* /proc/devices = -r--r--r-- */
437           case PFScpuinfo:    /* /proc/cpuinfo = -r--r--r-- */
438           case PFSuptime:               /* /proc/uptime = -r--r--r-- */
439           case PFSmounts:               /* /proc/mounts = -r--r--r-- */
440           case PFSloadavg:    /* /proc/loadavg = -r--r--r-- */
441           case PFSstatm:                /* /proc/N/statm = -r--r--r-- */
442           case PFSversion:    /* /proc/version = -r--r--r-- */
443           case PFSlimit:                /* /proc/N/limit = -r--r--r-- */
444           case PFSlimits:               /* /proc/N/limits = -r--r--r-- */
445                     pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
446                     vp->v_type = VREG;
447                     break;
448 
449           case PFSsys:        /* /proc/sys = dr-xr-xr-x */
450           case PFSsysfs:      /* /proc/sys/fs = dr-xr-xr-x */
451           case PFSmqueue:     /* /proc/sys/fs/mqueue = dr-xr-xr-x */
452           case PFSsysvipc:/* /proc/sysvipc = dr-xr-xr-x */
453                     if (pfs->pfs_fd == -1) {
454                               pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|
455                                   S_IROTH|S_IXOTH;
456                               vp->v_type = VDIR;
457                               break;
458                     }
459                     /*FALLTHROUGH*/
460           case PFSmq_msg_def: /* /proc/sys/fs/mqueue/msg_default = -r--r--r-- */
461           case PFSmq_msg_max: /* /proc/sys/fs/mqueue/msg_max = -r--r--r-- */
462           case PFSmq_siz_def: /* /proc/sys/fs/mqueue/msgsize_default = -r--r--r-- */
463           case PFSmq_siz_max: /* /proc/sys/fs/mqueue/msgsize_max = -r--r--r-- */
464           case PFSmq_qmax:    /* /proc/sys/fs/mqueue/queues_max = -r--r--r-- */
465           case PFSsysvipc_msg:          /* /proc/sysvipc/msg = -r--r--r-- */
466           case PFSsysvipc_sem:          /* /proc/sysvipc/sem = -r--r--r-- */
467           case PFSsysvipc_shm:          /* /proc/sysvipc/shm = -r--r--r-- */
468                     pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
469                     vp->v_type = VREG;
470                     break;
471 
472 #ifdef __HAVE_PROCFS_MACHDEP
473           PROCFS_MACHDEP_NODETYPE_CASES
474                     procfs_machdep_allocvp(vp);
475                     break;
476 #endif
477 
478           default:
479                     panic("procfs_allocvp");
480           }
481 
482           mutex_enter(&procfs_hashlock);
483           LIST_INSERT_HEAD(procfs_hashhead(pfs->pfs_pid), pfs, pfs_hash);
484           mutex_exit(&procfs_hashlock);
485 
486           uvm_vnp_setsize(vp, 0);
487           *new_key = &pfs->pfs_key;
488 
489           return 0;
490 
491 bad:
492           vp->v_tag =VT_NON;
493           vp->v_type = VNON;
494           vp->v_op = NULL;
495           vp->v_data = NULL;
496           kmem_free(pfs, sizeof(*pfs));
497           return error;
498 }
499 
500 void
procfs_init(void)501 procfs_init(void)
502 {
503 
504 }
505 
506 void
procfs_reinit(void)507 procfs_reinit(void)
508 {
509 
510 }
511 
512 void
procfs_done(void)513 procfs_done(void)
514 {
515 
516 }
517 
518 extern const struct vnodeopv_desc procfs_vnodeop_opv_desc;
519 
520 const struct vnodeopv_desc * const procfs_vnodeopv_descs[] = {
521           &procfs_vnodeop_opv_desc,
522           NULL,
523 };
524 
525 struct vfsops procfs_vfsops = {
526           .vfs_name = MOUNT_PROCFS,
527           .vfs_min_mount_data = sizeof (struct procfs_args),
528           .vfs_mount = procfs_mount,
529           .vfs_start = procfs_start,
530           .vfs_unmount = procfs_unmount,
531           .vfs_root = procfs_root,
532           .vfs_quotactl = (void *)eopnotsupp,
533           .vfs_statvfs = procfs_statvfs,
534           .vfs_sync = procfs_sync,
535           .vfs_vget = procfs_vget,
536           .vfs_loadvnode = procfs_loadvnode,
537           .vfs_fhtovp = (void *)eopnotsupp,
538           .vfs_vptofh = (void *)eopnotsupp,
539           .vfs_init = procfs_init,
540           .vfs_reinit = procfs_reinit,
541           .vfs_done = procfs_done,
542           .vfs_snapshot = (void *)eopnotsupp,
543           .vfs_extattrctl = vfs_stdextattrctl,
544           .vfs_suspendctl = genfs_suspendctl,
545           .vfs_renamelock_enter = genfs_renamelock_enter,
546           .vfs_renamelock_exit = genfs_renamelock_exit,
547           .vfs_fsync = (void *)eopnotsupp,
548           .vfs_opv_descs = procfs_vnodeopv_descs
549 };
550 
551 static void
procfs_exechook_cb(struct proc * p,void * arg)552 procfs_exechook_cb(struct proc *p, void *arg)
553 {
554           struct hashhead *head;
555           struct pfsnode *pfs;
556           struct mount *mp;
557           struct pfskey key;
558           struct vnode *vp;
559           int error;
560 
561           if (arg == PROCFS_EXEC_HOOK && !(p->p_flag & PK_SUGID))
562                     return;
563 
564           head = procfs_hashhead(p->p_pid);
565 
566 again:
567           mutex_enter(&procfs_hashlock);
568           LIST_FOREACH(pfs, head, pfs_hash) {
569                     if (pfs->pfs_pid != p->p_pid)
570                               continue;
571                     mp = pfs->pfs_mount;
572                     key = pfs->pfs_key;
573                     vfs_ref(mp);
574                     mutex_exit(&procfs_hashlock);
575 
576                     error = vcache_get(mp, &key, sizeof(key), &vp);
577                     vfs_rele(mp);
578                     if (error != 0)
579                               goto again;
580                     if (vrecycle(vp))
581                               goto again;
582                     do {
583                               error = vfs_suspend(mp, 0);
584                     } while (error == EINTR || error == ERESTART);
585                     vgone(vp);
586                     if (error == 0)
587                               vfs_resume(mp);
588                     goto again;
589           }
590           mutex_exit(&procfs_hashlock);
591 }
592 
593 static int
procfs_listener_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)594 procfs_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
595     void *arg0, void *arg1, void *arg2, void *arg3)
596 {
597           struct proc *p;
598           struct pfsnode *pfs;
599           int result;
600 
601           result = KAUTH_RESULT_DEFER;
602           p = arg0;
603           pfs = arg1;
604 
605           if (action != KAUTH_PROCESS_PROCFS)
606                     return result;
607 
608           switch (pfs->pfs_type) {
609           case PFSregs:
610           case PFSfpregs:
611           case PFSmem:
612                     if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
613                         ISSET(p->p_flag, PK_SUGID))
614                               break;
615 
616                     /*FALLTHROUGH*/
617           default:
618                     result = KAUTH_RESULT_ALLOW;
619                     break;
620           }
621 
622           return result;
623 }
624 
625 SYSCTL_SETUP(procfs_sysctl_setup, "procfs sysctl")
626 {
627 
628           sysctl_createv(clog, 0, NULL, NULL,
629                            CTLFLAG_PERMANENT,
630                            CTLTYPE_NODE, "procfs",
631                            SYSCTL_DESCR("Process file system"),
632                            NULL, 0, NULL, 0,
633                            CTL_VFS, 12, CTL_EOL);
634           /*
635            * XXX the "12" above could be dynamic, thereby eliminating
636            * one more instance of the "number to vfs" mapping problem,
637            * but "12" is the order as taken from sys/mount.h
638            */
639 }
640 
641 static int
procfs_modcmd(modcmd_t cmd,void * arg)642 procfs_modcmd(modcmd_t cmd, void *arg)
643 {
644           int error;
645 
646           switch (cmd) {
647           case MODULE_CMD_INIT:
648                     error = vfs_attach(&procfs_vfsops);
649                     if (error != 0)
650                               break;
651 
652                     procfs_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
653                         procfs_listener_cb, NULL);
654 
655                     procfs_exechook = exechook_establish(procfs_exechook_cb,
656                         PROCFS_EXEC_HOOK);
657                     procfs_exithook = exithook_establish(procfs_exechook_cb,
658                         PROCFS_EXIT_HOOK);
659 
660                     mutex_init(&procfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
661                     procfs_hashtab = hashinit(PROCFS_HASHSIZE, HASH_LIST, true,
662                         &procfs_hashmask);
663 
664                     break;
665           case MODULE_CMD_FINI:
666                     error = vfs_detach(&procfs_vfsops);
667                     if (error != 0)
668                               break;
669                     kauth_unlisten_scope(procfs_listener);
670                     exechook_disestablish(procfs_exechook);
671                     exithook_disestablish(procfs_exithook);
672                     mutex_destroy(&procfs_hashlock);
673                     hashdone(procfs_hashtab, HASH_LIST, procfs_hashmask);
674                     break;
675           default:
676                     error = ENOTTY;
677                     break;
678           }
679 
680           return (error);
681 }
682