From 85078b8573332c2c83a79adea8a61b519fb3b6af Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Tue, 17 Nov 2020 21:14:13 +0000 Subject: [PATCH] Split out cwd/root/jail, cmask state from filedesc table No functional change intended. Tracking these structures separately for each proc enables future work to correctly emulate clone(2) in linux(4). __FreeBSD_version is bumped (to 1300130) for consumption by, e.g., lsof. Reviewed by: kib Discussed with: markj, mjg Differential Revision: https://reviews.freebsd.org/D27037 --- lib/libkvm/kvm_proc.c | 1 + lib/libprocstat/libprocstat.c | 20 +- sys/compat/cloudabi/cloudabi_file.c | 2 +- sys/fs/fuse/fuse_internal.c | 2 +- sys/fs/fuse/fuse_vnops.c | 4 +- sys/fs/unionfs/union_subr.c | 2 +- sys/kern/imgact_elf.c | 6 +- sys/kern/init_main.c | 1 + sys/kern/kern_descrip.c | 328 ++++++++++++++++++++-------- sys/kern/kern_exec.c | 1 + sys/kern/kern_exit.c | 1 + sys/kern/kern_fork.c | 13 +- sys/kern/kern_proc.c | 9 +- sys/kern/kern_thread.c | 20 +- sys/kern/uipc_mqueue.c | 6 +- sys/kern/uipc_sem.c | 6 +- sys/kern/uipc_shm.c | 6 +- sys/kern/uipc_usrreq.c | 2 +- sys/kern/vfs_syscalls.c | 27 ++- sys/sys/filedesc.h | 69 +++--- sys/sys/param.h | 2 +- sys/sys/proc.h | 1 + sys/sys/user.h | 3 +- 23 files changed, 355 insertions(+), 177 deletions(-) diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c index c97a347decd7..71cfd5f1629b 100644 --- a/lib/libkvm/kvm_proc.c +++ b/lib/libkvm/kvm_proc.c @@ -221,6 +221,7 @@ kvm_proclist(kvm_t *kd, int what, int arg, struct proc *p, kp->ki_tracep = proc.p_tracevp; kp->ki_textvp = proc.p_textvp; kp->ki_fd = proc.p_fd; + kp->ki_pd = proc.p_pd; kp->ki_vmspace = proc.p_vmspace; if (proc.p_sigacts != NULL) { if (KREAD(kd, (u_long)proc.p_sigacts, &sigacts)) { diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 7be6a224eb82..a3545b919896 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -460,6 +460,7 @@ procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmap { struct file file; struct filedesc filed; + struct pwddesc pathsd; struct fdescenttbl *fdt; struct pwd pwd; unsigned long pwd_addr; @@ -484,15 +485,20 @@ procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmap kd = procstat->kd; if (kd == NULL) return (NULL); - if (kp->ki_fd == NULL) + if (kp->ki_fd == NULL || kp->ki_pd == NULL) return (NULL); if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed, sizeof(filed))) { warnx("can't read filedesc at %p", (void *)kp->ki_fd); return (NULL); } + if (!kvm_read_all(kd, (unsigned long)kp->ki_pd, &pathsd, + sizeof(pathsd))) { + warnx("can't read pwddesc at %p", (void *)kp->ki_pd); + return (NULL); + } haspwd = false; - pwd_addr = (unsigned long)(FILEDESC_KVM_LOAD_PWD(&filed)); + pwd_addr = (unsigned long)(PWDDESC_KVM_LOAD_PWD(&pathsd)); if (pwd_addr != 0) { if (!kvm_read_all(kd, pwd_addr, &pwd, sizeof(pwd))) { warnx("can't read fd_pwd at %p", (void *)pwd_addr); @@ -2086,18 +2092,18 @@ procstat_freegroups(struct procstat *procstat __unused, gid_t *groups) static int procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp) { - struct filedesc fd; + struct pwddesc pd; assert(kd != NULL); assert(kp != NULL); - if (kp->ki_fd == NULL) + if (kp->ki_pd == NULL) return (-1); - if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) { - warnx("can't read filedesc at %p for pid %d", kp->ki_fd, + if (!kvm_read_all(kd, (unsigned long)kp->ki_pd, &pd, sizeof(pd))) { + warnx("can't read pwddesc at %p for pid %d", kp->ki_pd, kp->ki_pid); return (-1); } - *maskp = fd.fd_cmask; + *maskp = pd.pd_cmask; return (0); } diff --git a/sys/compat/cloudabi/cloudabi_file.c b/sys/compat/cloudabi/cloudabi_file.c index f3b33299b19e..f7d93bc85cad 100644 --- a/sys/compat/cloudabi/cloudabi_file.c +++ b/sys/compat/cloudabi/cloudabi_file.c @@ -265,7 +265,7 @@ cloudabi_sys_file_open(struct thread *td, } NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, uap->dirfd.fd, &rights, td); - error = vn_open(&nd, &fflags, 0777 & ~td->td_proc->p_fd->fd_cmask, fp); + error = vn_open(&nd, &fflags, 0777 & ~td->td_proc->p_pd->pd_cmask, fp); cloudabi_freestr(path); if (error != 0) { /* Custom operations provided. */ diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c index 731bb9b2b13c..79365b8802df 100644 --- a/sys/fs/fuse/fuse_internal.c +++ b/sys/fs/fuse/fuse_internal.c @@ -497,7 +497,7 @@ fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp, fmni.rdev = vap->va_rdev; if (fuse_libabi_geq(data, 7, 12)) { insize = sizeof(fmni); - fmni.umask = curthread->td_proc->p_fd->fd_cmask; + fmni.umask = curthread->td_proc->p_pd->pd_cmask; } else { insize = FUSE_COMPAT_MKNOD_IN_SIZE; } diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index df29a3079ade..fde673d1f5f3 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -668,7 +668,7 @@ fuse_vnop_create(struct vop_create_args *ap) fci->flags = O_CREAT | flags; if (fuse_libabi_geq(data, 7, 12)) { insize = sizeof(*fci); - fci->umask = td->td_proc->p_fd->fd_cmask; + fci->umask = td->td_proc->p_pd->pd_cmask; } else { insize = sizeof(struct fuse_open_in); } @@ -1269,7 +1269,7 @@ fuse_vnop_mkdir(struct vop_mkdir_args *ap) return ENXIO; } fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode); - fmdi.umask = curthread->td_proc->p_fd->fd_cmask; + fmdi.umask = curthread->td_proc->p_pd->pd_cmask; return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi, sizeof(fmdi), VDIR)); diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index 09064f16550d..30b637171021 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -486,7 +486,7 @@ unionfs_create_uppervattr_core(struct unionfs_mount *ump, } break; default: /* UNIONFS_TRADITIONAL */ - uva->va_mode = 0777 & ~td->td_proc->p_fd->fd_cmask; + uva->va_mode = 0777 & ~td->td_proc->p_pd->pd_cmask; uva->va_uid = ump->um_uid; uva->va_gid = ump->um_gid; break; diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 41e69caa0fb8..fc1b7bf1a53a 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -2507,12 +2507,12 @@ note_procstat_umask(void *arg, struct sbuf *sb, size_t *sizep) int structsize; p = (struct proc *)arg; - size = sizeof(structsize) + sizeof(p->p_fd->fd_cmask); + size = sizeof(structsize) + sizeof(p->p_pd->pd_cmask); if (sb != NULL) { KASSERT(*sizep == size, ("invalid size")); - structsize = sizeof(p->p_fd->fd_cmask); + structsize = sizeof(p->p_pd->pd_cmask); sbuf_bcat(sb, &structsize, sizeof(structsize)); - sbuf_bcat(sb, &p->p_fd->fd_cmask, sizeof(p->p_fd->fd_cmask)); + sbuf_bcat(sb, &p->p_pd->pd_cmask, sizeof(p->p_pd->pd_cmask)); } *sizep = size; } diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 9c81e0c9f909..627a53cc74b3 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -555,6 +555,7 @@ proc0_init(void *dummy __unused) siginit(&proc0); /* Create the file descriptor table. */ + p->p_pd = pdinit(NULL, false); p->p_fd = fdinit(NULL, false, NULL); p->p_fdtol = NULL; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index a567a5ccbc20..ab36bb1657b5 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$"); static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table"); static MALLOC_DEFINE(M_PWD, "pwd", "Descriptor table vnodes"); +static MALLOC_DEFINE(M_PWDDESC, "pwddesc", "Pwd descriptors"); static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader", "file desc to leader structures"); static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures"); @@ -2029,7 +2030,6 @@ finstall(struct thread *td, struct file *fp, int *fd, int flags, /* * Build a new filedesc structure from another. - * Copy the current, root, and jail root vnode references. * * If fdp is not NULL, return with it shared locked. */ @@ -2038,7 +2038,6 @@ fdinit(struct filedesc *fdp, bool prepfiles, int *lastfile) { struct filedesc0 *newfdp0; struct filedesc *newfdp; - struct pwd *newpwd; if (prepfiles) MPASS(lastfile != NULL); @@ -2052,20 +2051,14 @@ fdinit(struct filedesc *fdp, bool prepfiles, int *lastfile) FILEDESC_LOCK_INIT(newfdp); refcount_init(&newfdp->fd_refcnt, 1); refcount_init(&newfdp->fd_holdcnt, 1); - newfdp->fd_cmask = CMASK; newfdp->fd_map = newfdp0->fd_dmap; newfdp->fd_files = (struct fdescenttbl *)&newfdp0->fd_dfiles; newfdp->fd_files->fdt_nfiles = NDFILE; - if (fdp == NULL) { - newpwd = pwd_alloc(); - smr_serialized_store(&newfdp->fd_pwd, newpwd, true); + if (fdp == NULL) return (newfdp); - } FILEDESC_SLOCK(fdp); - newpwd = pwd_hold_filedesc(fdp); - smr_serialized_store(&newfdp->fd_pwd, newpwd, true); if (!prepfiles) { FILEDESC_SUNLOCK(fdp); return (newfdp); @@ -2083,6 +2076,38 @@ fdinit(struct filedesc *fdp, bool prepfiles, int *lastfile) return (newfdp); } +/* + * Build a pwddesc structure from another. + * Copy the current, root, and jail root vnode references. + * + * If pdp is not NULL, return with it shared locked. + */ +struct pwddesc * +pdinit(struct pwddesc *pdp, bool keeplock) +{ + struct pwddesc *newpdp; + struct pwd *newpwd; + + newpdp = malloc(sizeof(*newpdp), M_PWDDESC, M_WAITOK | M_ZERO); + + PWDDESC_LOCK_INIT(newpdp); + refcount_init(&newpdp->pd_refcount, 1); + newpdp->pd_cmask = CMASK; + + if (pdp == NULL) { + newpwd = pwd_alloc(); + smr_serialized_store(&newpdp->pd_pwd, newpwd, true); + return (newpdp); + } + + PWDDESC_XLOCK(pdp); + newpwd = pwd_hold_pwddesc(pdp); + smr_serialized_store(&newpdp->pd_pwd, newpwd, true); + if (!keeplock) + PWDDESC_XUNLOCK(pdp); + return (newpdp); +} + static struct filedesc * fdhold(struct proc *p) { @@ -2095,6 +2120,18 @@ fdhold(struct proc *p) return (fdp); } +static struct pwddesc * +pdhold(struct proc *p) +{ + struct pwddesc *pdp; + + PROC_LOCK_ASSERT(p, MA_OWNED); + pdp = p->p_pd; + if (pdp != NULL) + refcount_acquire(&pdp->pd_refcount); + return (pdp); +} + static void fddrop(struct filedesc *fdp) { @@ -2108,6 +2145,28 @@ fddrop(struct filedesc *fdp) uma_zfree(filedesc0_zone, fdp); } +static void +pddrop(struct pwddesc *pdp) +{ + struct pwd *pwd; + + if (refcount_release_if_not_last(&pdp->pd_refcount)) + return; + + PWDDESC_XLOCK(pdp); + if (refcount_release(&pdp->pd_refcount) == 0) { + PWDDESC_XUNLOCK(pdp); + return; + } + pwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); + pwd_set(pdp, NULL); + PWDDESC_XUNLOCK(pdp); + pwd_drop(pwd); + + PWDDESC_LOCK_DESTROY(pdp); + free(pdp, M_PWDDESC); +} + /* * Share a filedesc structure. */ @@ -2119,6 +2178,16 @@ fdshare(struct filedesc *fdp) return (fdp); } +/* + * Share a pwddesc structure. + */ +struct pwddesc * +pdshare(struct pwddesc *pdp) +{ + refcount_acquire(&pdp->pd_refcount); + return (pdp); +} + /* * Unshare a filedesc structure, if necessary by making a copy */ @@ -2136,6 +2205,25 @@ fdunshare(struct thread *td) p->p_fd = tmp; } +/* + * Unshare a pwddesc structure. + */ +void +pdunshare(struct thread *td) +{ + struct pwddesc *pdp; + struct proc *p; + + p = td->td_proc; + /* Not shared. */ + if (p->p_pd->pd_refcount == 1) + return; + + pdp = pdcopy(p->p_pd); + pdescfree(td); + p->p_pd = pdp; +} + void fdinstall_remapped(struct thread *td, struct filedesc *fdp) { @@ -2176,11 +2264,26 @@ fdcopy(struct filedesc *fdp) } if (newfdp->fd_freefile == -1) newfdp->fd_freefile = i; - newfdp->fd_cmask = fdp->fd_cmask; FILEDESC_SUNLOCK(fdp); return (newfdp); } +/* + * Copy a pwddesc structure. + */ +struct pwddesc * +pdcopy(struct pwddesc *pdp) +{ + struct pwddesc *newpdp; + + MPASS(pdp != NULL); + + newpdp = pdinit(pdp, true); + newpdp->pd_cmask = pdp->pd_cmask; + PWDDESC_XUNLOCK(pdp); + return (newpdp); +} + /* * Copies a filedesc structure, while remapping all file descriptors * stored inside using a translation table. @@ -2232,7 +2335,6 @@ fdcopy_remapped(struct filedesc *fdp, const int *fds, size_t nfds, filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); fdused_init(newfdp, i); } - newfdp->fd_cmask = fdp->fd_cmask; FILEDESC_SUNLOCK(fdp); *ret = newfdp; return (0); @@ -2366,7 +2468,6 @@ fdescfree(struct thread *td) { struct proc *p; struct filedesc *fdp; - struct pwd *pwd; p = td->td_proc; fdp = p->p_fd; @@ -2387,21 +2488,29 @@ fdescfree(struct thread *td) if (refcount_release(&fdp->fd_refcnt) == 0) return; - FILEDESC_XLOCK(fdp); - pwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); - pwd_set(fdp, NULL); - FILEDESC_XUNLOCK(fdp); - - pwd_drop(pwd); - fdescfree_fds(td, fdp, 1); } +void +pdescfree(struct thread *td) +{ + struct proc *p; + struct pwddesc *pdp; + + p = td->td_proc; + pdp = p->p_pd; + MPASS(pdp != NULL); + + PROC_LOCK(p); + p->p_pd = NULL; + PROC_UNLOCK(p); + + pddrop(pdp); +} + void fdescfree_remapped(struct filedesc *fdp) { - - pwd_drop(smr_serialized_load(&fdp->fd_pwd, true)); fdescfree_fds(curthread, fdp, 0); } @@ -3452,12 +3561,12 @@ pwd_fill(struct pwd *oldpwd, struct pwd *newpwd) } struct pwd * -pwd_hold_filedesc(struct filedesc *fdp) +pwd_hold_pwddesc(struct pwddesc *pdp) { struct pwd *pwd; - FILEDESC_LOCK_ASSERT(fdp); - pwd = FILEDESC_LOCKED_LOAD_PWD(fdp); + PWDDESC_ASSERT_XLOCKED(pdp); + pwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); if (pwd != NULL) refcount_acquire(&pwd->pwd_refcount); return (pwd); @@ -3477,22 +3586,22 @@ pwd_hold_smr(struct pwd *pwd) struct pwd * pwd_hold(struct thread *td) { - struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *pwd; - fdp = td->td_proc->p_fd; + pdp = td->td_proc->p_pd; vfs_smr_enter(); - pwd = vfs_smr_entered_load(&fdp->fd_pwd); + pwd = vfs_smr_entered_load(&pdp->pd_pwd); if (pwd_hold_smr(pwd)) { vfs_smr_exit(); return (pwd); } vfs_smr_exit(); - FILEDESC_SLOCK(fdp); - pwd = pwd_hold_filedesc(fdp); + PWDDESC_XLOCK(pdp); + pwd = pwd_hold_pwddesc(pdp); MPASS(pwd != NULL); - FILEDESC_SUNLOCK(fdp); + PWDDESC_XUNLOCK(pdp); return (pwd); } @@ -3501,7 +3610,7 @@ pwd_get_smr(void) { struct pwd *pwd; - pwd = vfs_smr_entered_load(&curproc->p_fd->fd_pwd); + pwd = vfs_smr_entered_load(&curproc->p_pd->pd_pwd); MPASS(pwd != NULL); return (pwd); } @@ -3541,23 +3650,29 @@ pwd_drop(struct pwd *pwd) int pwd_chroot(struct thread *td, struct vnode *vp) { + struct pwddesc *pdp; struct filedesc *fdp; struct pwd *newpwd, *oldpwd; int error; fdp = td->td_proc->p_fd; + pdp = td->td_proc->p_pd; newpwd = pwd_alloc(); - FILEDESC_XLOCK(fdp); - oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); + FILEDESC_SLOCK(fdp); + PWDDESC_XLOCK(pdp); + oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); if (chroot_allow_open_directories == 0 || (chroot_allow_open_directories == 1 && oldpwd->pwd_rdir != rootvnode)) { error = chroot_refuse_vdir_fds(fdp); + FILEDESC_SUNLOCK(fdp); if (error != 0) { - FILEDESC_XUNLOCK(fdp); + PWDDESC_XUNLOCK(pdp); pwd_drop(newpwd); return (error); } + } else { + FILEDESC_SUNLOCK(fdp); } vrefact(vp); @@ -3567,8 +3682,8 @@ pwd_chroot(struct thread *td, struct vnode *vp) newpwd->pwd_jdir = vp; } pwd_fill(oldpwd, newpwd); - pwd_set(fdp, newpwd); - FILEDESC_XUNLOCK(fdp); + pwd_set(pdp, newpwd); + PWDDESC_XUNLOCK(pdp); pwd_drop(oldpwd); return (0); } @@ -3576,40 +3691,40 @@ pwd_chroot(struct thread *td, struct vnode *vp) void pwd_chdir(struct thread *td, struct vnode *vp) { - struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *newpwd, *oldpwd; VNPASS(vp->v_usecount > 0, vp); newpwd = pwd_alloc(); - fdp = td->td_proc->p_fd; - FILEDESC_XLOCK(fdp); - oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); + pdp = td->td_proc->p_pd; + PWDDESC_XLOCK(pdp); + oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); newpwd->pwd_cdir = vp; pwd_fill(oldpwd, newpwd); - pwd_set(fdp, newpwd); - FILEDESC_XUNLOCK(fdp); + pwd_set(pdp, newpwd); + PWDDESC_XUNLOCK(pdp); pwd_drop(oldpwd); } void pwd_ensure_dirs(void) { - struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *oldpwd, *newpwd; - fdp = curproc->p_fd; - FILEDESC_XLOCK(fdp); - oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); + pdp = curproc->p_pd; + PWDDESC_XLOCK(pdp); + oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); if (oldpwd->pwd_cdir != NULL && oldpwd->pwd_rdir != NULL) { - FILEDESC_XUNLOCK(fdp); + PWDDESC_XUNLOCK(pdp); return; } - FILEDESC_XUNLOCK(fdp); + PWDDESC_XUNLOCK(pdp); newpwd = pwd_alloc(); - FILEDESC_XLOCK(fdp); - oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); + PWDDESC_XLOCK(pdp); + oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); pwd_fill(oldpwd, newpwd); if (newpwd->pwd_cdir == NULL) { vrefact(rootvnode); @@ -3619,29 +3734,29 @@ pwd_ensure_dirs(void) vrefact(rootvnode); newpwd->pwd_rdir = rootvnode; } - pwd_set(fdp, newpwd); - FILEDESC_XUNLOCK(fdp); + pwd_set(pdp, newpwd); + PWDDESC_XUNLOCK(pdp); pwd_drop(oldpwd); } void pwd_set_rootvnode(void) { - struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *oldpwd, *newpwd; - fdp = curproc->p_fd; + pdp = curproc->p_pd; newpwd = pwd_alloc(); - FILEDESC_XLOCK(fdp); - oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); + PWDDESC_XLOCK(pdp); + oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); vrefact(rootvnode); newpwd->pwd_cdir = rootvnode; vrefact(rootvnode); newpwd->pwd_rdir = rootvnode; pwd_fill(oldpwd, newpwd); - pwd_set(fdp, newpwd); - FILEDESC_XUNLOCK(fdp); + pwd_set(pdp, newpwd); + PWDDESC_XUNLOCK(pdp); pwd_drop(oldpwd); } @@ -3652,7 +3767,7 @@ pwd_set_rootvnode(void) void mountcheckdirs(struct vnode *olddp, struct vnode *newdp) { - struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *newpwd, *oldpwd; struct prison *pr; struct proc *p; @@ -3665,18 +3780,18 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp) sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { PROC_LOCK(p); - fdp = fdhold(p); + pdp = pdhold(p); PROC_UNLOCK(p); - if (fdp == NULL) + if (pdp == NULL) continue; - FILEDESC_XLOCK(fdp); - oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp); + PWDDESC_XLOCK(pdp); + oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); if (oldpwd == NULL || (oldpwd->pwd_cdir != olddp && oldpwd->pwd_rdir != olddp && oldpwd->pwd_jdir != olddp)) { - FILEDESC_XUNLOCK(fdp); - fddrop(fdp); + PWDDESC_XUNLOCK(pdp); + pddrop(pdp); continue; } if (oldpwd->pwd_cdir == olddp) { @@ -3692,10 +3807,10 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp) newpwd->pwd_jdir = newdp; } pwd_fill(oldpwd, newpwd); - pwd_set(fdp, newpwd); - FILEDESC_XUNLOCK(fdp); + pwd_set(pdp, newpwd); + PWDDESC_XUNLOCK(pdp); pwd_drop(oldpwd); - fddrop(fdp); + pddrop(pdp); newpwd = pwd_alloc(); } sx_sunlock(&allproc_lock); @@ -3968,6 +4083,7 @@ export_vnode_to_kinfo(struct vnode *vp, int fd, int fflags, struct export_fd_buf { struct filedesc *fdp; + struct pwddesc *pdp; struct sbuf *sb; ssize_t remainder; struct kinfo_file kif; @@ -4015,12 +4131,12 @@ export_vnode_to_sb(struct vnode *vp, int fd, int fflags, if (efbuf->remainder == 0) return (0); - if (efbuf->fdp != NULL) - FILEDESC_SUNLOCK(efbuf->fdp); + if (efbuf->pdp != NULL) + PWDDESC_XUNLOCK(efbuf->pdp); export_vnode_to_kinfo(vp, fd, fflags, &efbuf->kif, efbuf->flags); error = export_kinfo_to_sb(efbuf); - if (efbuf->fdp != NULL) - FILEDESC_SLOCK(efbuf->fdp); + if (efbuf->pdp != NULL) + PWDDESC_XLOCK(efbuf->pdp); return (error); } @@ -4035,6 +4151,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, { struct file *fp; struct filedesc *fdp; + struct pwddesc *pdp; struct export_fd_buf *efbuf; struct vnode *cttyvp, *textvp, *tracevp; struct pwd *pwd; @@ -4059,9 +4176,11 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, vrefact(cttyvp); } fdp = fdhold(p); + pdp = pdhold(p); PROC_UNLOCK(p); efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK); efbuf->fdp = NULL; + efbuf->pdp = NULL; efbuf->sb = sb; efbuf->remainder = maxlen; efbuf->flags = flags; @@ -4074,11 +4193,12 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, export_vnode_to_sb(cttyvp, KF_FD_TYPE_CTTY, FREAD | FWRITE, efbuf); error = 0; - if (fdp == NULL) + if (pdp == NULL || fdp == NULL) goto fail; efbuf->fdp = fdp; - FILEDESC_SLOCK(fdp); - pwd = pwd_hold_filedesc(fdp); + efbuf->pdp = pdp; + PWDDESC_XLOCK(pdp); + pwd = pwd_hold_pwddesc(pdp); if (pwd != NULL) { /* working directory */ if (pwd->pwd_cdir != NULL) { @@ -4096,6 +4216,10 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, export_vnode_to_sb(pwd->pwd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf); } } + PWDDESC_XUNLOCK(pdp); + if (pwd != NULL) + pwd_drop(pwd); + FILEDESC_SLOCK(fdp); lastfile = fdlastfile(fdp); for (i = 0; fdp->fd_refcnt > 0 && i <= lastfile; i++) { if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) @@ -4116,10 +4240,11 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, break; } FILEDESC_SUNLOCK(fdp); - if (pwd != NULL) - pwd_drop(pwd); - fddrop(fdp); fail: + if (fdp != NULL) + fddrop(fdp); + if (pdp != NULL) + pddrop(pdp); free(efbuf, M_TEMP); return (error); } @@ -4190,16 +4315,16 @@ kinfo_to_okinfo(struct kinfo_file *kif, struct kinfo_ofile *okif) static int export_vnode_for_osysctl(struct vnode *vp, int type, struct kinfo_file *kif, - struct kinfo_ofile *okif, struct filedesc *fdp, struct sysctl_req *req) + struct kinfo_ofile *okif, struct pwddesc *pdp, struct sysctl_req *req) { int error; vrefact(vp); - FILEDESC_SUNLOCK(fdp); + PWDDESC_XUNLOCK(pdp); export_vnode_to_kinfo(vp, type, 0, kif, KERN_FILEDESC_PACK_KINFO); kinfo_to_okinfo(kif, okif); error = SYSCTL_OUT(req, okif, sizeof(*okif)); - FILEDESC_SLOCK(fdp); + PWDDESC_XLOCK(pdp); return (error); } @@ -4212,6 +4337,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) struct kinfo_ofile *okif; struct kinfo_file *kif; struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *pwd; int error, i, lastfile, *name; struct file *fp; @@ -4222,24 +4348,33 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) if (error != 0) return (error); fdp = fdhold(p); + if (fdp != NULL) + pdp = pdhold(p); PROC_UNLOCK(p); - if (fdp == NULL) + if (fdp == NULL || pdp == NULL) { + if (fdp != NULL) + fddrop(fdp); return (ENOENT); + } kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK); okif = malloc(sizeof(*okif), M_TEMP, M_WAITOK); - FILEDESC_SLOCK(fdp); - pwd = pwd_hold_filedesc(fdp); + PWDDESC_XLOCK(pdp); + pwd = pwd_hold_pwddesc(pdp); if (pwd != NULL) { if (pwd->pwd_cdir != NULL) export_vnode_for_osysctl(pwd->pwd_cdir, KF_FD_TYPE_CWD, kif, - okif, fdp, req); + okif, pdp, req); if (pwd->pwd_rdir != NULL) export_vnode_for_osysctl(pwd->pwd_rdir, KF_FD_TYPE_ROOT, kif, - okif, fdp, req); + okif, pdp, req); if (pwd->pwd_jdir != NULL) export_vnode_for_osysctl(pwd->pwd_jdir, KF_FD_TYPE_JAIL, kif, - okif, fdp, req); + okif, pdp, req); } + PWDDESC_XUNLOCK(pdp); + if (pwd != NULL) + pwd_drop(pwd); + FILEDESC_SLOCK(fdp); lastfile = fdlastfile(fdp); for (i = 0; fdp->fd_refcnt > 0 && i <= lastfile; i++) { if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) @@ -4254,9 +4389,8 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) break; } FILEDESC_SUNLOCK(fdp); - if (pwd != NULL) - pwd_drop(pwd); fddrop(fdp); + pddrop(pdp); free(kif, M_TEMP); free(okif, M_TEMP); return (0); @@ -4308,7 +4442,7 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc, int kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) { - struct filedesc *fdp; + struct pwddesc *pdp; struct pwd *pwd; struct export_fd_buf *efbuf; struct vnode *cdir; @@ -4316,18 +4450,18 @@ kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) PROC_LOCK_ASSERT(p, MA_OWNED); - fdp = fdhold(p); + pdp = pdhold(p); PROC_UNLOCK(p); - if (fdp == NULL) + if (pdp == NULL) return (EINVAL); efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK); - efbuf->fdp = fdp; + efbuf->pdp = pdp; efbuf->sb = sb; efbuf->remainder = maxlen; - FILEDESC_SLOCK(fdp); - pwd = FILEDESC_LOCKED_LOAD_PWD(fdp); + PWDDESC_XLOCK(pdp); + pwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); cdir = pwd->pwd_cdir; if (cdir == NULL) { error = EINVAL; @@ -4335,8 +4469,8 @@ kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) vrefact(cdir); error = export_vnode_to_sb(cdir, KF_FD_TYPE_CWD, FREAD, efbuf); } - FILEDESC_SUNLOCK(fdp); - fddrop(fdp); + PWDDESC_XUNLOCK(pdp); + pddrop(pdp); free(efbuf, M_TEMP); return (error); } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 45f79a6a5d25..6b33a5b63181 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -700,6 +700,7 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p, * cannot be shared after an exec. */ fdunshare(td); + pdunshare(td); /* close files on exec */ fdcloseexec(td); } diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index c81878742b75..dcd0b4ddea32 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -367,6 +367,7 @@ exit1(struct thread *td, int rval, int signo) * Close open files and release open-file table. * This may block! */ + pdescfree(td); fdescfree(td); /* diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 59032d57678c..25b6132e3511 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -332,16 +332,22 @@ fork_norfproc(struct thread *td, int flags) */ if (flags & RFCFDG) { struct filedesc *fdtmp; + struct pwddesc *pdtmp; + pdtmp = pdinit(td->td_proc->p_pd, false); fdtmp = fdinit(td->td_proc->p_fd, false, NULL); + pdescfree(td); fdescfree(td); p1->p_fd = fdtmp; + p1->p_pd = pdtmp; } /* * Unshare file descriptors (from parent). */ - if (flags & RFFDG) + if (flags & RFFDG) { fdunshare(td); + pdunshare(td); + } fail: if (((p1->p_flag & (P_HADTHREADS|P_SYSTEM)) == P_HADTHREADS) && @@ -360,6 +366,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * struct proc *p1, *pptr; struct filedesc *fd; struct filedesc_to_leader *fdtol; + struct pwddesc *pd; struct sigacts *newsigacts; p1 = td->td_proc; @@ -403,12 +410,15 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * * Copy filedesc. */ if (fr->fr_flags & RFCFDG) { + pd = pdinit(p1->p_pd, false); fd = fdinit(p1->p_fd, false, NULL); fdtol = NULL; } else if (fr->fr_flags & RFFDG) { + pd = pdcopy(p1->p_pd); fd = fdcopy(p1->p_fd); fdtol = NULL; } else { + pd = pdshare(p1->p_pd); fd = fdshare(p1->p_fd); if (p1->p_fdtol == NULL) p1->p_fdtol = filedesc_to_leader_alloc(NULL, NULL, @@ -498,6 +508,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * p2->p_textvp = p1->p_textvp; p2->p_fd = fd; p2->p_fdtol = fdtol; + p2->p_pd = pd; if (p1->p_flag2 & P2_INHERIT_PROTECTED) { p2->p_flag |= P_PROTECTED; diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 7d2b406135d3..7231c34cb8c7 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -1144,6 +1144,7 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp) kp->ki_traceflag = p->p_traceflag; #endif kp->ki_fd = p->p_fd; + kp->ki_pd = p->p_pd; kp->ki_vmspace = p->p_vmspace; kp->ki_flag = p->p_flag; kp->ki_flag2 = p->p_flag2; @@ -2967,7 +2968,7 @@ sysctl_kern_proc_umask(SYSCTL_HANDLER_ARGS) u_int namelen = arg2; struct proc *p; int error; - u_short fd_cmask; + u_short cmask; pid_t pid; if (namelen != 1) @@ -2976,7 +2977,7 @@ sysctl_kern_proc_umask(SYSCTL_HANDLER_ARGS) pid = (pid_t)name[0]; p = curproc; if (pid == p->p_pid || pid == 0) { - fd_cmask = p->p_fd->fd_cmask; + cmask = p->p_pd->pd_cmask; goto out; } @@ -2984,10 +2985,10 @@ sysctl_kern_proc_umask(SYSCTL_HANDLER_ARGS) if (error != 0) return (error); - fd_cmask = p->p_fd->fd_cmask; + cmask = p->p_pd->pd_cmask; PRELE(p); out: - error = SYSCTL_OUT(req, &fd_cmask, sizeof(fd_cmask)); + error = SYSCTL_OUT(req, &cmask, sizeof(cmask)); return (error); } diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 654d3a6c3b05..2c3d1cf5a8c9 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -88,15 +88,15 @@ _Static_assert(offsetof(struct thread, td_frame) == 0x4a0, "struct thread KBI td_frame"); _Static_assert(offsetof(struct thread, td_emuldata) == 0x6b0, "struct thread KBI td_emuldata"); -_Static_assert(offsetof(struct proc, p_flag) == 0xb0, +_Static_assert(offsetof(struct proc, p_flag) == 0xb8, "struct proc KBI p_flag"); -_Static_assert(offsetof(struct proc, p_pid) == 0xbc, +_Static_assert(offsetof(struct proc, p_pid) == 0xc4, "struct proc KBI p_pid"); -_Static_assert(offsetof(struct proc, p_filemon) == 0x3b8, +_Static_assert(offsetof(struct proc, p_filemon) == 0x3c0, "struct proc KBI p_filemon"); -_Static_assert(offsetof(struct proc, p_comm) == 0x3d0, +_Static_assert(offsetof(struct proc, p_comm) == 0x3d8, "struct proc KBI p_comm"); -_Static_assert(offsetof(struct proc, p_emuldata) == 0x4b0, +_Static_assert(offsetof(struct proc, p_emuldata) == 0x4b8, "struct proc KBI p_emuldata"); #endif #ifdef __i386__ @@ -108,15 +108,15 @@ _Static_assert(offsetof(struct thread, td_frame) == 0x300, "struct thread KBI td_frame"); _Static_assert(offsetof(struct thread, td_emuldata) == 0x344, "struct thread KBI td_emuldata"); -_Static_assert(offsetof(struct proc, p_flag) == 0x68, +_Static_assert(offsetof(struct proc, p_flag) == 0x6c, "struct proc KBI p_flag"); -_Static_assert(offsetof(struct proc, p_pid) == 0x74, +_Static_assert(offsetof(struct proc, p_pid) == 0x78, "struct proc KBI p_pid"); -_Static_assert(offsetof(struct proc, p_filemon) == 0x268, +_Static_assert(offsetof(struct proc, p_filemon) == 0x26c, "struct proc KBI p_filemon"); -_Static_assert(offsetof(struct proc, p_comm) == 0x27c, +_Static_assert(offsetof(struct proc, p_comm) == 0x280, "struct proc KBI p_comm"); -_Static_assert(offsetof(struct proc, p_emuldata) == 0x308, +_Static_assert(offsetof(struct proc, p_emuldata) == 0x30c, "struct proc KBI p_emuldata"); #endif diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index faf8f4ed25c8..72af4bc07144 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -2011,7 +2011,7 @@ kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode, { char path[MQFS_NAMELEN + 1]; struct mqfs_node *pn; - struct filedesc *fdp; + struct pwddesc *pdp; struct file *fp; struct mqueue *mq; int fd, error, len, cmode; @@ -2019,8 +2019,8 @@ kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode, AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); - fdp = td->td_proc->p_fd; - cmode = (((mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT); + pdp = td->td_proc->p_pd; + cmode = (((mode & ~pdp->pd_cmask) & ALLPERMS) & ~S_ISTXT); mq = NULL; if ((flags & O_CREAT) != 0 && attr != NULL) { if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > maxmsg) diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 3edf01a25d89..bb47fe9a3905 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -465,7 +465,7 @@ static int ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode, unsigned int value, int flags, int compat32) { - struct filedesc *fdp; + struct pwddesc *pdp; struct ksem *ks; struct file *fp; char *path; @@ -481,8 +481,8 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode, if (value > SEM_VALUE_MAX) return (EINVAL); - fdp = td->td_proc->p_fd; - mode = (mode & ~fdp->fd_cmask) & ACCESSPERMS; + pdp = td->td_proc->p_pd; + mode = (mode & ~pdp->pd_cmask) & ACCESSPERMS; error = falloc(td, &fp, &fd, O_CLOEXEC); if (error) { if (name == NULL) diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index b1cbd7d4eb0b..88151f1422f9 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -1031,7 +1031,7 @@ int kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode, int shmflags, struct filecaps *fcaps, const char *name __unused) { - struct filedesc *fdp; + struct pwddesc *pdp; struct shmfd *shmfd; struct file *fp; char *path; @@ -1081,8 +1081,8 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode, if ((initial_seals & ~F_SEAL_SEAL) != 0) return (EINVAL); - fdp = td->td_proc->p_fd; - cmode = (mode & ~fdp->fd_cmask) & ACCESSPERMS; + pdp = td->td_proc->p_pd; + cmode = (mode & ~pdp->pd_cmask) & ACCESSPERMS; /* * shm_open(2) created shm should always have O_CLOEXEC set, as mandated diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index c149ebd9e25f..5cadd3d4af48 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -660,7 +660,7 @@ uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td) } VATTR_NULL(&vattr); vattr.va_type = VSOCK; - vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask); + vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_pd->pd_cmask); #ifdef MAC error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index dfc46c405a1a..d3d7617c2801 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1098,7 +1098,8 @@ kern_openat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int flags, int mode) { struct proc *p = td->td_proc; - struct filedesc *fdp = p->p_fd; + struct filedesc *fdp; + struct pwddesc *pdp; struct file *fp; struct vnode *vp; struct nameidata nd; @@ -1106,6 +1107,8 @@ kern_openat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int cmode, error, indx; indx = -1; + fdp = p->p_fd; + pdp = p->p_pd; AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); @@ -1137,7 +1140,7 @@ kern_openat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, */ /* Set the flags early so the finit in devfs can pick them up. */ fp->f_flag = flags & FMASK; - cmode = ((mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT; + cmode = ((mode & ~pdp->pd_cmask) & ALLPERMS) & ~S_ISTXT; NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, &rights, td); td->td_dupfd = -1; /* XXX check for fdopen */ @@ -1339,7 +1342,7 @@ kern_mknodat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, } else { VATTR_NULL(&vattr); vattr.va_mode = (mode & ALLPERMS) & - ~td->td_proc->p_fd->fd_cmask; + ~td->td_proc->p_pd->pd_cmask; vattr.va_rdev = dev; whiteout = 0; @@ -1454,7 +1457,7 @@ kern_mkfifoat(struct thread *td, int fd, const char *path, } VATTR_NULL(&vattr); vattr.va_type = VFIFO; - vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_fd->fd_cmask; + vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_pd->pd_cmask; #ifdef MAC error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); @@ -1726,7 +1729,7 @@ kern_symlinkat(struct thread *td, const char *path1, int fd, const char *path2, goto restart; } VATTR_NULL(&vattr); - vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask; + vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_pd->pd_cmask; #ifdef MAC vattr.va_type = VLNK; error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, @@ -3803,7 +3806,7 @@ kern_mkdirat(struct thread *td, int fd, const char *path, enum uio_seg segflg, } VATTR_NULL(&vattr); vattr.va_type = VDIR; - vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask; + vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_pd->pd_cmask; #ifdef MAC error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); @@ -4207,13 +4210,13 @@ struct umask_args { int sys_umask(struct thread *td, struct umask_args *uap) { - struct filedesc *fdp; + struct pwddesc *pdp; - fdp = td->td_proc->p_fd; - FILEDESC_XLOCK(fdp); - td->td_retval[0] = fdp->fd_cmask; - fdp->fd_cmask = uap->newmask & ALLPERMS; - FILEDESC_XUNLOCK(fdp); + pdp = td->td_proc->p_pd; + PWDDESC_XLOCK(pdp); + td->td_retval[0] = pdp->pd_cmask; + pdp->pd_cmask = uap->newmask & ALLPERMS; + PWDDESC_XUNLOCK(pdp); return (0); } diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 8ab96c440b87..53d289366580 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -92,12 +93,17 @@ struct pwd { }; typedef SMR_POINTER(struct pwd *) smrpwd_t; +struct pwddesc { + struct mtx pd_lock; /* protects members of this struct */ + smrpwd_t pd_pwd; /* directories */ + volatile u_int pd_refcount; + u_short pd_cmask; /* mask for file creation */ +}; + struct filedesc { struct fdescenttbl *fd_files; /* open files table */ - smrpwd_t fd_pwd; /* directories */ NDSLOTTYPE *fd_map; /* bitmap of free fds */ int fd_freefile; /* approx. next free file */ - u_short fd_cmask; /* mask for file creation */ int fd_refcnt; /* thread reference count */ int fd_holdcnt; /* hold count on structure + mutex */ struct sx fd_sx; /* protects members of this struct */ @@ -134,6 +140,28 @@ struct filedesc_to_leader { #ifdef _KERNEL +/* Lock a paths descriptor table. */ +#define PWDDESC_LOCK(pdp) (&(pdp)->pd_lock) +#define PWDDESC_LOCK_INIT(pdp) \ + mtx_init(PWDDESC_LOCK(pdp), "pwddesc", NULL, MTX_DEF) +#define PWDDESC_LOCK_DESTROY(pdp) mtx_destroy(PWDDESC_LOCK(pdp)) +#define PWDDESC_XLOCK(pdp) mtx_lock(PWDDESC_LOCK(pdp)) +#define PWDDESC_XUNLOCK(pdp) mtx_unlock(PWDDESC_LOCK(pdp)) +#define PWDDESC_LOCK_ASSERT(pdp, what) \ + mtx_assert(PWDDESC_LOCK(pdp), (what)) +#define PWDDESC_ASSERT_XLOCKED(pdp) \ + PWDDESC_LOCK_ASSERT((pdp), MA_OWNED) +#define PWDDESC_ASSERT_UNLOCKED(pdp) \ + PWDDESC_LOCK_ASSERT((pdp), MA_NOTOWNED) + +#define PWDDESC_XLOCKED_LOAD_PWD(pdp) ({ \ + struct pwddesc *_pdp = (pdp); \ + struct pwd *_pwd; \ + _pwd = smr_serialized_load(&(_pdp)->pd_pwd, \ + (PWDDESC_ASSERT_XLOCKED(_pdp), true)); \ + _pwd; \ +}) + /* Lock a file descriptor table. */ #define FILEDESC_LOCK_INIT(fdp) sx_init(&(fdp)->fd_sx, "filedesc structure") #define FILEDESC_LOCK_DESTROY(fdp) sx_destroy(&(fdp)->fd_sx) @@ -149,31 +177,15 @@ struct filedesc_to_leader { SX_NOTRECURSED) #define FILEDESC_UNLOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_sx, SX_UNLOCKED) -#define FILEDESC_LOCKED_LOAD_PWD(fdp) ({ \ - struct filedesc *_fdp = (fdp); \ - struct pwd *_pwd; \ - _pwd = smr_serialized_load(&(_fdp)->fd_pwd, \ - (FILEDESC_LOCK_ASSERT(_fdp), true)); \ - _pwd; \ -}) - -#define FILEDESC_XLOCKED_LOAD_PWD(fdp) ({ \ - struct filedesc *_fdp = (fdp); \ - struct pwd *_pwd; \ - _pwd = smr_serialized_load(&(_fdp)->fd_pwd, \ - (FILEDESC_XLOCK_ASSERT(_fdp), true)); \ - _pwd; \ -}) - #else /* * Accessor for libkvm et al. */ -#define FILEDESC_KVM_LOAD_PWD(fdp) ({ \ - struct filedesc *_fdp = (fdp); \ +#define PWDDESC_KVM_LOAD_PWD(pdp) ({ \ + struct pwddesc *_pdp = (pdp); \ struct pwd *_pwd; \ - _pwd = smr_kvm_load(&(_fdp)->fd_pwd); \ + _pwd = smr_kvm_load(&(_pdp)->pd_pwd); \ _pwd; \ }) @@ -296,21 +308,26 @@ fd_modified(struct filedesc *fdp, int fd, seqc_t seqc) #endif /* cdir/rdir/jdir manipulation functions. */ +struct pwddesc *pdcopy(struct pwddesc *pdp); +void pdescfree(struct thread *td); +struct pwddesc *pdinit(struct pwddesc *pdp, bool keeplock); +struct pwddesc *pdshare(struct pwddesc *pdp); +void pdunshare(struct thread *td); + void pwd_chdir(struct thread *td, struct vnode *vp); int pwd_chroot(struct thread *td, struct vnode *vp); void pwd_ensure_dirs(void); void pwd_set_rootvnode(void); -struct pwd *pwd_hold_filedesc(struct filedesc *fdp); +struct pwd *pwd_hold_pwddesc(struct pwddesc *pdp); bool pwd_hold_smr(struct pwd *pwd); struct pwd *pwd_hold(struct thread *td); void pwd_drop(struct pwd *pwd); static inline void -pwd_set(struct filedesc *fdp, struct pwd *newpwd) +pwd_set(struct pwddesc *pdp, struct pwd *newpwd) { - - smr_serialized_store(&fdp->fd_pwd, newpwd, - (FILEDESC_XLOCK_ASSERT(fdp), true)); + smr_serialized_store(&pdp->pd_pwd, newpwd, + (PWDDESC_ASSERT_XLOCKED(pdp), true)); } struct pwd *pwd_get_smr(void); diff --git a/sys/sys/param.h b/sys/sys/param.h index e0a9adb5cc78..577f0e1d6e07 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300129 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300130 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 45118db34dde..0b41b84c08ab 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -597,6 +597,7 @@ struct proc { struct ucred *p_ucred; /* (c) Process owner's identity. */ struct filedesc *p_fd; /* (b) Open files. */ struct filedesc_to_leader *p_fdtol; /* (b) Tracking node */ + struct pwddesc *p_pd; /* (b) Cwd, chroot, jail, umask */ struct pstats *p_stats; /* (b) Accounting/statistics (CPU). */ struct plimit *p_limit; /* (c) Resource limits. */ struct callout p_limco; /* (c) Limit callout handle */ diff --git a/sys/sys/user.h b/sys/sys/user.h index 1442e2bdca73..800bf9497679 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -88,7 +88,7 @@ */ #define KI_NSPARE_INT 2 #define KI_NSPARE_LONG 12 -#define KI_NSPARE_PTR 6 +#define KI_NSPARE_PTR 5 #ifndef _KERNEL #ifndef KINFO_PROC_SIZE @@ -213,6 +213,7 @@ struct kinfo_proc { * front of ki_spareptrs, and longs from the end of ki_sparelongs. * That way the spare room from both arrays will remain contiguous. */ + struct pwddesc *ki_pd; /* pointer to process paths info */ void *ki_spareptrs[KI_NSPARE_PTR]; /* spare room for growth */ long ki_sparelongs[KI_NSPARE_LONG]; /* spare room for growth */ long ki_sflag; /* PS_* flags */