1 /* $NetBSD: procfs_subr.c,v 1.120 2024/07/01 01:35:53 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2006, 2007, 2008 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 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_subr.c 8.6 (Berkeley) 5/14/95 64 */ 65 66 /* 67 * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved. 68 * Copyright (c) 1993 Jan-Simon Pendry 69 * 70 * This code is derived from software contributed to Berkeley by 71 * Jan-Simon Pendry. 72 * 73 * Redistribution and use in source and binary forms, with or without 74 * modification, are permitted provided that the following conditions 75 * are met: 76 * 1. Redistributions of source code must retain the above copyright 77 * notice, this list of conditions and the following disclaimer. 78 * 2. Redistributions in binary form must reproduce the above copyright 79 * notice, this list of conditions and the following disclaimer in the 80 * documentation and/or other materials provided with the distribution. 81 * 3. All advertising materials mentioning features or use of this software 82 * must display the following acknowledgement: 83 * This product includes software developed by the University of 84 * California, Berkeley and its contributors. 85 * 4. Neither the name of the University nor the names of its contributors 86 * may be used to endorse or promote products derived from this software 87 * without specific prior written permission. 88 * 89 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 90 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 91 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 92 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 93 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 94 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 95 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 96 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 97 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 98 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 99 * SUCH DAMAGE. 100 * 101 * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95 102 */ 103 104 #include <sys/cdefs.h> 105 __KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.120 2024/07/01 01:35:53 christos Exp $"); 106 107 #include <sys/param.h> 108 #include <sys/systm.h> 109 #include <sys/time.h> 110 #include <sys/kernel.h> 111 #include <sys/proc.h> 112 #include <sys/fstrans.h> 113 #include <sys/vnode.h> 114 #include <sys/stat.h> 115 #include <sys/file.h> 116 #include <sys/filedesc.h> 117 #include <sys/kauth.h> 118 #include <sys/sysctl.h> 119 120 #include <miscfs/procfs/procfs.h> 121 122 /* 123 * Allocate a pfsnode/vnode pair. The vnode is referenced. 124 * The pid, type, and file descriptor uniquely identify a pfsnode. 125 */ 126 int 127 procfs_allocvp(struct mount *mp, struct vnode **vpp, pid_t pid, 128 pfstype type, int fd) 129 { 130 struct pfskey key; 131 132 memset(&key, 0, sizeof(key)); 133 key.pk_type = type; 134 key.pk_pid = pid; 135 key.pk_fd = fd; 136 137 return vcache_get(mp, &key, sizeof(key), vpp); 138 } 139 140 int 141 procfs_rw(void *v) 142 { 143 struct vop_read_args *ap = v; 144 struct vnode *vp = ap->a_vp; 145 struct uio *uio = ap->a_uio; 146 struct lwp *curl; 147 struct lwp *l; 148 struct pfsnode *pfs = VTOPFS(vp); 149 struct proc *p; 150 int error; 151 152 if (uio->uio_offset < 0) 153 return EINVAL; 154 155 if ((error = 156 procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, ESRCH)) != 0) 157 return error; 158 159 curl = curlwp; 160 161 /* 162 * Do not allow init to be modified while in secure mode; it 163 * could be duped into changing the security level. 164 */ 165 #define M2K(m) ((m) == UIO_READ ? KAUTH_REQ_PROCESS_PROCFS_READ : \ 166 KAUTH_REQ_PROCESS_PROCFS_WRITE) 167 mutex_enter(p->p_lock); 168 error = kauth_authorize_process(curl->l_cred, KAUTH_PROCESS_PROCFS, 169 p, pfs, KAUTH_ARG(M2K(uio->uio_rw)), NULL); 170 mutex_exit(p->p_lock); 171 if (error) { 172 procfs_proc_unlock(p); 173 return (error); 174 } 175 #undef M2K 176 177 mutex_enter(p->p_lock); 178 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 179 if (l->l_stat != LSZOMB) 180 break; 181 } 182 /* Process is exiting if no-LWPS or all LWPs are LSZOMB */ 183 if (l == NULL) { 184 mutex_exit(p->p_lock); 185 procfs_proc_unlock(p); 186 return ESRCH; 187 } 188 189 lwp_addref(l); 190 mutex_exit(p->p_lock); 191 192 switch (pfs->pfs_type) { 193 case PFSnote: 194 case PFSnotepg: 195 error = procfs_donote(curl, p, pfs, uio); 196 break; 197 198 case PFSregs: 199 error = procfs_doregs(curl, l, pfs, uio); 200 break; 201 202 case PFSfpregs: 203 error = procfs_dofpregs(curl, l, pfs, uio); 204 break; 205 206 case PFSstatus: 207 error = procfs_dostatus(curl, l, pfs, uio); 208 break; 209 210 case PFSstat: 211 error = procfs_do_pid_stat(curl, l, pfs, uio); 212 break; 213 214 case PFSlimit: 215 error = procfs_dolimit(curl, p, pfs, uio); 216 break; 217 218 case PFSlimits: 219 error = procfs_dolimits(curl, p, pfs, uio); 220 break; 221 222 case PFSmap: 223 error = procfs_domap(curl, p, pfs, uio, 0); 224 break; 225 226 case PFSmaps: 227 error = procfs_domap(curl, p, pfs, uio, 1); 228 break; 229 230 case PFSmem: 231 error = procfs_domem(curl, l, pfs, uio); 232 break; 233 234 case PFScmdline: 235 error = procfs_doprocargs(curl, p, pfs, uio, KERN_PROC_ARGV); 236 break; 237 238 case PFSenviron: 239 error = procfs_doprocargs(curl, p, pfs, uio, KERN_PROC_ENV); 240 break; 241 242 case PFSmeminfo: 243 error = procfs_domeminfo(curl, p, pfs, uio); 244 break; 245 246 case PFSdevices: 247 error = procfs_dodevices(curl, p, pfs, uio); 248 break; 249 250 case PFScpuinfo: 251 error = procfs_docpuinfo(curl, p, pfs, uio); 252 break; 253 254 case PFScpustat: 255 error = procfs_docpustat(curl, p, pfs, uio); 256 break; 257 258 case PFSloadavg: 259 error = procfs_doloadavg(curl, p, pfs, uio); 260 break; 261 262 case PFSstatm: 263 error = procfs_do_pid_statm(curl, l, pfs, uio); 264 break; 265 266 case PFSfd: 267 error = procfs_dofd(curl, p, pfs, uio); 268 break; 269 270 case PFSuptime: 271 error = procfs_douptime(curl, p, pfs, uio); 272 break; 273 274 case PFSmounts: 275 error = procfs_domounts(curl, p, pfs, uio); 276 break; 277 278 case PFSemul: 279 error = procfs_doemul(curl, p, pfs, uio); 280 break; 281 282 case PFSversion: 283 error = procfs_doversion(curl, p, pfs, uio); 284 break; 285 286 case PFSauxv: 287 error = procfs_doauxv(curl, p, pfs, uio); 288 break; 289 290 case PFSsysvipc_msg: 291 error = procfs_dosysvipc_msg(curl, p, pfs, uio); 292 break; 293 294 case PFSsysvipc_sem: 295 error = procfs_dosysvipc_sem(curl, p, pfs, uio); 296 break; 297 298 case PFSsysvipc_shm: 299 error = procfs_dosysvipc_shm(curl, p, pfs, uio); 300 break; 301 302 case PFSmq_msg_def: 303 error = procfs_domq_msg_def(curl, p, pfs, uio); 304 break; 305 306 case PFSmq_msg_max: 307 error = procfs_domq_msg_max(curl, p, pfs, uio); 308 break; 309 310 case PFSmq_siz_def: 311 error = procfs_domq_siz_def(curl, p, pfs, uio); 312 break; 313 314 case PFSmq_siz_max: 315 error = procfs_domq_siz_max(curl, p, pfs, uio); 316 break; 317 318 case PFSmq_qmax: 319 error = procfs_domq_qmax(curl, p, pfs, uio); 320 break; 321 322 #ifdef __HAVE_PROCFS_MACHDEP 323 PROCFS_MACHDEP_NODETYPE_CASES 324 error = procfs_machdep_rw(curl, l, pfs, uio); 325 break; 326 #endif 327 328 default: 329 error = EOPNOTSUPP; 330 break; 331 } 332 333 /* 334 * Release the references that we acquired earlier. 335 */ 336 lwp_delref(l); 337 procfs_proc_unlock(p); 338 339 return (error); 340 } 341 342 /* 343 * Get a string from userland into (bf). Strip a trailing 344 * nl character (to allow easy access from the shell). 345 * The buffer should be *buflenp + 1 chars long. vfs_getuserstr 346 * will automatically add a nul char at the end. 347 * 348 * Returns 0 on success or the following errors 349 * 350 * EINVAL: file offset is non-zero. 351 * EMSGSIZE: message is longer than kernel buffer 352 * EFAULT: user i/o buffer is not addressable 353 */ 354 int 355 vfs_getuserstr(struct uio *uio, char *bf, int *buflenp) 356 { 357 size_t xlen; 358 int error; 359 360 if (uio->uio_offset != 0) 361 return (EINVAL); 362 363 xlen = *buflenp; 364 365 /* must be able to read the whole string in one go */ 366 if (xlen < uio->uio_resid) 367 return (EMSGSIZE); 368 xlen = uio->uio_resid; 369 370 if ((error = uiomove(bf, xlen, uio)) != 0) 371 return (error); 372 373 /* allow multiple writes without seeks */ 374 uio->uio_offset = 0; 375 376 /* cleanup string and remove trailing newline */ 377 bf[xlen] = '\0'; 378 xlen = strlen(bf); 379 if (xlen > 0 && bf[xlen-1] == '\n') 380 bf[--xlen] = '\0'; 381 *buflenp = xlen; 382 383 return (0); 384 } 385 386 const vfs_namemap_t * 387 vfs_findname(const vfs_namemap_t *nm, const char *bf, int buflen) 388 { 389 390 for (; nm->nm_name; nm++) 391 if (memcmp(bf, nm->nm_name, buflen+1) == 0) 392 return (nm); 393 394 return (0); 395 } 396 397 bool 398 procfs_use_linux_compat(struct mount *mp) 399 { 400 const int flags = VFSTOPROC(mp)->pmnt_flags; 401 402 return (flags & PROCFSMNT_LINUXCOMPAT) ? true : false; 403 } 404 405 struct proc * 406 procfs_proc_find(struct mount *mp, pid_t pid) 407 { 408 409 KASSERT(mutex_owned(&proc_lock)); 410 return procfs_use_linux_compat(mp) ? proc_find_lwpid(pid) 411 : proc_find(pid); 412 } 413 414 int 415 procfs_proc_lock(struct mount *mp, int pid, struct proc **bunghole, 416 int notfound) 417 { 418 struct proc *tp; 419 int error = 0; 420 421 mutex_enter(&proc_lock); 422 423 if (pid == 0) 424 tp = &proc0; 425 else if ((tp = procfs_proc_find(mp, pid)) == NULL) 426 error = notfound; 427 if (tp != NULL && !rw_tryenter(&tp->p_reflock, RW_READER)) 428 error = EBUSY; 429 430 mutex_exit(&proc_lock); 431 432 *bunghole = tp; 433 return error; 434 } 435 436 void 437 procfs_proc_unlock(struct proc *p) 438 { 439 440 rw_exit(&p->p_reflock); 441 } 442 443 int 444 procfs_doemul(struct lwp *curl, struct proc *p, 445 struct pfsnode *pfs, struct uio *uio) 446 { 447 const char *ename = p->p_emul->e_name; 448 return uiomove_frombuf(__UNCONST(ename), strlen(ename), uio); 449 } 450