1 /*        $NetBSD: procfs_vnops.c,v 1.233 2024/07/01 01:35:53 christos Exp $    */
2 
3 /*-
4  * Copyright (c) 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1993, 1995
34  *        The Regents of the University of California.  All rights reserved.
35  *
36  * This code is derived from software contributed to Berkeley by
37  * Jan-Simon Pendry.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  *
63  *        @(#)procfs_vnops.c  8.18 (Berkeley) 5/21/95
64  */
65 
66 /*
67  * Copyright (c) 1993 Jan-Simon Pendry
68  *
69  * This code is derived from software contributed to Berkeley by
70  * Jan-Simon Pendry.
71  *
72  * Redistribution and use in source and binary forms, with or without
73  * modification, are permitted provided that the following conditions
74  * are met:
75  * 1. Redistributions of source code must retain the above copyright
76  *    notice, this list of conditions and the following disclaimer.
77  * 2. Redistributions in binary form must reproduce the above copyright
78  *    notice, this list of conditions and the following disclaimer in the
79  *    documentation and/or other materials provided with the distribution.
80  * 3. All advertising materials mentioning features or use of this software
81  *    must display the following acknowledgement:
82  *        This product includes software developed by the University of
83  *        California, Berkeley and its contributors.
84  * 4. Neither the name of the University nor the names of its contributors
85  *    may be used to endorse or promote products derived from this software
86  *    without specific prior written permission.
87  *
88  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
89  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
92  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98  * SUCH DAMAGE.
99  *
100  *        @(#)procfs_vnops.c  8.18 (Berkeley) 5/21/95
101  */
102 
103 /*
104  * procfs vnode interface
105  */
106 
107 #include <sys/cdefs.h>
108 __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.233 2024/07/01 01:35:53 christos Exp $");
109 
110 #include <sys/param.h>
111 #include <sys/atomic.h>
112 #include <sys/systm.h>
113 #include <sys/time.h>
114 #include <sys/kernel.h>
115 #include <sys/file.h>
116 #include <sys/filedesc.h>
117 #include <sys/proc.h>
118 #include <sys/vnode.h>
119 #include <sys/namei.h>
120 #include <sys/malloc.h>
121 #include <sys/mount.h>
122 #include <sys/dirent.h>
123 #include <sys/resourcevar.h>
124 #include <sys/stat.h>
125 #include <sys/ptrace.h>
126 #include <sys/kauth.h>
127 #include <sys/exec.h>
128 
129 #include <uvm/uvm_extern.h>   /* for PAGE_SIZE */
130 
131 #include <machine/reg.h>
132 
133 #include <miscfs/genfs/genfs.h>
134 #include <miscfs/procfs/procfs.h>
135 
136 /*
137  * Vnode Operations.
138  *
139  */
140 
141 static int procfs_validfile_linux(struct lwp *, struct mount *);
142 static int procfs_root_readdir_callback(struct proc *, void *);
143 static void procfs_dir(pfstype, struct lwp *, struct proc *, char **, char *,
144     size_t);
145 
146 /*
147  * This is a list of the valid names in the
148  * process-specific sub-directories.  It is
149  * used in procfs_lookup and procfs_readdir
150  */
151 static const struct proc_target {
152           u_char    pt_type;
153           u_char    pt_namlen;
154           const char          *pt_name;
155           pfstype   pt_pfstype;
156           int       (*pt_valid)(struct lwp *, struct mount *);
157 } proc_targets[] = {
158 #define N(s) sizeof(s)-1, s
159           /*          name              type                validp */
160           { DT_DIR, N("."),   PFSproc,  NULL },
161           { DT_DIR, N(".."),  PFSroot,  NULL },
162           { DT_DIR, N("fd"),  PFSfd,              NULL },
163           { DT_DIR, N("task"),          PFStask,  procfs_validfile_linux },
164           { DT_LNK, N("cwd"), PFScwd,             NULL },
165           { DT_REG, N("emul"),          PFSemul,  NULL },
166           { DT_LNK, N("root"),          PFSchroot,          NULL },
167           { DT_REG, N("auxv"),          PFSauxv,  procfs_validauxv },
168           { DT_REG, N("cmdline"), PFScmdline,     NULL },
169           { DT_REG, N("environ"), PFSenviron,     NULL },
170           { DT_LNK, N("exe"), PFSexe,             procfs_validfile },
171           { DT_REG, N("file"),          PFSfile,  procfs_validfile },
172           { DT_REG, N("fpregs"),        PFSfpregs,          procfs_validfpregs },
173           { DT_REG, N("limit"),         PFSlimit, NULL },
174           { DT_REG, N("limits"),        PFSlimits,          procfs_validfile_linux },
175           { DT_REG, N("map"), PFSmap,             procfs_validmap },
176           { DT_REG, N("maps"),          PFSmaps,  procfs_validmap },
177           { DT_REG, N("mem"), PFSmem,             NULL },
178           { DT_REG, N("note"),          PFSnote,  NULL },
179           { DT_REG, N("notepg"),        PFSnotepg,          NULL },
180           { DT_REG, N("regs"),          PFSregs,  procfs_validregs },
181           { DT_REG, N("stat"),          PFSstat,  procfs_validfile_linux },
182           { DT_REG, N("statm"),         PFSstatm, procfs_validfile_linux },
183           { DT_REG, N("status"),        PFSstatus,          NULL },
184 #ifdef __HAVE_PROCFS_MACHDEP
185           PROCFS_MACHDEP_NODETYPE_DEFNS
186 #endif
187 #undef N
188 };
189 static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
190 
191 /*
192  * List of files in the root directory. Note: the validate function will
193  * be called with p == NULL for these ones.
194  */
195 static const struct proc_target proc_root_targets[] = {
196 #define N(s) sizeof(s)-1, s
197           /*          name                  type      validp */
198           { DT_REG, N("meminfo"),     PFSmeminfo,        procfs_validfile_linux },
199           { DT_REG, N("cpuinfo"),     PFScpuinfo,        procfs_validfile_linux },
200           { DT_REG, N("uptime"),      PFSuptime,         procfs_validfile_linux },
201           { DT_REG, N("mounts"),            PFSmounts,             procfs_validfile_linux },
202           { DT_REG, N("devices"),     PFSdevices,        procfs_validfile_linux },
203           { DT_REG, N("stat"),              PFScpustat,        procfs_validfile_linux },
204           { DT_REG, N("loadavg"),           PFSloadavg,        procfs_validfile_linux },
205           { DT_REG, N("version"),     PFSversion,        procfs_validfile_linux },
206           { DT_DIR, N("sys"),         PFSsys,            procfs_validfile_linux },
207           { DT_DIR, N("sysvipc"),     PFSsysvipc,        procfs_validfile_linux },
208 #undef N
209 };
210 static const int nproc_root_targets =
211     sizeof(proc_root_targets) / sizeof(proc_root_targets[0]);
212 
213 /*
214  * List of files in the sys directory
215  */
216 static const struct proc_target proc_sys_targets[] = {
217 #define N(s) sizeof(s)-1, s
218         /*        name              type            validp */
219           { DT_DIR, N("."),   PFSsys,             procfs_validfile_linux },
220           { DT_DIR, N(".."),  PFSroot,  NULL },
221           { DT_REG, N("fs"),  PFSsysfs, procfs_validfile_linux },
222 #undef N
223 };
224 static const int nproc_sys_targets =
225     sizeof(proc_sys_targets) / sizeof(proc_sys_targets[0]);
226 
227 /*
228  * List of files in the sys/fs directory
229  */
230 static const struct proc_target proc_sysfs_targets[] = {
231 #define N(s) sizeof(s)-1, s
232         /*        name              type            validp */
233           { DT_DIR, N("."),   PFSsysfs, procfs_validfile_linux },
234           { DT_DIR, N(".."),  PFSsys,             procfs_validfile_linux },
235           { DT_REG, N("mqueue"),        PFSmqueue,          procfs_validfile_linux },
236 #undef N
237 };
238 static const int nproc_sysfs_targets =
239     sizeof(proc_sysfs_targets) / sizeof(proc_sysfs_targets[0]);
240 
241 /*
242  * List of files in the sys/fs/mqueue directory
243  */
244 static const struct proc_target proc_mqueue_targets[] = {
245 #define N(s) sizeof(s)-1, s
246         /*        name                  type            validp */
247           { DT_DIR, N("."),             PFSmqueue,          procfs_validfile_linux },
248           { DT_DIR, N(".."),            PFSsysfs, procfs_validfile_linux },
249           { DT_REG, N("msg_default"),   PFSmq_msg_def,      procfs_validfile_linux },
250           { DT_REG, N("msg_max"),                 PFSmq_msg_max,      procfs_validfile_linux },
251           { DT_REG, N("msgsize_default"),         PFSmq_siz_def,      procfs_validfile_linux },
252           { DT_REG, N("msgsize_max"),   PFSmq_siz_max,      procfs_validfile_linux },
253           { DT_REG, N("queues_max"),    PFSmq_qmax,         procfs_validfile_linux },
254 #undef N
255 };
256 static const int nproc_mqueue_targets =
257     sizeof(proc_mqueue_targets) / sizeof(proc_mqueue_targets[0]);
258 
259 /*
260  * List of files in the sysvipc directory
261  */
262 static const struct proc_target proc_sysvipc_targets[] = {
263 #define N(s) sizeof(s)-1, s
264         /*        name              type            validp */
265           { DT_DIR, N("."),   PFSsysvipc,         NULL },
266           { DT_DIR, N(".."),  PFSroot,  NULL },
267           { DT_REG, N("msg"), PFSsysvipc_msg, procfs_validfile_linux },
268           { DT_REG, N("sem"), PFSsysvipc_sem, procfs_validfile_linux },
269           { DT_REG, N("shm"), PFSsysvipc_shm, procfs_validfile_linux },
270 #undef N
271 };
272 static const int nproc_sysvipc_targets =
273     sizeof(proc_sysvipc_targets) / sizeof(proc_sysvipc_targets[0]);
274 
275 int       procfs_lookup(void *);
276 int       procfs_open(void *);
277 int       procfs_close(void *);
278 int       procfs_access(void *);
279 int       procfs_getattr(void *);
280 int       procfs_setattr(void *);
281 int       procfs_readdir(void *);
282 int       procfs_readlink(void *);
283 int       procfs_inactive(void *);
284 int       procfs_reclaim(void *);
285 int       procfs_print(void *);
286 int       procfs_pathconf(void *);
287 int       procfs_getpages(void *);
288 
289 static uint8_t fttodt(file_t *);
290 static int atoi(const char *, size_t);
291 
292 /*
293  * procfs vnode operations.
294  */
295 int (**procfs_vnodeop_p)(void *);
296 const struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
297           { &vop_default_desc, vn_default_error },
298           { &vop_parsepath_desc, genfs_parsepath },         /* parsepath */
299           { &vop_lookup_desc, procfs_lookup },              /* lookup */
300           { &vop_create_desc, genfs_eopnotsupp },           /* create */
301           { &vop_mknod_desc, genfs_eopnotsupp },            /* mknod */
302           { &vop_open_desc, procfs_open },                  /* open */
303           { &vop_close_desc, procfs_close },                /* close */
304           { &vop_access_desc, procfs_access },              /* access */
305           { &vop_accessx_desc, genfs_accessx },             /* accessx */
306           { &vop_getattr_desc, procfs_getattr },            /* getattr */
307           { &vop_setattr_desc, procfs_setattr },            /* setattr */
308           { &vop_read_desc, procfs_rw },                              /* read */
309           { &vop_write_desc, procfs_rw },                             /* write */
310           { &vop_fallocate_desc, genfs_eopnotsupp },        /* fallocate */
311           { &vop_fdiscard_desc, genfs_eopnotsupp },         /* fdiscard */
312           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
313           { &vop_ioctl_desc, genfs_enoioctl },              /* ioctl */
314           { &vop_poll_desc, genfs_poll },                             /* poll */
315           { &vop_kqfilter_desc, genfs_kqfilter },           /* kqfilter */
316           { &vop_revoke_desc, genfs_revoke },               /* revoke */
317           { &vop_fsync_desc, genfs_nullop },                /* fsync */
318           { &vop_seek_desc, genfs_nullop },                 /* seek */
319           { &vop_remove_desc, genfs_eopnotsupp },           /* remove */
320           { &vop_link_desc, genfs_erofs_link },             /* link */
321           { &vop_rename_desc, genfs_eopnotsupp },           /* rename */
322           { &vop_mkdir_desc, genfs_eopnotsupp },            /* mkdir */
323           { &vop_rmdir_desc, genfs_eopnotsupp },            /* rmdir */
324           { &vop_symlink_desc, genfs_erofs_symlink },       /* symlink */
325           { &vop_readdir_desc, procfs_readdir },            /* readdir */
326           { &vop_readlink_desc, procfs_readlink },          /* readlink */
327           { &vop_abortop_desc, genfs_abortop },             /* abortop */
328           { &vop_inactive_desc, procfs_inactive },          /* inactive */
329           { &vop_reclaim_desc, procfs_reclaim },            /* reclaim */
330           { &vop_lock_desc, genfs_lock },                             /* lock */
331           { &vop_unlock_desc, genfs_unlock },               /* unlock */
332           { &vop_bmap_desc, genfs_eopnotsupp },             /* bmap */
333           { &vop_strategy_desc, genfs_badop },              /* strategy */
334           { &vop_print_desc, procfs_print },                /* print */
335           { &vop_islocked_desc, genfs_islocked },           /* islocked */
336           { &vop_pathconf_desc, procfs_pathconf },          /* pathconf */
337           { &vop_advlock_desc, genfs_einval },              /* advlock */
338           { &vop_getpages_desc, procfs_getpages },          /* getpages */
339           { &vop_putpages_desc, genfs_null_putpages },      /* putpages */
340           { NULL, NULL }
341 };
342 const struct vnodeopv_desc procfs_vnodeop_opv_desc =
343           { &procfs_vnodeop_p, procfs_vnodeop_entries };
344 /*
345  * set things up for doing i/o on
346  * the pfsnode (vp).  (vp) is locked
347  * on entry, and should be left locked
348  * on exit.
349  *
350  * for procfs we don't need to do anything
351  * in particular for i/o.  all that is done
352  * is to support exclusive open on process
353  * memory images.
354  */
355 int
procfs_open(void * v)356 procfs_open(void *v)
357 {
358           struct vop_open_args /* {
359                     struct vnode *a_vp;
360                     int  a_mode;
361                     kauth_cred_t a_cred;
362           } */ *ap = v;
363           struct vnode *vp = ap->a_vp;
364           struct pfsnode *pfs = VTOPFS(vp);
365           struct lwp *l1;
366           struct proc *p2;
367           int error;
368 
369           if ((error =
370                procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p2, ENOENT)) != 0)
371                     return error;
372 
373           l1 = curlwp;                                      /* tracer */
374 
375 #define   M2K(m)    (((m) & FREAD) && ((m) & FWRITE) ? \
376                      KAUTH_REQ_PROCESS_PROCFS_RW : \
377                      (m) & FWRITE ? KAUTH_REQ_PROCESS_PROCFS_WRITE : \
378                      KAUTH_REQ_PROCESS_PROCFS_READ)
379 
380           mutex_enter(p2->p_lock);
381           error = kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_PROCFS,
382               p2, pfs, KAUTH_ARG(M2K(ap->a_mode)), NULL);
383           mutex_exit(p2->p_lock);
384           if (error) {
385                     procfs_proc_unlock(p2);
386                     return (error);
387           }
388 
389 #undef M2K
390 
391           switch (pfs->pfs_type) {
392           case PFSmem:
393                     if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
394                         ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
395                               error = EBUSY;
396                               break;
397                     }
398 
399                     if (!proc_isunder(p2, l1)) {
400                               error = EPERM;
401                               break;
402                     }
403 
404                     if (ap->a_mode & FWRITE)
405                               pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
406 
407                     break;
408 
409           case PFSregs:
410           case PFSfpregs:
411                     if (!proc_isunder(p2, l1)) {
412                               error = EPERM;
413                               break;
414                     }
415                     break;
416 
417           default:
418                     break;
419           }
420 
421           procfs_proc_unlock(p2);
422           return (error);
423 }
424 
425 /*
426  * close the pfsnode (vp) after doing i/o.
427  * (vp) is not locked on entry or exit.
428  *
429  * nothing to do for procfs other than undo
430  * any exclusive open flag (see _open above).
431  */
432 int
procfs_close(void * v)433 procfs_close(void *v)
434 {
435           struct vop_close_args /* {
436                     struct vnode *a_vp;
437                     int  a_fflag;
438                     kauth_cred_t a_cred;
439           } */ *ap = v;
440           struct pfsnode *pfs = VTOPFS(ap->a_vp);
441 
442           switch (pfs->pfs_type) {
443           case PFSmem:
444                     if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
445                               pfs->pfs_flags &= ~(FWRITE|O_EXCL);
446                     break;
447 
448           default:
449                     break;
450           }
451 
452           return (0);
453 }
454 
455 /*
456  * _inactive is called when the pfsnode
457  * is vrele'd and the reference count goes
458  * to zero.  (vp) will be on the vnode free
459  * list, so to get it back vget() must be
460  * used.
461  *
462  * (vp) is locked on entry, but must be unlocked on exit.
463  */
464 int
procfs_inactive(void * v)465 procfs_inactive(void *v)
466 {
467           struct vop_inactive_v2_args /* {
468                     struct vnode *a_vp;
469                     bool *a_recycle;
470           } */ *ap = v;
471           struct vnode *vp = ap->a_vp;
472           struct pfsnode *pfs = VTOPFS(vp);
473 
474           mutex_enter(&proc_lock);
475           *ap->a_recycle = (procfs_proc_find(vp->v_mount, pfs->pfs_pid) == NULL);
476           mutex_exit(&proc_lock);
477 
478           return (0);
479 }
480 
481 /*
482  * _reclaim is called when getnewvnode()
483  * wants to make use of an entry on the vnode
484  * free list.  at this time the filesystem needs
485  * to free any private data and remove the node
486  * from any private lists.
487  */
488 int
procfs_reclaim(void * v)489 procfs_reclaim(void *v)
490 {
491           struct vop_reclaim_v2_args /* {
492                     struct vnode *a_vp;
493           } */ *ap = v;
494           struct vnode *vp = ap->a_vp;
495           struct pfsnode *pfs = VTOPFS(vp);
496 
497           VOP_UNLOCK(vp);
498 
499           /*
500            * To interlock with procfs_revoke_vnodes().
501            */
502           mutex_enter(vp->v_interlock);
503           vp->v_data = NULL;
504           mutex_exit(vp->v_interlock);
505           procfs_hashrem(pfs);
506           kmem_free(pfs, sizeof(*pfs));
507           return 0;
508 }
509 
510 /*
511  * Return POSIX pathconf information applicable to special devices.
512  */
513 int
procfs_pathconf(void * v)514 procfs_pathconf(void *v)
515 {
516           struct vop_pathconf_args /* {
517                     struct vnode *a_vp;
518                     int a_name;
519                     register_t *a_retval;
520           } */ *ap = v;
521 
522           switch (ap->a_name) {
523           case _PC_LINK_MAX:
524                     *ap->a_retval = LINK_MAX;
525                     return (0);
526           case _PC_MAX_CANON:
527                     *ap->a_retval = MAX_CANON;
528                     return (0);
529           case _PC_MAX_INPUT:
530                     *ap->a_retval = MAX_INPUT;
531                     return (0);
532           case _PC_PIPE_BUF:
533                     *ap->a_retval = PIPE_BUF;
534                     return (0);
535           case _PC_CHOWN_RESTRICTED:
536                     *ap->a_retval = 1;
537                     return (0);
538           case _PC_VDISABLE:
539                     *ap->a_retval = _POSIX_VDISABLE;
540                     return (0);
541           case _PC_SYNC_IO:
542                     *ap->a_retval = 1;
543                     return (0);
544           default:
545                     return genfs_pathconf(ap);
546           }
547           /* NOTREACHED */
548 }
549 
550 /*
551  * _print is used for debugging.
552  * just print a readable description
553  * of (vp).
554  */
555 int
procfs_print(void * v)556 procfs_print(void *v)
557 {
558           struct vop_print_args /* {
559                     struct vnode *a_vp;
560           } */ *ap = v;
561           struct pfsnode *pfs = VTOPFS(ap->a_vp);
562 
563           printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n",
564               pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
565           return 0;
566 }
567 
568 /*
569  * Works out the path to the target process's current
570  * working directory or chroot.  If the caller is in a chroot and
571  * can't "reach" the target's cwd or root (or some other error
572  * occurs), a "/" is returned for the path.
573  */
574 static void
procfs_dir(pfstype t,struct lwp * caller,struct proc * target,char ** bpp,char * path,size_t len)575 procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp,
576     char *path, size_t len)
577 {
578           struct cwdinfo *cwdi;
579           struct vnode *vp, *rvp;
580           char *bp;
581 
582           /*
583            * Lock target cwdi and take a reference to the vnode
584            * we are interested in to prevent it from disappearing
585            * before getcwd_common() below.
586            */
587           rw_enter(&target->p_cwdi->cwdi_lock, RW_READER);
588           switch (t) {
589           case PFScwd:
590                     vp = target->p_cwdi->cwdi_cdir;
591                     break;
592           case PFSchroot:
593                     vp = target->p_cwdi->cwdi_rdir;
594                     break;
595           default:
596                     rw_exit(&target->p_cwdi->cwdi_lock);
597                     return;
598           }
599           if (vp != NULL)
600                     vref(vp);
601           rw_exit(&target->p_cwdi->cwdi_lock);
602 
603           cwdi = caller->l_proc->p_cwdi;
604           rw_enter(&cwdi->cwdi_lock, RW_READER);
605 
606           rvp = cwdi->cwdi_rdir;
607           bp = bpp ? *bpp : NULL;
608 
609           /*
610            * XXX: this horrible kludge avoids locking panics when
611            * attempting to lookup links that point to within procfs
612            */
613           if (vp != NULL && vp->v_tag == VT_PROCFS) {
614                     if (bpp) {
615                               *--bp = '/';
616                               *bpp = bp;
617                     }
618                     vrele(vp);
619                     rw_exit(&cwdi->cwdi_lock);
620                     return;
621           }
622 
623           if (rvp == NULL)
624                     rvp = rootvnode;
625           if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path,
626               len / 2, 0, caller) != 0) {
627                     if (bpp) {
628                               bp = *bpp;
629                               *--bp = '/';
630                     }
631           }
632 
633           if (bpp)
634                     *bpp = bp;
635 
636           if (vp != NULL)
637                     vrele(vp);
638           rw_exit(&cwdi->cwdi_lock);
639 }
640 
641 /*
642  * Invent attributes for pfsnode (vp) and store
643  * them in (vap).
644  * Directories lengths are returned as zero since
645  * any real length would require the genuine size
646  * to be computed, and nothing cares anyway.
647  *
648  * this is relatively minimal for procfs.
649  */
650 int
procfs_getattr(void * v)651 procfs_getattr(void *v)
652 {
653           struct vop_getattr_args /* {
654                     struct vnode *a_vp;
655                     struct vattr *a_vap;
656                     kauth_cred_t a_cred;
657           } */ *ap = v;
658           struct vnode *vp = ap->a_vp;
659           struct pfsnode *pfs = VTOPFS(vp);
660           struct vattr *vap = ap->a_vap;
661           struct proc *procp;
662           char *path, *bp, bf[16];
663           int error;
664 
665           /* first check the process still exists */
666           switch (pfs->pfs_type) {
667           case PFSroot:
668           case PFScurproc:
669           case PFSself:
670                     procp = NULL;
671                     break;
672 
673           default:
674                     error =
675                         procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &procp, ENOENT);
676                     if (error != 0)
677                               return (error);
678                     break;
679           }
680 
681           switch (pfs->pfs_type) {
682           case PFStask:
683                     if (pfs->pfs_fd == -1) {
684                               path = NULL;
685                               break;
686                     }
687                     /*FALLTHROUGH*/
688           case PFScwd:
689           case PFSchroot:
690                     path = malloc(MAXPATHLEN + 4, M_TEMP, M_WAITOK);
691                     if (path == NULL && procp != NULL) {
692                               procfs_proc_unlock(procp);
693                               return (ENOMEM);
694                     }
695                     break;
696 
697           default:
698                     path = NULL;
699                     break;
700           }
701 
702           if (procp != NULL) {
703                     mutex_enter(procp->p_lock);
704                     error = kauth_authorize_process(kauth_cred_get(),
705                         KAUTH_PROCESS_CANSEE, procp,
706                         KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
707                     mutex_exit(procp->p_lock);
708                     if (error != 0) {
709                               procfs_proc_unlock(procp);
710                               if (path != NULL)
711                                         free(path, M_TEMP);
712                               return (ENOENT);
713                     }
714           }
715 
716           error = 0;
717 
718           /* start by zeroing out the attributes */
719           vattr_null(vap);
720 
721           /* next do all the common fields */
722           vap->va_type = ap->a_vp->v_type;
723           vap->va_mode = pfs->pfs_mode;
724           vap->va_fileid = pfs->pfs_fileno;
725           vap->va_flags = 0;
726           vap->va_blocksize = PAGE_SIZE;
727 
728           /*
729            * Make all times be current TOD.
730            *
731            * It would be possible to get the process start
732            * time from the p_stats structure, but there's
733            * no "file creation" time stamp anyway, and the
734            * p_stats structure is not addressable if u. gets
735            * swapped out for that process.
736            */
737           getnanotime(&vap->va_ctime);
738           vap->va_atime = vap->va_mtime = vap->va_ctime;
739           if (procp)
740                     TIMEVAL_TO_TIMESPEC(&procp->p_stats->p_start,
741                         &vap->va_birthtime);
742           else
743                     getnanotime(&vap->va_birthtime);
744 
745           switch (pfs->pfs_type) {
746           case PFSmem:
747           case PFSregs:
748           case PFSfpregs:
749 #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES)
750           PROCFS_MACHDEP_PROTECT_CASES
751 #endif
752                     /*
753                      * If the process has exercised some setuid or setgid
754                      * privilege, then rip away read/write permission so
755                      * that only root can gain access.
756                      */
757                     if (procp->p_flag & PK_SUGID)
758                               vap->va_mode &= ~(S_IRUSR|S_IWUSR);
759                     /* FALLTHROUGH */
760           case PFSstatus:
761           case PFSstat:
762           case PFSnote:
763           case PFSnotepg:
764           case PFScmdline:
765           case PFSenviron:
766           case PFSemul:
767           case PFSstatm:
768 
769           case PFSmap:
770           case PFSmaps:
771           case PFSlimit:
772           case PFSlimits:
773           case PFSauxv:
774                     vap->va_nlink = 1;
775                     vap->va_uid = kauth_cred_geteuid(procp->p_cred);
776                     vap->va_gid = kauth_cred_getegid(procp->p_cred);
777                     break;
778           case PFScwd:
779           case PFSchroot:
780           case PFSmeminfo:
781           case PFSdevices:
782           case PFScpuinfo:
783           case PFSuptime:
784           case PFSmounts:
785           case PFScpustat:
786           case PFSloadavg:
787           case PFSversion:
788           case PFSexe:
789           case PFSself:
790           case PFScurproc:
791           case PFSroot:
792           case PFSmq_msg_def:
793           case PFSmq_msg_max:
794           case PFSmq_siz_def:
795           case PFSmq_siz_max:
796           case PFSmq_qmax:
797           case PFSsysvipc_msg:
798           case PFSsysvipc_sem:
799           case PFSsysvipc_shm:
800                     vap->va_nlink = 1;
801                     vap->va_uid = vap->va_gid = 0;
802                     break;
803 
804           case PFSsysvipc:
805                     vap->va_nlink = 5;
806                     vap->va_uid = vap->va_gid = 0;
807                     break;
808 
809           case PFSsys:        /* proc/sys only contains "fs" */
810           case PFSsysfs:      /* proc/sys/fs only contains "mqueue" */
811                     vap->va_nlink = 3;
812                     vap->va_uid = vap->va_gid = 0;
813                     break;
814 
815           case PFSmqueue:
816                     vap->va_nlink = 7;
817                     vap->va_uid = vap->va_gid = 0;
818                     break;
819 
820           case PFSproc:
821           case PFStask:
822           case PFSfile:
823           case PFSfd:
824                     break;
825 
826           default:
827                     panic("%s: %d/1", __func__, pfs->pfs_type);
828           }
829 
830           /*
831            * now do the object specific fields
832            *
833            * The size could be set from struct reg, but it's hardly
834            * worth the trouble, and it puts some (potentially) machine
835            * dependent data into this machine-independent code.  If it
836            * becomes important then this function should break out into
837            * a per-file stat function in the corresponding .c file.
838            */
839 
840           switch (pfs->pfs_type) {
841           case PFSroot:
842                     vap->va_bytes = vap->va_size = DEV_BSIZE;
843                     break;
844 
845           case PFSself:
846           case PFScurproc:
847                     vap->va_bytes = vap->va_size =
848                         snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
849                     break;
850           case PFStask:
851                     if (pfs->pfs_fd != -1) {
852                               vap->va_nlink = 1;
853                               vap->va_uid = 0;
854                               vap->va_gid = 0;
855                               vap->va_bytes = vap->va_size =
856                                   snprintf(bf, sizeof(bf), "..");
857                               break;
858                     }
859                     /*FALLTHROUGH*/
860           case PFSfd:
861                     if (pfs->pfs_fd != -1) {
862                               file_t *fp;
863 
864                               fp = fd_getfile2(procp, pfs->pfs_fd);
865                               if (fp == NULL) {
866                                         error = EBADF;
867                                         break;
868                               }
869                               vap->va_nlink = 1;
870                               vap->va_uid = kauth_cred_geteuid(fp->f_cred);
871                               vap->va_gid = kauth_cred_getegid(fp->f_cred);
872                               switch (fp->f_type) {
873                               case DTYPE_VNODE:
874                                         vap->va_bytes = vap->va_size =
875                                             fp->f_vnode->v_size;
876                                         break;
877                               default:
878                                         vap->va_bytes = vap->va_size = 0;
879                                         break;
880                               }
881                               closef(fp);
882                               break;
883                     }
884                     /*FALLTHROUGH*/
885           case PFSproc:
886                     vap->va_nlink = 2;
887                     vap->va_uid = kauth_cred_geteuid(procp->p_cred);
888                     vap->va_gid = kauth_cred_getegid(procp->p_cred);
889                     vap->va_bytes = vap->va_size = DEV_BSIZE;
890                     break;
891 
892           case PFSfile:
893                     error = EOPNOTSUPP;
894                     break;
895 
896           case PFSmem:
897                     vap->va_bytes = vap->va_size =
898                               ctob(procp->p_vmspace->vm_tsize +
899                                             procp->p_vmspace->vm_dsize +
900                                             procp->p_vmspace->vm_ssize);
901                     break;
902 
903           case PFSauxv:
904                     vap->va_bytes = vap->va_size = procp->p_execsw->es_arglen;
905                     break;
906 
907 #if defined(PT_GETREGS) || defined(PT_SETREGS)
908           case PFSregs:
909                     vap->va_bytes = vap->va_size = sizeof(struct reg);
910                     break;
911 #endif
912 
913 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
914           case PFSfpregs:
915                     vap->va_bytes = vap->va_size = sizeof(struct fpreg);
916                     break;
917 #endif
918 
919           case PFSstatus:
920           case PFSstat:
921           case PFSnote:
922           case PFSnotepg:
923           case PFScmdline:
924           case PFSenviron:
925           case PFSmeminfo:
926           case PFSdevices:
927           case PFScpuinfo:
928           case PFSuptime:
929           case PFSmounts:
930           case PFScpustat:
931           case PFSloadavg:
932           case PFSstatm:
933           case PFSversion:
934           case PFSsys:
935           case PFSsysfs:
936           case PFSmqueue:
937           case PFSmq_msg_def:
938           case PFSmq_msg_max:
939           case PFSmq_siz_def:
940           case PFSmq_siz_max:
941           case PFSmq_qmax:
942           case PFSsysvipc:
943           case PFSsysvipc_msg:
944           case PFSsysvipc_sem:
945           case PFSsysvipc_shm:
946                     vap->va_bytes = vap->va_size = 0;
947                     break;
948           case PFSlimit:
949           case PFSlimits:
950           case PFSmap:
951           case PFSmaps:
952                     /*
953                      * Advise a larger blocksize for the map files, so that
954                      * they may be read in one pass.
955                      */
956                     vap->va_blocksize = 4 * PAGE_SIZE;
957                     vap->va_bytes = vap->va_size = 0;
958                     break;
959 
960           case PFScwd:
961           case PFSchroot:
962                     bp = path + MAXPATHLEN;
963                     *--bp = '\0';
964                     procfs_dir(pfs->pfs_type, curlwp, procp, &bp, path,
965                          MAXPATHLEN);
966                     vap->va_bytes = vap->va_size = strlen(bp);
967                     break;
968 
969           case PFSexe:
970                     vap->va_bytes = vap->va_size = strlen(procp->p_path);
971                     break;
972 
973           case PFSemul:
974                     vap->va_bytes = vap->va_size = strlen(procp->p_emul->e_name);
975                     break;
976 
977 #ifdef __HAVE_PROCFS_MACHDEP
978           PROCFS_MACHDEP_NODETYPE_CASES
979                     error = procfs_machdep_getattr(ap->a_vp, vap, procp);
980                     break;
981 #endif
982 
983           default:
984                     panic("%s: %d/2", __func__, pfs->pfs_type);
985           }
986 
987           if (procp != NULL)
988                     procfs_proc_unlock(procp);
989           if (path != NULL)
990                     free(path, M_TEMP);
991 
992           return (error);
993 }
994 
995 /*ARGSUSED*/
996 int
procfs_setattr(void * v)997 procfs_setattr(void *v)
998 {
999           /*
1000            * just fake out attribute setting
1001            * it's not good to generate an error
1002            * return, otherwise things like creat()
1003            * will fail when they try to set the
1004            * file length to 0.  worse, this means
1005            * that echo $note > /proc/$pid/note will fail.
1006            */
1007 
1008           return (0);
1009 }
1010 
1011 /*
1012  * implement access checking.
1013  *
1014  * actually, the check for super-user is slightly
1015  * broken since it will allow read access to write-only
1016  * objects.  this doesn't cause any particular trouble
1017  * but does mean that the i/o entry points need to check
1018  * that the operation really does make sense.
1019  */
1020 int
procfs_access(void * v)1021 procfs_access(void *v)
1022 {
1023           struct vop_access_args /* {
1024                     struct vnode *a_vp;
1025                     accmode_t a_accmode;
1026                     kauth_cred_t a_cred;
1027           } */ *ap = v;
1028           struct vattr va;
1029           int error;
1030 
1031           if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0)
1032                     return (error);
1033 
1034           return kauth_authorize_vnode(ap->a_cred,
1035               KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode),
1036               ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred,
1037               va.va_uid, va.va_gid, va.va_mode, NULL, ap->a_accmode));
1038 }
1039 
1040 /*
1041  * lookup.  this is incredibly complicated in the
1042  * general case, however for most pseudo-filesystems
1043  * very little needs to be done.
1044  *
1045  * Locking isn't hard here, just poorly documented.
1046  *
1047  * If we're looking up ".", just vref the parent & return it.
1048  *
1049  * If we're looking up "..", unlock the parent, and lock "..". If everything
1050  * went ok, and we're on the last component and the caller requested the
1051  * parent locked, try to re-lock the parent. We do this to prevent lock
1052  * races.
1053  *
1054  * For anything else, get the needed node. Then unlock the parent if not
1055  * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
1056  * parent in the .. case).
1057  *
1058  * We try to exit with the parent locked in error cases.
1059  */
1060 int
procfs_lookup(void * v)1061 procfs_lookup(void *v)
1062 {
1063           struct vop_lookup_v2_args /* {
1064                     struct vnode * a_dvp;
1065                     struct vnode ** a_vpp;
1066                     struct componentname * a_cnp;
1067           } */ *ap = v;
1068           struct componentname *cnp = ap->a_cnp;
1069           struct vnode **vpp = ap->a_vpp;
1070           struct vnode *dvp = ap->a_dvp;
1071           const char *pname = cnp->cn_nameptr;
1072           const struct proc_target *pt = NULL;
1073           struct vnode *fvp;
1074           pid_t pid, vnpid;
1075           struct pfsnode *pfs;
1076           struct proc *p = NULL;
1077           struct lwp *plwp;
1078           int i, error;
1079           pfstype type;
1080 
1081           *vpp = NULL;
1082 
1083           if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred)) != 0)
1084                     return (error);
1085 
1086           if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
1087                     return (EROFS);
1088 
1089           if (cnp->cn_namelen == 1 && *pname == '.') {
1090                     *vpp = dvp;
1091                     vref(dvp);
1092                     return (0);
1093           }
1094 
1095           pfs = VTOPFS(dvp);
1096           switch (pfs->pfs_type) {
1097           case PFSroot:
1098                     /*
1099                      * Shouldn't get here with .. in the root node.
1100                      */
1101                     if (cnp->cn_flags & ISDOTDOT)
1102                               return (EIO);
1103 
1104                     for (i = 0; i < nproc_root_targets; i++) {
1105                               pt = &proc_root_targets[i];
1106                               /*
1107                                * check for node match.  proc is always NULL here,
1108                                * so call pt_valid with constant NULL lwp.
1109                                */
1110                               if (cnp->cn_namelen == pt->pt_namlen &&
1111                                   memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1112                                   (pt->pt_valid == NULL ||
1113                                    (*pt->pt_valid)(NULL, dvp->v_mount)))
1114                                         break;
1115                     }
1116 
1117                     if (i != nproc_root_targets) {
1118                               error = procfs_allocvp(dvp->v_mount, vpp, 0,
1119                                   pt->pt_pfstype, -1);
1120                               return (error);
1121                     }
1122 
1123                     if (CNEQ(cnp, "curproc", 7)) {
1124                               pid = curproc->p_pid;
1125                               vnpid = 0;
1126                               type = PFScurproc;
1127                     } else if (CNEQ(cnp, "self", 4)) {
1128                               pid = curproc->p_pid;
1129                               vnpid = 0;
1130                               type = PFSself;
1131                     } else {
1132                               pid = (pid_t)atoi(pname, cnp->cn_namelen);
1133                               vnpid = pid;
1134                               type = PFSproc;
1135                     }
1136 
1137                     if (procfs_proc_lock(dvp->v_mount, pid, &p, ESRCH) != 0)
1138                               break;
1139                     error = procfs_allocvp(dvp->v_mount, vpp, vnpid, type, -1);
1140                     procfs_proc_unlock(p);
1141                     return (error);
1142 
1143           case PFSproc:
1144                     if (cnp->cn_flags & ISDOTDOT) {
1145                               error = procfs_allocvp(dvp->v_mount, vpp, 0, PFSroot,
1146                                   -1);
1147                               return (error);
1148                     }
1149 
1150                     if (procfs_proc_lock(dvp->v_mount, pfs->pfs_pid, &p,
1151                                              ESRCH) != 0)
1152                               break;
1153 
1154                     mutex_enter(p->p_lock);
1155                     LIST_FOREACH(plwp, &p->p_lwps, l_sibling) {
1156                               if (plwp->l_stat != LSZOMB)
1157                                         break;
1158                     }
1159                     /* Process is exiting if no-LWPS or all LWPs are LSZOMB */
1160                     if (plwp == NULL) {
1161                               mutex_exit(p->p_lock);
1162                               procfs_proc_unlock(p);
1163                               return ESRCH;
1164                     }
1165 
1166                     lwp_addref(plwp);
1167                     mutex_exit(p->p_lock);
1168 
1169                     for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
1170                               int found;
1171 
1172                               found = cnp->cn_namelen == pt->pt_namlen &&
1173                                   memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1174                                   (pt->pt_valid == NULL
1175                                     || (*pt->pt_valid)(plwp, dvp->v_mount));
1176                               if (found)
1177                                         break;
1178                     }
1179                     lwp_delref(plwp);
1180 
1181                     if (i == nproc_targets) {
1182                               procfs_proc_unlock(p);
1183                               break;
1184                     }
1185                     if (pt->pt_pfstype == PFSfile) {
1186                               fvp = p->p_textvp;
1187                               /* We already checked that it exists. */
1188                               vref(fvp);
1189                               procfs_proc_unlock(p);
1190                               *vpp = fvp;
1191                               return (0);
1192                     }
1193 
1194                     error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1195                         pt->pt_pfstype, -1);
1196                     procfs_proc_unlock(p);
1197                     return (error);
1198 
1199           case PFSfd: {
1200                     int fd;
1201                     file_t *fp;
1202 
1203                     if ((error = procfs_proc_lock(dvp->v_mount, pfs->pfs_pid, &p,
1204                                                         ENOENT)) != 0)
1205                               return error;
1206 
1207                     if (cnp->cn_flags & ISDOTDOT) {
1208                               error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1209                                   PFSproc, -1);
1210                               procfs_proc_unlock(p);
1211                               return (error);
1212                     }
1213                     fd = atoi(pname, cnp->cn_namelen);
1214 
1215                     fp = fd_getfile2(p, fd);
1216                     if (fp == NULL) {
1217                               procfs_proc_unlock(p);
1218                               return ENOENT;
1219                     }
1220                     fvp = fp->f_vnode;
1221 
1222                     /* Don't show directories */
1223                     if (fp->f_type == DTYPE_VNODE && fvp->v_type != VDIR &&
1224                         !procfs_proc_is_linux_compat()) {
1225                               vref(fvp);
1226                               closef(fp);
1227                               procfs_proc_unlock(p);
1228                               *vpp = fvp;
1229                               return 0;
1230                     }
1231 
1232                     closef(fp);
1233                     error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1234                         PFSfd, fd);
1235                     procfs_proc_unlock(p);
1236                     return error;
1237           }
1238           case PFStask: {
1239                     int xpid;
1240 
1241                     if ((error = procfs_proc_lock(dvp->v_mount, pfs->pfs_pid, &p,
1242                                                         ENOENT)) != 0)
1243                               return error;
1244 
1245                     if (cnp->cn_flags & ISDOTDOT) {
1246                               error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1247                                   PFSproc, -1);
1248                               procfs_proc_unlock(p);
1249                               return (error);
1250                     }
1251                     xpid = atoi(pname, cnp->cn_namelen);
1252 
1253                     if (xpid != pfs->pfs_pid) {
1254                               procfs_proc_unlock(p);
1255                               return ENOENT;
1256                     }
1257                     error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1258                         PFStask, 0);
1259                     procfs_proc_unlock(p);
1260                     return error;
1261           }
1262           case PFSsys:
1263           case PFSsysfs:
1264           case PFSmqueue:
1265           case PFSsysvipc: {
1266                     const struct proc_target *targets;
1267                     int ntargets;
1268                     pfstype parent;
1269 
1270                     switch (pfs->pfs_type) {
1271                     case PFSsys:
1272                               targets = proc_sys_targets;
1273                               ntargets = nproc_sys_targets;
1274                               parent = PFSroot;
1275                               break;
1276                     case PFSsysfs:
1277                               targets = proc_sysfs_targets;
1278                               ntargets = nproc_sysfs_targets;
1279                               parent = PFSsys;
1280                               break;
1281                     case PFSmqueue:
1282                               targets = proc_mqueue_targets;
1283                               ntargets = nproc_mqueue_targets;
1284                               parent = PFSsysfs;
1285                               break;
1286                     case PFSsysvipc:
1287                               targets = proc_sysvipc_targets;
1288                               ntargets = nproc_sysvipc_targets;
1289                               parent = PFSroot;
1290                               break;
1291                     default:
1292                               return (EINVAL);
1293                     }
1294 
1295                     if (cnp->cn_flags & ISDOTDOT) {
1296                               error = procfs_allocvp(dvp->v_mount, vpp, 0, parent,
1297                                   -1);
1298                               return (error);
1299                     }
1300 
1301                     for (i = 0; i < ntargets; i++) {
1302                               pt = &targets[i];
1303                               /*
1304                                * check for node match.  proc is always NULL here,
1305                                * so call pt_valid with constant NULL lwp.
1306                                */
1307                               if (cnp->cn_namelen == pt->pt_namlen &&
1308                                   memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1309                                   (pt->pt_valid == NULL ||
1310                                    (*pt->pt_valid)(NULL, dvp->v_mount)))
1311                                         break;
1312                     }
1313 
1314                     if (i != ntargets) {
1315                               error = procfs_allocvp(dvp->v_mount, vpp, 0,
1316                                   pt->pt_pfstype, -1);
1317                               return (error);
1318                     }
1319 
1320                     return (ENOENT);
1321           }
1322 
1323           default:
1324                     return (ENOTDIR);
1325           }
1326 
1327           return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
1328 }
1329 
1330 int
procfs_validfile(struct lwp * l,struct mount * mp)1331 procfs_validfile(struct lwp *l, struct mount *mp)
1332 {
1333           return l != NULL && l->l_proc != NULL && l->l_proc->p_textvp != NULL;
1334 }
1335 
1336 static int
procfs_validfile_linux(struct lwp * l,struct mount * mp)1337 procfs_validfile_linux(struct lwp *l, struct mount *mp)
1338 {
1339           return procfs_use_linux_compat(mp) &&
1340               (l == NULL || l->l_proc == NULL || procfs_validfile(l, mp));
1341 }
1342 
1343 struct procfs_root_readdir_ctx {
1344           struct uio *uiop;
1345           off_t *cookies;
1346           int ncookies;
1347           off_t off;
1348           off_t startoff;
1349           int error;
1350 };
1351 
1352 static int
procfs_root_readdir_callback(struct proc * p,void * arg)1353 procfs_root_readdir_callback(struct proc *p, void *arg)
1354 {
1355           struct procfs_root_readdir_ctx *ctxp = arg;
1356           struct dirent d;
1357           struct uio *uiop;
1358           int error;
1359 
1360           uiop = ctxp->uiop;
1361           if (uiop->uio_resid < UIO_MX)
1362                     return -1; /* no space */
1363 
1364           if (kauth_authorize_process(kauth_cred_get(),
1365               KAUTH_PROCESS_CANSEE, p,
1366               KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL) != 0)
1367                     return 0;
1368 
1369           if (ctxp->off < ctxp->startoff) {
1370                     ctxp->off++;
1371                     return 0;
1372           }
1373 
1374           memset(&d, 0, UIO_MX);
1375           d.d_reclen = UIO_MX;
1376           d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1);
1377           d.d_namlen = snprintf(d.d_name,
1378               UIO_MX - offsetof(struct dirent, d_name), "%ld", (long)p->p_pid);
1379           d.d_type = DT_DIR;
1380 
1381           mutex_exit(&proc_lock);
1382           error = uiomove(&d, UIO_MX, uiop);
1383           mutex_enter(&proc_lock);
1384           if (error) {
1385                     ctxp->error = error;
1386                     return -1;
1387           }
1388 
1389           ctxp->ncookies++;
1390           if (ctxp->cookies)
1391                     *(ctxp->cookies)++ = ctxp->off + 1;
1392           ctxp->off++;
1393 
1394           return 0;
1395 }
1396 
1397 /*
1398  * readdir returns directory entries from pfsnode (vp).
1399  *
1400  * the strategy here with procfs is to generate a single
1401  * directory entry at a time (struct dirent) and then
1402  * copy that out to userland using uiomove.  a more efficient
1403  * though more complex implementation, would try to minimize
1404  * the number of calls to uiomove().  for procfs, this is
1405  * hardly worth the added code complexity.
1406  *
1407  * this should just be done through read()
1408  */
1409 int
procfs_readdir(void * v)1410 procfs_readdir(void *v)
1411 {
1412           struct vop_readdir_args /* {
1413                     struct vnode *a_vp;
1414                     struct uio *a_uio;
1415                     kauth_cred_t a_cred;
1416                     int *a_eofflag;
1417                     off_t **a_cookies;
1418                     int *a_ncookies;
1419           } */ *ap = v;
1420           struct uio *uio = ap->a_uio;
1421           struct dirent d;
1422           struct pfsnode *pfs;
1423           off_t i;
1424           int error;
1425           off_t *cookies = NULL;
1426           int ncookies;
1427           struct vnode *vp;
1428           const struct proc_target *pt;
1429           struct procfs_root_readdir_ctx ctx;
1430           struct proc *p = NULL;
1431           struct lwp *l;
1432           int nfd;
1433           int nc = 0;
1434 
1435           vp = ap->a_vp;
1436           pfs = VTOPFS(vp);
1437 
1438           if (uio->uio_resid < UIO_MX)
1439                     return (EINVAL);
1440           if (uio->uio_offset < 0)
1441                     return (EINVAL);
1442 
1443           error = 0;
1444           i = uio->uio_offset;
1445           memset(&d, 0, UIO_MX);
1446           d.d_reclen = UIO_MX;
1447           ncookies = uio->uio_resid / UIO_MX;
1448 
1449           switch (pfs->pfs_type) {
1450           /*
1451            * this is for the process-specific sub-directories.
1452            * all that is needed to is copy out all the entries
1453            * from the procent[] table (top of this file).
1454            */
1455           case PFSproc: {
1456 
1457                     if (i >= nproc_targets)
1458                               return 0;
1459 
1460                     if (procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, ESRCH) != 0)
1461                               break;
1462 
1463                     if (ap->a_ncookies) {
1464                               ncookies = uimin(ncookies, (nproc_targets - i));
1465                               cookies = malloc(ncookies * sizeof (off_t),
1466                                   M_TEMP, M_WAITOK);
1467                               *ap->a_cookies = cookies;
1468                     }
1469 
1470                     for (pt = &proc_targets[i];
1471                          uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
1472                               if (pt->pt_valid) {
1473                                         /* XXXSMP LWP can disappear */
1474                                         mutex_enter(p->p_lock);
1475                                         l = LIST_FIRST(&p->p_lwps);
1476                                         KASSERT(l != NULL);
1477                                         mutex_exit(p->p_lock);
1478                                         if ((*pt->pt_valid)(l, vp->v_mount) == 0)
1479                                                   continue;
1480                               }
1481 
1482                               d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1483                                   pt->pt_pfstype, -1);
1484                               d.d_namlen = pt->pt_namlen;
1485                               memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1486                               d.d_type = pt->pt_type;
1487 
1488                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1489                                         break;
1490                               if (cookies)
1491                                         *cookies++ = i + 1;
1492                     }
1493 
1494                     procfs_proc_unlock(p);
1495                     break;
1496           }
1497           case PFSfd: {
1498                     file_t *fp;
1499                     int lim;
1500 
1501                     if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p,
1502                                                         ESRCH)) != 0)
1503                               return error;
1504 
1505                     /* XXX Should this be by file as well? */
1506                     if (kauth_authorize_process(kauth_cred_get(),
1507                         KAUTH_PROCESS_CANSEE, p,
1508                         KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_OPENFILES), NULL,
1509                         NULL) != 0) {
1510                               procfs_proc_unlock(p);
1511                               return ESRCH;
1512                     }
1513 
1514                     nfd = atomic_load_consume(&p->p_fd->fd_dt)->dt_nfiles;
1515 
1516                     lim = uimin((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
1517                     if (i >= lim) {
1518                               procfs_proc_unlock(p);
1519                               return 0;
1520                     }
1521 
1522                     if (ap->a_ncookies) {
1523                               ncookies = uimin(ncookies, (nfd + 2 - i));
1524                               cookies = malloc(ncookies * sizeof (off_t),
1525                                   M_TEMP, M_WAITOK);
1526                               *ap->a_cookies = cookies;
1527                     }
1528 
1529                     for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
1530                               pt = &proc_targets[i];
1531                               d.d_namlen = pt->pt_namlen;
1532                               d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1533                                   pt->pt_pfstype, -1);
1534                               (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1535                               d.d_type = pt->pt_type;
1536                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1537                                         break;
1538                               if (cookies)
1539                                         *cookies++ = i + 1;
1540                               nc++;
1541                     }
1542                     if (error)
1543                               goto out;
1544                     for (; uio->uio_resid >= UIO_MX && i < nfd; i++) {
1545                               /* check the descriptor exists */
1546                               if ((fp = fd_getfile2(p, i - 2)) == NULL)
1547                                         continue;
1548                               closef(fp);
1549 
1550                               d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2);
1551                               d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
1552                                   "%lld", (long long)(i - 2));
1553                               d.d_type = fttodt(fp);
1554                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1555                                         break;
1556                               if (cookies)
1557                                         *cookies++ = i + 1;
1558                               nc++;
1559                     }
1560                     goto out;
1561           }
1562           case PFStask: {
1563 
1564                     if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p,
1565                                                         ESRCH)) != 0)
1566                               return error;
1567 
1568                     nfd = 3;  /* ., .., pid */
1569 
1570                     if (ap->a_ncookies) {
1571                               ncookies = uimin(ncookies, (nfd + 2 - i));
1572                               cookies = malloc(ncookies * sizeof (off_t),
1573                                   M_TEMP, M_WAITOK);
1574                               *ap->a_cookies = cookies;
1575                     }
1576 
1577                     for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
1578                               pt = &proc_targets[i];
1579                               d.d_namlen = pt->pt_namlen;
1580                               d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1581                                   pt->pt_pfstype, -1);
1582                               (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1583                               d.d_type = pt->pt_type;
1584                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1585                                         break;
1586                               if (cookies)
1587                                         *cookies++ = i + 1;
1588                               nc++;
1589                     }
1590                     if (error)
1591                               goto out;
1592                     for (; uio->uio_resid >= UIO_MX && i < nfd; i++) {
1593                               /* check the descriptor exists */
1594                               d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFStask,
1595                                   i - 2);
1596                               d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
1597                                   "%ld", (long)pfs->pfs_pid);
1598                               d.d_type = DT_LNK;
1599                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1600                                         break;
1601                               if (cookies)
1602                                         *cookies++ = i + 1;
1603                               nc++;
1604                     }
1605                     goto out;
1606           }
1607 
1608           /*
1609            * misc subdirectories
1610            */
1611           case PFSsys:
1612           case PFSsysfs:
1613           case PFSmqueue:
1614           case PFSsysvipc: {
1615                     const struct proc_target *targets;
1616                     int ntargets;
1617 
1618                     switch (pfs->pfs_type) {
1619                     case PFSsys:
1620                               targets = proc_sys_targets;
1621                               ntargets = nproc_sys_targets;
1622                               break;
1623                     case PFSsysfs:
1624                               targets = proc_sysfs_targets;
1625                               ntargets = nproc_sysfs_targets;
1626                               break;
1627                     case PFSmqueue:
1628                               targets = proc_mqueue_targets;
1629                               ntargets = nproc_mqueue_targets;
1630                               break;
1631                     case PFSsysvipc:
1632                               targets = proc_sysvipc_targets;
1633                               ntargets = nproc_sysvipc_targets;
1634                               break;
1635                     default:
1636                               return (EINVAL);
1637                     }
1638 
1639                     if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p,
1640                                                         ESRCH)) != 0)
1641                               return error;
1642                     if (ap->a_ncookies) {
1643                               ncookies = uimin(ncookies, (ntargets - i));
1644                               cookies = malloc(ncookies * sizeof (off_t),
1645                                   M_TEMP, M_WAITOK);
1646                               *ap->a_cookies = cookies;
1647                     }
1648 
1649                     for (pt = &targets[i];
1650                          uio->uio_resid >= UIO_MX && i < ntargets; pt++, i++) {
1651                               if (pt->pt_valid &&
1652                                   (*pt->pt_valid)(NULL, vp->v_mount) == 0)
1653                                         continue;
1654                               d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1655                                   pt->pt_pfstype, -1);
1656                               d.d_namlen = pt->pt_namlen;
1657                               memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1658                               d.d_type = pt->pt_type;
1659 
1660                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1661                                         break;
1662                               if (cookies)
1663                                         *cookies++ = i + 1;
1664                     }
1665 
1666                     goto out;
1667           }
1668 
1669           /*
1670            * this is for the root of the procfs filesystem
1671            * what is needed are special entries for "curproc"
1672            * and "self" followed by an entry for each process
1673            * on allproc.
1674            */
1675 
1676           case PFSroot: {
1677 
1678                     if (ap->a_ncookies) {
1679                               /*
1680                                * XXX Potentially allocating too much space here,
1681                                * but I'm lazy. This loop needs some work.
1682                                */
1683                               cookies = malloc(ncookies * sizeof (off_t),
1684                                   M_TEMP, M_WAITOK);
1685                               *ap->a_cookies = cookies;
1686                     }
1687 
1688                     /* 0 ... 3 are static entries. */
1689                     for (; i <= 3 && uio->uio_resid >= UIO_MX; i++) {
1690                               switch (i) {
1691                               case 0:             /* `.' */
1692                               case 1:             /* `..' */
1693                                         d.d_fileno = PROCFS_FILENO(0, PFSroot, -1);
1694                                         d.d_namlen = i + 1;
1695                                         memcpy(d.d_name, "..", d.d_namlen);
1696                                         d.d_name[i + 1] = '\0';
1697                                         d.d_type = DT_DIR;
1698                                         break;
1699 
1700                               case 2:
1701                                         d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1);
1702                                         d.d_namlen = sizeof("curproc") - 1;
1703                                         memcpy(d.d_name, "curproc", sizeof("curproc"));
1704                                         d.d_type = DT_LNK;
1705                                         break;
1706 
1707                               case 3:
1708                                         d.d_fileno = PROCFS_FILENO(0, PFSself, -1);
1709                                         d.d_namlen = sizeof("self") - 1;
1710                                         memcpy(d.d_name, "self", sizeof("self"));
1711                                         d.d_type = DT_LNK;
1712                                         break;
1713                               }
1714 
1715                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1716                                         break;
1717                               nc++;
1718                               if (cookies)
1719                                         *cookies++ = i + 1;
1720                     }
1721                     if (error)
1722                               break;
1723                     /* 4 ... are process entries. */
1724                     ctx.uiop = uio;
1725                     ctx.error = 0;
1726                     ctx.off = 4;
1727                     ctx.startoff = i;
1728                     ctx.cookies = cookies;
1729                     ctx.ncookies = nc;
1730                     proclist_foreach_call(&allproc,
1731                         procfs_root_readdir_callback, &ctx);
1732                     cookies = ctx.cookies;
1733                     nc = ctx.ncookies;
1734                     error = ctx.error;
1735                     if (error)
1736                               break;
1737 
1738                     /* misc entries. */
1739                     if (i < ctx.off)
1740                               i = ctx.off;
1741                     if (i >= ctx.off + nproc_root_targets)
1742                               break;
1743                     error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, ESRCH);
1744                     if (error)
1745                               break;
1746                     for (pt = &proc_root_targets[i - ctx.off];
1747                         uio->uio_resid >= UIO_MX &&
1748                         pt < &proc_root_targets[nproc_root_targets];
1749                         pt++, i++) {
1750                               if (pt->pt_valid &&
1751                                   (*pt->pt_valid)(NULL, vp->v_mount) == 0)
1752                                         continue;
1753                               if (kauth_authorize_process(kauth_cred_get(),
1754                                   KAUTH_PROCESS_CANSEE, p,
1755                                   KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY),
1756                                   NULL, NULL) != 0)
1757                                         continue;
1758                               d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1);
1759                               d.d_namlen = pt->pt_namlen;
1760                               memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1761                               d.d_type = pt->pt_type;
1762 
1763                               if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1764                                         break;
1765                               nc++;
1766                               if (cookies)
1767                                         *cookies++ = i + 1;
1768                     }
1769 out:
1770                     KASSERT(p != NULL);
1771                     ncookies = nc;
1772                     procfs_proc_unlock(p);
1773                     break;
1774           }
1775 
1776           default:
1777                     error = ENOTDIR;
1778                     break;
1779           }
1780 
1781           if (ap->a_ncookies) {
1782                     if (error) {
1783                               if (cookies)
1784                                         free(*ap->a_cookies, M_TEMP);
1785                               *ap->a_ncookies = 0;
1786                               *ap->a_cookies = NULL;
1787                     } else
1788                               *ap->a_ncookies = ncookies;
1789           }
1790           uio->uio_offset = i;
1791           return (error);
1792 }
1793 
1794 /*
1795  * readlink reads the link of `curproc' and others
1796  */
1797 int
procfs_readlink(void * v)1798 procfs_readlink(void *v)
1799 {
1800           struct vop_readlink_args *ap = v;
1801           char bf[16];                  /* should be enough */
1802           char *bp = bf;
1803           char *path = NULL;
1804           int len = 0;
1805           int error = 0;
1806           struct vnode *vp = ap->a_vp;
1807           struct pfsnode *pfs = VTOPFS(vp);
1808           struct proc *pown = NULL;
1809 
1810           if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1))
1811                     len = snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1812           else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1))
1813                     len = snprintf(bf, sizeof(bf), "%s", "curproc");
1814           else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFStask, 0))
1815                     len = snprintf(bf, sizeof(bf), "..");
1816           else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSexe, -1)) {
1817                     if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &pown,
1818                                                         ESRCH)) != 0)
1819                               return error;
1820                     bp = pown->p_path;
1821                     len = strlen(bp);
1822           } else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFScwd, -1) ||
1823               pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSchroot, -1)) {
1824                     if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &pown,
1825                                                         ESRCH)) != 0)
1826                               return error;
1827                     path = malloc(MAXPATHLEN + 4, M_TEMP, M_WAITOK);
1828                     if (path == NULL) {
1829                               procfs_proc_unlock(pown);
1830                               return (ENOMEM);
1831                     }
1832                     bp = path + MAXPATHLEN;
1833                     *--bp = '\0';
1834                     procfs_dir(PROCFS_TYPE(pfs->pfs_fileno), curlwp, pown,
1835                         &bp, path, MAXPATHLEN);
1836                     len = strlen(bp);
1837           } else {
1838                     file_t *fp;
1839                     struct vnode *vxp;
1840 
1841                     if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &pown,
1842                                                         ESRCH)) != 0)
1843                               return error;
1844 
1845                     fp = fd_getfile2(pown, pfs->pfs_fd);
1846                     if (fp == NULL) {
1847                               procfs_proc_unlock(pown);
1848                               return EBADF;
1849                     }
1850 
1851                     switch (fp->f_type) {
1852                     case DTYPE_VNODE:
1853                               vxp = fp->f_vnode;
1854                               if (vxp->v_type != VDIR &&
1855                                   !procfs_proc_is_linux_compat()) {
1856                                         error = EINVAL;
1857                                         break;
1858                               }
1859                               if ((path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK))
1860                                   == NULL) {
1861                                         error = ENOMEM;
1862                                         break;
1863                               }
1864                               bp = path + MAXPATHLEN;
1865                               *--bp = '\0';
1866 
1867                               /*
1868                                * XXX: kludge to avoid locking against ourselves
1869                                * in getcwd()
1870                                */
1871                               if (vxp->v_tag == VT_PROCFS) {
1872                                         *--bp = '/';
1873                               } else {
1874                                         rw_enter(&curproc->p_cwdi->cwdi_lock,
1875                                             RW_READER);
1876                                         vp = curproc->p_cwdi->cwdi_rdir;
1877                                         if (vp == NULL)
1878                                                   vp = rootvnode;
1879                                         error = getcwd_common(vxp, vp, &bp, path,
1880                                             MAXPATHLEN / 2, 0, curlwp);
1881                                         rw_exit(&curproc->p_cwdi->cwdi_lock);
1882                               }
1883                               if (error)
1884                                         break;
1885                               len = strlen(bp);
1886                               break;
1887 
1888                     case DTYPE_MISC:
1889                               len = snprintf(bf, sizeof(bf), "%s", "[misc]");
1890                               break;
1891 
1892                     case DTYPE_KQUEUE:
1893                               len = snprintf(bf, sizeof(bf), "%s", "[kqueue]");
1894                               break;
1895 
1896                     case DTYPE_SEM:
1897                               len = snprintf(bf, sizeof(bf), "%s", "[ksem]");
1898                               break;
1899 
1900                     default:
1901                               error = EINVAL;
1902                               break;
1903                     }
1904                     closef(fp);
1905           }
1906 
1907           if (error == 0)
1908                     error = uiomove(bp, len, ap->a_uio);
1909           if (pown)
1910                     procfs_proc_unlock(pown);
1911           if (path)
1912                     free(path, M_TEMP);
1913           return error;
1914 }
1915 
1916 int
procfs_getpages(void * v)1917 procfs_getpages(void *v)
1918 {
1919           struct vop_getpages_args /* {
1920                     struct vnode *a_vp;
1921                     voff_t a_offset;
1922                     struct vm_page **a_m;
1923                     int *a_count;
1924                     int a_centeridx;
1925                     vm_prot_t a_access_type;
1926                     int a_advice;
1927                     int a_flags;
1928           } */ *ap = v;
1929 
1930           if ((ap->a_flags & PGO_LOCKED) == 0)
1931                     rw_exit(ap->a_vp->v_uobj.vmobjlock);
1932 
1933           return (EFAULT);
1934 }
1935 
1936 /*
1937  * convert decimal ascii to int
1938  */
1939 static int
atoi(const char * b,size_t len)1940 atoi(const char *b, size_t len)
1941 {
1942           int p = 0;
1943 
1944           while (len--) {
1945                     char c = *b++;
1946                     if (c < '0' || c > '9')
1947                               return -1;
1948                     p = 10 * p + (c - '0');
1949           }
1950 
1951           return p;
1952 }
1953 
1954 /**
1955  * convert DTYPE_XXX to corresponding DT_XXX
1956  * matching what procfs_loadvnode() does.
1957  */
1958 static uint8_t
fttodt(file_t * fp)1959 fttodt(file_t *fp)
1960 {
1961           switch (fp->f_type) {
1962           case DTYPE_VNODE:
1963                     switch (fp->f_vnode->v_type) {
1964                     case VREG:          return DT_REG;
1965                     case VDIR:          return DT_LNK;      /* symlink */
1966                     case VBLK:          return DT_BLK;
1967                     case VCHR:          return DT_CHR;
1968                     case VLNK:          return DT_LNK;
1969                     case VSOCK:         return DT_SOCK;
1970                     case VFIFO:         return DT_FIFO;
1971                     default:  return DT_UNKNOWN;
1972                     }
1973           case DTYPE_PIPE:    return DT_FIFO;
1974           case DTYPE_SOCKET:  return DT_SOCK;
1975           case DTYPE_KQUEUE:  /*FALLTHROUGH*/
1976           case DTYPE_MISC:    /*FALLTHROUGH*/
1977           case DTYPE_SEM:               return DT_LNK;      /* symlinks */
1978           default:            return DT_UNKNOWN;
1979           }
1980 }
1981