1 /* $NetBSD: vfs_getcwd.c,v 1.52 2017/07/28 15:37:23 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Bill Sommerfeld. 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 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: vfs_getcwd.c,v 1.52 2017/07/28 15:37:23 riastradh Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/namei.h> 38 #include <sys/filedesc.h> 39 #include <sys/kernel.h> 40 #include <sys/file.h> 41 #include <sys/stat.h> 42 #include <sys/vnode.h> 43 #include <sys/mount.h> 44 #include <sys/proc.h> 45 #include <sys/uio.h> 46 #include <sys/kmem.h> 47 #include <sys/dirent.h> 48 #include <sys/kauth.h> 49 50 #include <ufs/ufs/dir.h> /* XXX only for DIRBLKSIZ */ 51 52 #include <sys/syscallargs.h> 53 54 /* 55 * Vnode variable naming conventions in this file: 56 * 57 * rvp: the current root we're aiming towards. 58 * lvp, *lvpp: the "lower" vnode 59 * uvp, *uvpp: the "upper" vnode. 60 * 61 * Since all the vnodes we're dealing with are directories, and the 62 * lookups are going *up* in the filesystem rather than *down*, the 63 * usual "pvp" (parent) or "dvp" (directory) naming conventions are 64 * too confusing. 65 */ 66 67 /* 68 * XXX Will infinite loop in certain cases if a directory read reliably 69 * returns EINVAL on last block. 70 * XXX is EINVAL the right thing to return if a directory is malformed? 71 */ 72 73 /* 74 * XXX Untested vs. mount -o union; probably does the wrong thing. 75 */ 76 77 /* 78 * Find parent vnode of *lvpp, return in *uvpp 79 * 80 * If we care about the name, scan it looking for name of directory 81 * entry pointing at lvp. 82 * 83 * Place the name in the buffer which starts at bufp, immediately 84 * before *bpp, and move bpp backwards to point at the start of it. 85 * 86 * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed 87 * On exit, *uvpp is either NULL or is a locked vnode reference. 88 */ 89 static int 90 getcwd_scandir(struct vnode **lvpp, struct vnode **uvpp, char **bpp, 91 char *bufp, struct lwp *l) 92 { 93 int error = 0; 94 int eofflag; 95 off_t off; 96 int tries; 97 struct uio uio; 98 struct iovec iov; 99 char *dirbuf = NULL; 100 int dirbuflen; 101 ino_t fileno; 102 struct vattr va; 103 struct vnode *uvp = NULL; 104 struct vnode *lvp = *lvpp; 105 kauth_cred_t cred = l->l_cred; 106 struct componentname cn; 107 int len, reclen; 108 tries = 0; 109 110 /* 111 * If we want the filename, get some info we need while the 112 * current directory is still locked. 113 */ 114 if (bufp != NULL) { 115 error = VOP_GETATTR(lvp, &va, cred); 116 if (error) { 117 vput(lvp); 118 *lvpp = NULL; 119 *uvpp = NULL; 120 return error; 121 } 122 } 123 124 /* 125 * Ok, we have to do it the hard way.. 126 * Next, get parent vnode using lookup of .. 127 */ 128 cn.cn_nameiop = LOOKUP; 129 cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY; 130 cn.cn_cred = cred; 131 cn.cn_nameptr = ".."; 132 cn.cn_namelen = 2; 133 cn.cn_consume = 0; 134 135 /* At this point, lvp is locked */ 136 error = VOP_LOOKUP(lvp, uvpp, &cn); 137 vput(lvp); 138 if (error) { 139 *lvpp = NULL; 140 *uvpp = NULL; 141 return error; 142 } 143 uvp = *uvpp; 144 /* Now lvp is unlocked, try to lock uvp */ 145 error = vn_lock(uvp, LK_EXCLUSIVE); 146 if (error) { 147 *lvpp = NULL; 148 *uvpp = NULL; 149 return error; 150 } 151 152 /* If we don't care about the pathname, we're done */ 153 if (bufp == NULL) { 154 *lvpp = NULL; 155 return 0; 156 } 157 158 fileno = va.va_fileid; 159 160 /* I guess UFS_DIRBLKSIZ is a good guess at a good size to use? */ 161 dirbuflen = UFS_DIRBLKSIZ; 162 if (dirbuflen < va.va_blocksize) 163 dirbuflen = va.va_blocksize; 164 dirbuf = kmem_alloc(dirbuflen, KM_SLEEP); 165 166 #if 0 167 unionread: 168 #endif 169 off = 0; 170 do { 171 /* call VOP_READDIR of parent */ 172 iov.iov_base = dirbuf; 173 iov.iov_len = dirbuflen; 174 175 uio.uio_iov = &iov; 176 uio.uio_iovcnt = 1; 177 uio.uio_offset = off; 178 uio.uio_resid = dirbuflen; 179 uio.uio_rw = UIO_READ; 180 UIO_SETUP_SYSSPACE(&uio); 181 182 eofflag = 0; 183 184 error = VOP_READDIR(uvp, &uio, cred, &eofflag, 0, 0); 185 186 off = uio.uio_offset; 187 188 /* 189 * Try again if NFS tosses its cookies. 190 * XXX this can still loop forever if the directory is busted 191 * such that the second or subsequent page of it always 192 * returns EINVAL 193 */ 194 if ((error == EINVAL) && (tries < 3)) { 195 off = 0; 196 tries++; 197 continue; /* once more, with feeling */ 198 } 199 200 if (!error) { 201 char *cpos; 202 struct dirent *dp; 203 204 cpos = dirbuf; 205 tries = 0; 206 207 /* scan directory page looking for matching vnode */ 208 for (len = (dirbuflen - uio.uio_resid); len > 0; 209 len -= reclen) { 210 dp = (struct dirent *) cpos; 211 reclen = dp->d_reclen; 212 213 /* check for malformed directory.. */ 214 if (reclen < _DIRENT_MINSIZE(dp) || 215 reclen > len) { 216 error = EINVAL; 217 goto out; 218 } 219 /* 220 * XXX should perhaps do VOP_LOOKUP to 221 * check that we got back to the right place, 222 * but getting the locking games for that 223 * right would be heinous. 224 */ 225 if ((dp->d_type != DT_WHT) && 226 (dp->d_fileno == fileno)) { 227 char *bp = *bpp; 228 229 bp -= dp->d_namlen; 230 if (bp <= bufp) { 231 error = ERANGE; 232 goto out; 233 } 234 memcpy(bp, dp->d_name, dp->d_namlen); 235 error = 0; 236 *bpp = bp; 237 goto out; 238 } 239 cpos += reclen; 240 } 241 } else 242 goto out; 243 } while (!eofflag); 244 #if 0 245 /* 246 * Deal with mount -o union, which unions only the 247 * root directory of the mount. 248 */ 249 if ((uvp->v_vflag & VV_ROOT) && 250 (uvp->v_mount->mnt_flag & MNT_UNION)) { 251 struct vnode *tvp = uvp; 252 253 uvp = uvp->v_mount->mnt_vnodecovered; 254 vput(tvp); 255 vref(uvp); 256 *uvpp = uvp; 257 vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY); 258 goto unionread; 259 } 260 #endif 261 error = ENOENT; 262 263 out: 264 *lvpp = NULL; 265 kmem_free(dirbuf, dirbuflen); 266 return error; 267 } 268 269 /* 270 * Look in the vnode-to-name reverse cache to see if 271 * we can find things the easy way. 272 * 273 * XXX vget failure path is untested. 274 * 275 * On entry, *lvpp is a locked vnode reference. 276 * On exit, one of the following is the case: 277 * 0) Both *lvpp and *uvpp are NULL and failure is returned. 278 * 1) *uvpp is NULL, *lvpp remains locked and -1 is returned (cache miss) 279 * 2) *uvpp is a locked vnode reference, *lvpp is vput and NULL'ed 280 * and 0 is returned (cache hit) 281 */ 282 283 static int 284 getcwd_getcache(struct vnode **lvpp, struct vnode **uvpp, char **bpp, 285 char *bufp) 286 { 287 struct vnode *lvp, *uvp = NULL; 288 int error; 289 290 lvp = *lvpp; 291 292 /* 293 * This returns 0 on a cache hit, -1 on a clean cache miss, 294 * or an errno on other failure. 295 */ 296 error = cache_revlookup(lvp, uvpp, bpp, bufp); 297 if (error) { 298 if (error != -1) { 299 vput(lvp); 300 *lvpp = NULL; 301 *uvpp = NULL; 302 } 303 return error; 304 } 305 uvp = *uvpp; 306 307 /* 308 * Since we're going up, we have to release the current lock 309 * before we take the parent lock. 310 */ 311 312 VOP_UNLOCK(lvp); 313 vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY); 314 vrele(lvp); 315 *lvpp = NULL; 316 317 return error; 318 } 319 320 /* 321 * common routine shared by sys___getcwd() and vn_isunder() 322 */ 323 324 int 325 getcwd_common(struct vnode *lvp, struct vnode *rvp, char **bpp, char *bufp, 326 int limit, int flags, struct lwp *l) 327 { 328 struct cwdinfo *cwdi = l->l_proc->p_cwdi; 329 kauth_cred_t cred = l->l_cred; 330 struct vnode *uvp = NULL; 331 char *bp = NULL; 332 int error; 333 int perms = VEXEC; 334 335 error = 0; 336 if (rvp == NULL) { 337 rvp = cwdi->cwdi_rdir; 338 if (rvp == NULL) 339 rvp = rootvnode; 340 } 341 342 vref(rvp); 343 vref(lvp); 344 345 /* 346 * Error handling invariant: 347 * Before a `goto out': 348 * lvp is either NULL, or locked and held. 349 * uvp is either NULL, or locked and held. 350 */ 351 352 vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); 353 if (bufp) 354 bp = *bpp; 355 356 /* 357 * this loop will terminate when one of the following happens: 358 * - we hit the root 359 * - getdirentries or lookup fails 360 * - we run out of space in the buffer. 361 */ 362 if (lvp == rvp) { 363 if (bp) 364 *(--bp) = '/'; 365 goto out; 366 } 367 do { 368 /* 369 * access check here is optional, depending on 370 * whether or not caller cares. 371 */ 372 if (flags & GETCWD_CHECK_ACCESS) { 373 error = VOP_ACCESS(lvp, perms, cred); 374 if (error) 375 goto out; 376 perms = VEXEC|VREAD; 377 } 378 379 /* 380 * step up if we're a covered vnode.. 381 */ 382 while (lvp->v_vflag & VV_ROOT) { 383 struct vnode *tvp; 384 385 if (lvp == rvp) 386 goto out; 387 388 tvp = lvp; 389 lvp = lvp->v_mount->mnt_vnodecovered; 390 vput(tvp); 391 /* 392 * hodie natus est radici frater 393 */ 394 if (lvp == NULL) { 395 error = ENOENT; 396 goto out; 397 } 398 vref(lvp); 399 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); 400 if (error != 0) { 401 vrele(lvp); 402 lvp = NULL; 403 goto out; 404 } 405 } 406 /* 407 * Look in the name cache; if that fails, look in the 408 * directory.. 409 */ 410 error = getcwd_getcache(&lvp, &uvp, &bp, bufp); 411 if (error == -1) { 412 if (lvp->v_type != VDIR) { 413 error = ENOTDIR; 414 goto out; 415 } 416 error = getcwd_scandir(&lvp, &uvp, &bp, bufp, l); 417 } 418 if (error) 419 goto out; 420 #if DIAGNOSTIC 421 if (lvp != NULL) 422 panic("getcwd: oops, forgot to null lvp"); 423 if (bufp && (bp <= bufp)) { 424 panic("getcwd: oops, went back too far"); 425 } 426 #endif 427 if (bp) 428 *(--bp) = '/'; 429 lvp = uvp; 430 uvp = NULL; 431 limit--; 432 } while ((lvp != rvp) && (limit > 0)); 433 434 out: 435 if (bpp) 436 *bpp = bp; 437 if (uvp) 438 vput(uvp); 439 if (lvp) 440 vput(lvp); 441 vrele(rvp); 442 return error; 443 } 444 445 /* 446 * Check if one directory can be found inside another in the directory 447 * hierarchy. 448 * 449 * Intended to be used in chroot, chdir, fchdir, etc., to ensure that 450 * chroot() actually means something. 451 */ 452 int 453 vn_isunder(struct vnode *lvp, struct vnode *rvp, struct lwp *l) 454 { 455 int error; 456 457 error = getcwd_common(lvp, rvp, NULL, NULL, MAXPATHLEN / 2, 0, l); 458 459 if (!error) 460 return 1; 461 else 462 return 0; 463 } 464 465 /* 466 * Returns true if proc p1's root directory equal to or under p2's 467 * root directory. 468 * 469 * Intended to be used from ptrace/procfs sorts of things. 470 */ 471 472 int 473 proc_isunder(struct proc *p1, struct lwp *l2) 474 { 475 struct vnode *r1 = p1->p_cwdi->cwdi_rdir; 476 struct vnode *r2 = l2->l_proc->p_cwdi->cwdi_rdir; 477 478 if (r1 == NULL) 479 return (r2 == NULL); 480 else if (r2 == NULL) 481 return 1; 482 else 483 return vn_isunder(r1, r2, l2); 484 } 485 486 /* 487 * Find pathname of process's current directory. 488 * 489 * Use vfs vnode-to-name reverse cache; if that fails, fall back 490 * to reading directory contents. 491 */ 492 493 int 494 sys___getcwd(struct lwp *l, const struct sys___getcwd_args *uap, register_t *retval) 495 { 496 /* { 497 syscallarg(char *) bufp; 498 syscallarg(size_t) length; 499 } */ 500 501 int error; 502 char *path; 503 char *bp, *bend; 504 int len = SCARG(uap, length); 505 int lenused; 506 struct cwdinfo *cwdi; 507 508 if (len > MAXPATHLEN * 4) 509 len = MAXPATHLEN * 4; 510 else if (len < 2) 511 return ERANGE; 512 513 path = kmem_alloc(len, KM_SLEEP); 514 bp = &path[len]; 515 bend = bp; 516 *(--bp) = '\0'; 517 518 /* 519 * 5th argument here is "max number of vnodes to traverse". 520 * Since each entry takes up at least 2 bytes in the output buffer, 521 * limit it to N/2 vnodes for an N byte buffer. 522 */ 523 cwdi = l->l_proc->p_cwdi; 524 rw_enter(&cwdi->cwdi_lock, RW_READER); 525 error = getcwd_common(cwdi->cwdi_cdir, NULL, &bp, path, 526 len/2, GETCWD_CHECK_ACCESS, l); 527 rw_exit(&cwdi->cwdi_lock); 528 529 if (error) 530 goto out; 531 lenused = bend - bp; 532 *retval = lenused; 533 /* put the result into user buffer */ 534 error = copyout(bp, SCARG(uap, bufp), lenused); 535 536 out: 537 kmem_free(path, len); 538 return error; 539 } 540 541 /* 542 * Try to find a pathname for a vnode. Since there is no mapping 543 * vnode -> parent directory, this needs the NAMECACHE_ENTER_REVERSE 544 * option to work (to make cache_revlookup succeed). Caller holds a 545 * reference to the vnode. 546 */ 547 int 548 vnode_to_path(char *path, size_t len, struct vnode *vp, struct lwp *curl, 549 struct proc *p) 550 { 551 struct proc *curp = curl->l_proc; 552 int error, lenused, elen; 553 char *bp, *bend; 554 struct vnode *dvp; 555 556 KASSERT(vp->v_usecount > 0); 557 558 bp = bend = &path[len]; 559 *(--bp) = '\0'; 560 561 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 562 if (error != 0) 563 return error; 564 error = cache_revlookup(vp, &dvp, &bp, path); 565 VOP_UNLOCK(vp); 566 if (error != 0) 567 return (error == -1 ? ENOENT : error); 568 569 *(--bp) = '/'; 570 error = getcwd_common(dvp, NULL, &bp, path, len / 2, 571 GETCWD_CHECK_ACCESS, curl); 572 vrele(dvp); 573 574 /* 575 * Strip off emulation path for emulated processes looking at 576 * the maps file of a process of the same emulation. (Won't 577 * work if /emul/xxx is a symlink..) 578 */ 579 if (curp->p_emul == p->p_emul && curp->p_emul->e_path != NULL) { 580 elen = strlen(curp->p_emul->e_path); 581 if (!strncmp(bp, curp->p_emul->e_path, elen)) 582 bp = &bp[elen]; 583 } 584 585 lenused = bend - bp; 586 587 memcpy(path, bp, lenused); 588 path[lenused] = 0; 589 590 return 0; 591 } 592