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