Module Name: src Committed By: bad Date: Sat Aug 1 21:17:12 UTC 2009
Modified Files: src/sys/kern: vfs_syscalls.c src/sys/sys: vfs_syscalls.h Log Message: As discussed on tech-kern: Factor out common code of chroot-like syscalls into change_root() and export that function for use in other parts of the kernel. Rename change_dir() to chdir_lookup() as the latter describes better what the function does. While there, move the namei_data initialisation into chdir_lookup(), too. And export chdir_lookup(). To generate a diff of this commit: cvs rdiff -u -r1.396 -r1.397 src/sys/kern/vfs_syscalls.c cvs rdiff -u -r1.11 -r1.12 src/sys/sys/vfs_syscalls.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_syscalls.c diff -u src/sys/kern/vfs_syscalls.c:1.396 src/sys/kern/vfs_syscalls.c:1.397 --- src/sys/kern/vfs_syscalls.c:1.396 Thu Jul 2 12:53:47 2009 +++ src/sys/kern/vfs_syscalls.c Sat Aug 1 21:17:11 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_syscalls.c,v 1.396 2009/07/02 12:53:47 pooka Exp $ */ +/* $NetBSD: vfs_syscalls.c,v 1.397 2009/08/01 21:17:11 bad Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.396 2009/07/02 12:53:47 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.397 2009/08/01 21:17:11 bad Exp $"); #ifdef _KERNEL_OPT #include "opt_fileassoc.h" @@ -110,7 +110,6 @@ MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct"); -static int change_dir(struct nameidata *, struct lwp *); static int change_flags(struct vnode *, u_long, struct lwp *); static int change_mode(struct vnode *, int, struct lwp *l); static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int); @@ -1126,7 +1125,6 @@ sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval) { struct proc *p = l->l_proc; - struct cwdinfo *cwdi; struct vnode *vp; file_t *fp; int error, fd = SCARG(uap, fd); @@ -1135,7 +1133,7 @@ KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0) return error; /* fd_getvnode() will use the descriptor for us */ - if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) + if ((error = fd_getvnode(fd, &fp)) != 0) return error; vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); @@ -1148,27 +1146,7 @@ goto out; VREF(vp); - /* - * Prevent escaping from chroot by putting the root under - * the working directory. Silently chdir to / if we aren't - * already there. - */ - cwdi = p->p_cwdi; - rw_enter(&cwdi->cwdi_lock, RW_WRITER); - if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) { - /* - * XXX would be more failsafe to change directory to a - * deadfs node here instead - */ - vrele(cwdi->cwdi_cdir); - VREF(vp); - cwdi->cwdi_cdir = vp; - } - - if (cwdi->cwdi_rdir != NULL) - vrele(cwdi->cwdi_rdir); - cwdi->cwdi_rdir = vp; - rw_exit(&cwdi->cwdi_lock); + change_root(p->p_cwdi, vp, l); out: fd_putfile(fd); @@ -1188,16 +1166,15 @@ struct proc *p = l->l_proc; struct cwdinfo *cwdi; int error; - struct nameidata nd; + struct vnode *vp; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, - SCARG(uap, path)); - if ((error = change_dir(&nd, l)) != 0) + if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, + &vp, l)) != 0) return (error); cwdi = p->p_cwdi; rw_enter(&cwdi->cwdi_lock, RW_WRITER); vrele(cwdi->cwdi_cdir); - cwdi->cwdi_cdir = nd.ni_vp; + cwdi->cwdi_cdir = vp; rw_exit(&cwdi->cwdi_lock); return (0); } @@ -1213,24 +1190,31 @@ syscallarg(const char *) path; } */ struct proc *p = l->l_proc; - struct cwdinfo *cwdi; - struct vnode *vp; int error; - struct nameidata nd; + struct vnode *vp; if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT, KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0) return (error); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, - SCARG(uap, path)); - if ((error = change_dir(&nd, l)) != 0) + if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, + &vp, l)) != 0) return (error); - cwdi = p->p_cwdi; + change_root(p->p_cwdi, vp, l); + + return (0); +} + +/* + * Common routine for chroot and fchroot. + */ +void +change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l) +{ + rw_enter(&cwdi->cwdi_lock, RW_WRITER); if (cwdi->cwdi_rdir != NULL) vrele(cwdi->cwdi_rdir); - vp = nd.ni_vp; cwdi->cwdi_rdir = vp; /* @@ -1248,31 +1232,31 @@ cwdi->cwdi_cdir = vp; } rw_exit(&cwdi->cwdi_lock); - - return (0); } /* * Common routine for chroot and chdir. */ -static int -change_dir(struct nameidata *ndp, struct lwp *l) +int +chdir_lookup(const char *path, int where, struct vnode **vpp, struct lwp *l) { - struct vnode *vp; + struct nameidata nd; int error; - if ((error = namei(ndp)) != 0) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, where, + path); + if ((error = namei(&nd)) != 0) return (error); - vp = ndp->ni_vp; - if (vp->v_type != VDIR) + *vpp = nd.ni_vp; + if ((*vpp)->v_type != VDIR) error = ENOTDIR; else - error = VOP_ACCESS(vp, VEXEC, l->l_cred); + error = VOP_ACCESS(*vpp, VEXEC, l->l_cred); if (error) - vput(vp); + vput(*vpp); else - VOP_UNLOCK(vp, 0); + VOP_UNLOCK(*vpp, 0); return (error); } Index: src/sys/sys/vfs_syscalls.h diff -u src/sys/sys/vfs_syscalls.h:1.11 src/sys/sys/vfs_syscalls.h:1.12 --- src/sys/sys/vfs_syscalls.h:1.11 Thu Jul 2 12:56:40 2009 +++ src/sys/sys/vfs_syscalls.h Sat Aug 1 21:17:12 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_syscalls.h,v 1.11 2009/07/02 12:56:40 pooka Exp $ */ +/* $NetBSD: vfs_syscalls.h,v 1.12 2009/08/01 21:17:12 bad Exp $ */ /* * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -65,4 +65,7 @@ int do_sys_mknod(struct lwp *l, const char *, mode_t, dev_t, register_t *); int do_sys_mkdir(const char *, mode_t); +int chdir_lookup(const char *, int, struct vnode **, struct lwp *); +void change_root(struct cwdinfo *, struct vnode *, struct lwp *); + #endif /* _SYS_VFS_SYSCALLS_H_ */