Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_descrip.c
Show First 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
#include <security/audit/audit.h> | #include <security/audit/audit.h> | ||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <ddb/ddb.h> | #include <ddb/ddb.h> | ||||
static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table"); | static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table"); | ||||
static MALLOC_DEFINE(M_PWD, "pwd", "Descriptor table vnodes"); | |||||
static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader", | static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader", | ||||
"file desc to leader structures"); | "file desc to leader structures"); | ||||
static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures"); | static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures"); | ||||
MALLOC_DEFINE(M_FILECAPS, "filecaps", "descriptor capabilities"); | MALLOC_DEFINE(M_FILECAPS, "filecaps", "descriptor capabilities"); | ||||
MALLOC_DECLARE(M_FADVISE); | MALLOC_DECLARE(M_FADVISE); | ||||
static __read_mostly uma_zone_t file_zone; | static __read_mostly uma_zone_t file_zone; | ||||
Show All 9 Lines | |||||
static void fdused(struct filedesc *fdp, int fd); | static void fdused(struct filedesc *fdp, int fd); | ||||
static int getmaxfd(struct thread *td); | static int getmaxfd(struct thread *td); | ||||
static u_long *filecaps_copy_prep(const struct filecaps *src); | static u_long *filecaps_copy_prep(const struct filecaps *src); | ||||
static void filecaps_copy_finish(const struct filecaps *src, | static void filecaps_copy_finish(const struct filecaps *src, | ||||
struct filecaps *dst, u_long *ioctls); | struct filecaps *dst, u_long *ioctls); | ||||
static u_long *filecaps_free_prep(struct filecaps *fcaps); | static u_long *filecaps_free_prep(struct filecaps *fcaps); | ||||
static void filecaps_free_finish(u_long *ioctls); | static void filecaps_free_finish(u_long *ioctls); | ||||
static struct pwd *pwd_alloc(void); | |||||
/* | /* | ||||
* Each process has: | * Each process has: | ||||
* | * | ||||
* - An array of open file descriptors (fd_ofiles) | * - An array of open file descriptors (fd_ofiles) | ||||
* - An array of file flags (fd_ofileflags) | * - An array of file flags (fd_ofileflags) | ||||
* - A bitmap recording which descriptors are in use (fd_map) | * - A bitmap recording which descriptors are in use (fd_map) | ||||
* | * | ||||
* A process starts out with NDFILE descriptors. The value of NDFILE has | * A process starts out with NDFILE descriptors. The value of NDFILE has | ||||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | #endif | ||||
fde->fde_file = NULL; | fde->fde_file = NULL; | ||||
#ifdef CAPABILITIES | #ifdef CAPABILITIES | ||||
seqc_write_end(&fde->fde_seqc); | seqc_write_end(&fde->fde_seqc); | ||||
#endif | #endif | ||||
fdefree_last(fde); | fdefree_last(fde); | ||||
fdunused(fdp, fd); | fdunused(fdp, fd); | ||||
} | } | ||||
void | |||||
pwd_ensure_dirs(void) | |||||
{ | |||||
struct filedesc *fdp; | |||||
fdp = curproc->p_fd; | |||||
FILEDESC_XLOCK(fdp); | |||||
if (fdp->fd_cdir == NULL) { | |||||
fdp->fd_cdir = rootvnode; | |||||
vrefact(rootvnode); | |||||
} | |||||
if (fdp->fd_rdir == NULL) { | |||||
fdp->fd_rdir = rootvnode; | |||||
vrefact(rootvnode); | |||||
} | |||||
FILEDESC_XUNLOCK(fdp); | |||||
} | |||||
/* | /* | ||||
* System calls on descriptors. | * System calls on descriptors. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct getdtablesize_args { | struct getdtablesize_args { | ||||
int dummy; | int dummy; | ||||
}; | }; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 1,666 Lines • ▼ Show 20 Lines | fdinit(struct filedesc *fdp, bool prepfiles) | ||||
refcount_init(&newfdp->fd_refcnt, 1); | refcount_init(&newfdp->fd_refcnt, 1); | ||||
refcount_init(&newfdp->fd_holdcnt, 1); | refcount_init(&newfdp->fd_holdcnt, 1); | ||||
newfdp->fd_cmask = CMASK; | newfdp->fd_cmask = CMASK; | ||||
newfdp->fd_map = newfdp0->fd_dmap; | newfdp->fd_map = newfdp0->fd_dmap; | ||||
newfdp->fd_lastfile = -1; | newfdp->fd_lastfile = -1; | ||||
newfdp->fd_files = (struct fdescenttbl *)&newfdp0->fd_dfiles; | newfdp->fd_files = (struct fdescenttbl *)&newfdp0->fd_dfiles; | ||||
newfdp->fd_files->fdt_nfiles = NDFILE; | newfdp->fd_files->fdt_nfiles = NDFILE; | ||||
if (fdp == NULL) | if (fdp == NULL) { | ||||
newfdp->fd_pwd = pwd_alloc(); | |||||
return (newfdp); | return (newfdp); | ||||
} | |||||
if (prepfiles && fdp->fd_lastfile >= newfdp->fd_nfiles) | if (prepfiles && fdp->fd_lastfile >= newfdp->fd_nfiles) | ||||
fdgrowtable(newfdp, fdp->fd_lastfile + 1); | fdgrowtable(newfdp, fdp->fd_lastfile + 1); | ||||
FILEDESC_SLOCK(fdp); | FILEDESC_SLOCK(fdp); | ||||
newfdp->fd_cdir = fdp->fd_cdir; | newfdp->fd_pwd = pwd_hold_filedesc(fdp); | ||||
if (newfdp->fd_cdir) | |||||
vrefact(newfdp->fd_cdir); | |||||
newfdp->fd_rdir = fdp->fd_rdir; | |||||
if (newfdp->fd_rdir) | |||||
vrefact(newfdp->fd_rdir); | |||||
newfdp->fd_jdir = fdp->fd_jdir; | |||||
if (newfdp->fd_jdir) | |||||
vrefact(newfdp->fd_jdir); | |||||
if (!prepfiles) { | if (!prepfiles) { | ||||
FILEDESC_SUNLOCK(fdp); | FILEDESC_SUNLOCK(fdp); | ||||
} else { | } else { | ||||
while (fdp->fd_lastfile >= newfdp->fd_nfiles) { | while (fdp->fd_lastfile >= newfdp->fd_nfiles) { | ||||
FILEDESC_SUNLOCK(fdp); | FILEDESC_SUNLOCK(fdp); | ||||
fdgrowtable(newfdp, fdp->fd_lastfile + 1); | fdgrowtable(newfdp, fdp->fd_lastfile + 1); | ||||
FILEDESC_SLOCK(fdp); | FILEDESC_SLOCK(fdp); | ||||
▲ Show 20 Lines • Show All 281 Lines • ▼ Show 20 Lines | fdescfree_fds(struct thread *td, struct filedesc *fdp, bool needclose) | ||||
fddrop(fdp); | fddrop(fdp); | ||||
} | } | ||||
void | void | ||||
fdescfree(struct thread *td) | fdescfree(struct thread *td) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct vnode *cdir, *jdir, *rdir; | struct pwd *pwd; | ||||
p = td->td_proc; | p = td->td_proc; | ||||
fdp = p->p_fd; | fdp = p->p_fd; | ||||
MPASS(fdp != NULL); | MPASS(fdp != NULL); | ||||
#ifdef RACCT | #ifdef RACCT | ||||
if (RACCT_ENABLED()) | if (RACCT_ENABLED()) | ||||
racct_set_unlocked(p, RACCT_NOFILE, 0); | racct_set_unlocked(p, RACCT_NOFILE, 0); | ||||
#endif | #endif | ||||
if (p->p_fdtol != NULL) | if (p->p_fdtol != NULL) | ||||
fdclearlocks(td); | fdclearlocks(td); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
p->p_fd = NULL; | p->p_fd = NULL; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
if (refcount_release(&fdp->fd_refcnt) == 0) | if (refcount_release(&fdp->fd_refcnt) == 0) | ||||
return; | return; | ||||
FILEDESC_XLOCK(fdp); | FILEDESC_XLOCK(fdp); | ||||
cdir = fdp->fd_cdir; | pwd = fdp->fd_pwd; | ||||
fdp->fd_cdir = NULL; | pwd_set(fdp, NULL); | ||||
rdir = fdp->fd_rdir; | |||||
fdp->fd_rdir = NULL; | |||||
jdir = fdp->fd_jdir; | |||||
fdp->fd_jdir = NULL; | |||||
FILEDESC_XUNLOCK(fdp); | FILEDESC_XUNLOCK(fdp); | ||||
if (cdir != NULL) | pwd_drop(pwd); | ||||
vrele(cdir); | |||||
if (rdir != NULL) | |||||
vrele(rdir); | |||||
if (jdir != NULL) | |||||
vrele(jdir); | |||||
fdescfree_fds(td, fdp, 1); | fdescfree_fds(td, fdp, 1); | ||||
} | } | ||||
void | void | ||||
fdescfree_remapped(struct filedesc *fdp) | fdescfree_remapped(struct filedesc *fdp) | ||||
{ | { | ||||
if (fdp->fd_cdir != NULL) | pwd_drop(fdp->fd_pwd); | ||||
vrele(fdp->fd_cdir); | |||||
if (fdp->fd_rdir != NULL) | |||||
vrele(fdp->fd_rdir); | |||||
if (fdp->fd_jdir != NULL) | |||||
vrele(fdp->fd_jdir); | |||||
fdescfree_fds(curthread, fdp, 0); | fdescfree_fds(curthread, fdp, 0); | ||||
} | } | ||||
/* | /* | ||||
* For setugid programs, we don't want to people to use that setugidness | * For setugid programs, we don't want to people to use that setugidness | ||||
* to generate error messages which write to a file which otherwise would | * to generate error messages which write to a file which otherwise would | ||||
* otherwise be off-limits to the process. We check for filesystems where | * otherwise be off-limits to the process. We check for filesystems where | ||||
* the vnode can change out from under us after execve (like [lin]procfs). | * the vnode can change out from under us after execve (like [lin]procfs). | ||||
▲ Show 20 Lines • Show All 893 Lines • ▼ Show 20 Lines | if (fp->f_type == DTYPE_VNODE) { | ||||
vp = fp->f_vnode; | vp = fp->f_vnode; | ||||
if (vp->v_type == VDIR) | if (vp->v_type == VDIR) | ||||
return (EPERM); | return (EPERM); | ||||
} | } | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | |||||
pwd_fill(struct pwd *oldpwd, struct pwd *newpwd) | |||||
{ | |||||
if (newpwd->pwd_cdir == NULL && oldpwd->pwd_cdir != NULL) { | |||||
vrefact(oldpwd->pwd_cdir); | |||||
newpwd->pwd_cdir = oldpwd->pwd_cdir; | |||||
} | |||||
if (newpwd->pwd_rdir == NULL && oldpwd->pwd_rdir != NULL) { | |||||
vrefact(oldpwd->pwd_rdir); | |||||
newpwd->pwd_rdir = oldpwd->pwd_rdir; | |||||
} | |||||
if (newpwd->pwd_jdir == NULL && oldpwd->pwd_jdir != NULL) { | |||||
vrefact(oldpwd->pwd_jdir); | |||||
newpwd->pwd_jdir = oldpwd->pwd_jdir; | |||||
} | |||||
} | |||||
struct pwd * | |||||
pwd_hold_filedesc(struct filedesc *fdp) | |||||
{ | |||||
struct pwd *pwd; | |||||
FILEDESC_LOCK_ASSERT(fdp); | |||||
pwd = fdp->fd_pwd; | |||||
if (pwd != NULL) | |||||
refcount_acquire(&pwd->pwd_refcount); | |||||
return (pwd); | |||||
} | |||||
struct pwd * | |||||
pwd_hold(struct thread *td) | |||||
{ | |||||
struct filedesc *fdp; | |||||
struct pwd *pwd; | |||||
fdp = td->td_proc->p_fd; | |||||
FILEDESC_SLOCK(fdp); | |||||
pwd = fdp->fd_pwd; | |||||
MPASS(pwd != NULL); | |||||
refcount_acquire(&pwd->pwd_refcount); | |||||
FILEDESC_SUNLOCK(fdp); | |||||
return (pwd); | |||||
} | |||||
static struct pwd * | |||||
pwd_alloc(void) | |||||
{ | |||||
struct pwd *pwd; | |||||
pwd = malloc(sizeof(*pwd), M_PWD, M_WAITOK | M_ZERO); | |||||
refcount_init(&pwd->pwd_refcount, 1); | |||||
return (pwd); | |||||
} | |||||
void | |||||
pwd_drop(struct pwd *pwd) | |||||
{ | |||||
if (!refcount_release(&pwd->pwd_refcount)) | |||||
return; | |||||
if (pwd->pwd_cdir != NULL) | |||||
vrele(pwd->pwd_cdir); | |||||
if (pwd->pwd_rdir != NULL) | |||||
vrele(pwd->pwd_rdir); | |||||
if (pwd->pwd_jdir != NULL) | |||||
vrele(pwd->pwd_jdir); | |||||
free(pwd, M_PWD); | |||||
} | |||||
/* | /* | ||||
* Common routine for kern_chroot() and jail_attach(). The caller is | * Common routine for kern_chroot() and jail_attach(). The caller is | ||||
* responsible for invoking priv_check() and mac_vnode_check_chroot() to | * responsible for invoking priv_check() and mac_vnode_check_chroot() to | ||||
* authorize this operation. | * authorize this operation. | ||||
*/ | */ | ||||
int | int | ||||
pwd_chroot(struct thread *td, struct vnode *vp) | pwd_chroot(struct thread *td, struct vnode *vp) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct vnode *oldvp; | struct pwd *newpwd, *oldpwd; | ||||
int error; | int error; | ||||
fdp = td->td_proc->p_fd; | fdp = td->td_proc->p_fd; | ||||
newpwd = pwd_alloc(); | |||||
FILEDESC_XLOCK(fdp); | FILEDESC_XLOCK(fdp); | ||||
oldpwd = fdp->fd_pwd; | |||||
if (chroot_allow_open_directories == 0 || | if (chroot_allow_open_directories == 0 || | ||||
(chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { | (chroot_allow_open_directories == 1 && | ||||
oldpwd->pwd_rdir != rootvnode)) { | |||||
error = chroot_refuse_vdir_fds(fdp); | error = chroot_refuse_vdir_fds(fdp); | ||||
if (error != 0) { | if (error != 0) { | ||||
FILEDESC_XUNLOCK(fdp); | FILEDESC_XUNLOCK(fdp); | ||||
pwd_drop(newpwd); | |||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
oldvp = fdp->fd_rdir; | |||||
vrefact(vp); | vrefact(vp); | ||||
fdp->fd_rdir = vp; | newpwd->pwd_rdir = vp; | ||||
if (fdp->fd_jdir == NULL) { | if (oldpwd->pwd_jdir == NULL) { | ||||
vrefact(vp); | vrefact(vp); | ||||
fdp->fd_jdir = vp; | newpwd->pwd_jdir = vp; | ||||
} | } | ||||
pwd_fill(oldpwd, newpwd); | |||||
pwd_set(fdp, newpwd); | |||||
FILEDESC_XUNLOCK(fdp); | FILEDESC_XUNLOCK(fdp); | ||||
vrele(oldvp); | pwd_drop(oldpwd); | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
pwd_chdir(struct thread *td, struct vnode *vp) | pwd_chdir(struct thread *td, struct vnode *vp) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct vnode *oldvp; | struct pwd *newpwd, *oldpwd; | ||||
VNPASS(vp->v_usecount > 0, vp); | |||||
newpwd = pwd_alloc(); | |||||
fdp = td->td_proc->p_fd; | fdp = td->td_proc->p_fd; | ||||
FILEDESC_XLOCK(fdp); | FILEDESC_XLOCK(fdp); | ||||
VNASSERT(vp->v_usecount > 0, vp, | oldpwd = fdp->fd_pwd; | ||||
("chdir to a vnode with zero usecount")); | newpwd->pwd_cdir = vp; | ||||
oldvp = fdp->fd_cdir; | pwd_fill(oldpwd, newpwd); | ||||
fdp->fd_cdir = vp; | pwd_set(fdp, newpwd); | ||||
FILEDESC_XUNLOCK(fdp); | FILEDESC_XUNLOCK(fdp); | ||||
vrele(oldvp); | pwd_drop(oldpwd); | ||||
} | } | ||||
void | |||||
pwd_ensure_dirs(void) | |||||
{ | |||||
struct filedesc *fdp; | |||||
struct pwd *oldpwd, *newpwd; | |||||
fdp = curproc->p_fd; | |||||
FILEDESC_XLOCK(fdp); | |||||
oldpwd = fdp->fd_pwd; | |||||
if (oldpwd->pwd_cdir != NULL && oldpwd->pwd_rdir != NULL) { | |||||
FILEDESC_XUNLOCK(fdp); | |||||
return; | |||||
} | |||||
FILEDESC_XUNLOCK(fdp); | |||||
newpwd = pwd_alloc(); | |||||
FILEDESC_XLOCK(fdp); | |||||
oldpwd = fdp->fd_pwd; | |||||
pwd_fill(oldpwd, newpwd); | |||||
if (newpwd->pwd_cdir == NULL) { | |||||
vrefact(rootvnode); | |||||
newpwd->pwd_cdir = rootvnode; | |||||
} | |||||
if (newpwd->pwd_rdir == NULL) { | |||||
vrefact(rootvnode); | |||||
newpwd->pwd_rdir = rootvnode; | |||||
} | |||||
pwd_set(fdp, newpwd); | |||||
FILEDESC_XUNLOCK(fdp); | |||||
pwd_drop(oldpwd); | |||||
} | |||||
/* | /* | ||||
* Scan all active processes and prisons to see if any of them have a current | * Scan all active processes and prisons to see if any of them have a current | ||||
* or root directory of `olddp'. If so, replace them with the new mount point. | * or root directory of `olddp'. If so, replace them with the new mount point. | ||||
*/ | */ | ||||
void | void | ||||
mountcheckdirs(struct vnode *olddp, struct vnode *newdp) | mountcheckdirs(struct vnode *olddp, struct vnode *newdp) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct pwd *newpwd, *oldpwd; | |||||
struct prison *pr; | struct prison *pr; | ||||
struct proc *p; | struct proc *p; | ||||
int nrele; | int nrele; | ||||
if (vrefcnt(olddp) == 1) | if (vrefcnt(olddp) == 1) | ||||
return; | return; | ||||
nrele = 0; | nrele = 0; | ||||
newpwd = pwd_alloc(); | |||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
fdp = fdhold(p); | fdp = fdhold(p); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
if (fdp == NULL) | if (fdp == NULL) | ||||
continue; | continue; | ||||
FILEDESC_XLOCK(fdp); | FILEDESC_XLOCK(fdp); | ||||
if (fdp->fd_cdir == olddp) { | oldpwd = fdp->fd_pwd; | ||||
if (oldpwd == NULL || | |||||
(oldpwd->pwd_cdir != olddp && | |||||
oldpwd->pwd_rdir != olddp && | |||||
oldpwd->pwd_jdir != olddp)) { | |||||
FILEDESC_XUNLOCK(fdp); | |||||
fddrop(fdp); | |||||
continue; | |||||
} | |||||
if (oldpwd->pwd_cdir == olddp) { | |||||
vrefact(newdp); | vrefact(newdp); | ||||
fdp->fd_cdir = newdp; | newpwd->pwd_cdir = newdp; | ||||
nrele++; | |||||
} | } | ||||
if (fdp->fd_rdir == olddp) { | if (oldpwd->pwd_rdir == olddp) { | ||||
vrefact(newdp); | vrefact(newdp); | ||||
fdp->fd_rdir = newdp; | newpwd->pwd_rdir = newdp; | ||||
nrele++; | |||||
} | } | ||||
if (fdp->fd_jdir == olddp) { | if (oldpwd->pwd_jdir == olddp) { | ||||
vrefact(newdp); | vrefact(newdp); | ||||
fdp->fd_jdir = newdp; | newpwd->pwd_jdir = newdp; | ||||
nrele++; | |||||
} | } | ||||
pwd_fill(oldpwd, newpwd); | |||||
pwd_set(fdp, newpwd); | |||||
FILEDESC_XUNLOCK(fdp); | FILEDESC_XUNLOCK(fdp); | ||||
pwd_drop(oldpwd); | |||||
fddrop(fdp); | fddrop(fdp); | ||||
newpwd = pwd_alloc(); | |||||
} | } | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
pwd_drop(newpwd); | |||||
if (rootvnode == olddp) { | if (rootvnode == olddp) { | ||||
vrefact(newdp); | vrefact(newdp); | ||||
rootvnode = newdp; | rootvnode = newdp; | ||||
nrele++; | nrele++; | ||||
} | } | ||||
mtx_lock(&prison0.pr_mtx); | mtx_lock(&prison0.pr_mtx); | ||||
if (prison0.pr_root == olddp) { | if (prison0.pr_root == olddp) { | ||||
vrefact(newdp); | vrefact(newdp); | ||||
▲ Show 20 Lines • Show All 319 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, | kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, | ||||
int flags) | int flags) | ||||
{ | { | ||||
struct file *fp; | struct file *fp; | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct export_fd_buf *efbuf; | struct export_fd_buf *efbuf; | ||||
struct vnode *cttyvp, *textvp, *tracevp; | struct vnode *cttyvp, *textvp, *tracevp; | ||||
struct pwd *pwd; | |||||
int error, i; | int error, i; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
/* ktrace vnode */ | /* ktrace vnode */ | ||||
tracevp = p->p_tracevp; | tracevp = p->p_tracevp; | ||||
if (tracevp != NULL) | if (tracevp != NULL) | ||||
Show All 24 Lines | kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, | ||||
if (cttyvp != NULL) | if (cttyvp != NULL) | ||||
export_vnode_to_sb(cttyvp, KF_FD_TYPE_CTTY, FREAD | FWRITE, | export_vnode_to_sb(cttyvp, KF_FD_TYPE_CTTY, FREAD | FWRITE, | ||||
efbuf); | efbuf); | ||||
error = 0; | error = 0; | ||||
if (fdp == NULL) | if (fdp == NULL) | ||||
goto fail; | goto fail; | ||||
efbuf->fdp = fdp; | efbuf->fdp = fdp; | ||||
FILEDESC_SLOCK(fdp); | FILEDESC_SLOCK(fdp); | ||||
pwd = pwd_hold_filedesc(fdp); | |||||
if (pwd != NULL) { | |||||
/* working directory */ | /* working directory */ | ||||
if (fdp->fd_cdir != NULL) { | if (pwd->pwd_cdir != NULL) { | ||||
vrefact(fdp->fd_cdir); | vrefact(pwd->pwd_cdir); | ||||
export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf); | export_vnode_to_sb(pwd->pwd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf); | ||||
} | } | ||||
/* root directory */ | /* root directory */ | ||||
if (fdp->fd_rdir != NULL) { | if (pwd->pwd_rdir != NULL) { | ||||
vrefact(fdp->fd_rdir); | vrefact(pwd->pwd_rdir); | ||||
export_vnode_to_sb(fdp->fd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf); | export_vnode_to_sb(pwd->pwd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf); | ||||
} | } | ||||
/* jail directory */ | /* jail directory */ | ||||
if (fdp->fd_jdir != NULL) { | if (pwd->pwd_jdir != NULL) { | ||||
vrefact(fdp->fd_jdir); | vrefact(pwd->pwd_jdir); | ||||
export_vnode_to_sb(fdp->fd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf); | export_vnode_to_sb(pwd->pwd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf); | ||||
} | } | ||||
pwd_drop(pwd); | |||||
} | |||||
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { | for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { | ||||
if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) | if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) | ||||
continue; | continue; | ||||
#ifdef CAPABILITIES | #ifdef CAPABILITIES | ||||
rights = *cap_rights(fdp, i); | rights = *cap_rights(fdp, i); | ||||
#else /* !CAPABILITIES */ | #else /* !CAPABILITIES */ | ||||
rights = cap_no_rights; | rights = cap_no_rights; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
* Get per-process file descriptors for use by procstat(1), et al. | * Get per-process file descriptors for use by procstat(1), et al. | ||||
*/ | */ | ||||
static int | static int | ||||
sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) | sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct kinfo_ofile *okif; | struct kinfo_ofile *okif; | ||||
struct kinfo_file *kif; | struct kinfo_file *kif; | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct pwd *pwd; | |||||
int error, i, *name; | int error, i, *name; | ||||
struct file *fp; | struct file *fp; | ||||
struct proc *p; | struct proc *p; | ||||
name = (int *)arg1; | name = (int *)arg1; | ||||
error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); | error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
fdp = fdhold(p); | fdp = fdhold(p); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
if (fdp == NULL) | if (fdp == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK); | kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK); | ||||
okif = malloc(sizeof(*okif), M_TEMP, M_WAITOK); | okif = malloc(sizeof(*okif), M_TEMP, M_WAITOK); | ||||
FILEDESC_SLOCK(fdp); | FILEDESC_SLOCK(fdp); | ||||
if (fdp->fd_cdir != NULL) | pwd = pwd_hold_filedesc(fdp); | ||||
export_vnode_for_osysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif, | if (pwd != NULL) { | ||||
if (pwd->pwd_cdir != NULL) | |||||
export_vnode_for_osysctl(pwd->pwd_cdir, KF_FD_TYPE_CWD, kif, | |||||
okif, fdp, req); | okif, fdp, req); | ||||
if (fdp->fd_rdir != NULL) | if (pwd->pwd_rdir != NULL) | ||||
export_vnode_for_osysctl(fdp->fd_rdir, KF_FD_TYPE_ROOT, kif, | export_vnode_for_osysctl(pwd->pwd_rdir, KF_FD_TYPE_ROOT, kif, | ||||
okif, fdp, req); | okif, fdp, req); | ||||
if (fdp->fd_jdir != NULL) | if (pwd->pwd_jdir != NULL) | ||||
export_vnode_for_osysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif, | export_vnode_for_osysctl(pwd->pwd_jdir, KF_FD_TYPE_JAIL, kif, | ||||
okif, fdp, req); | okif, fdp, req); | ||||
pwd_drop(pwd); | |||||
} | |||||
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { | for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { | ||||
if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) | if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) | ||||
continue; | continue; | ||||
export_file_to_kinfo(fp, i, NULL, kif, fdp, | export_file_to_kinfo(fp, i, NULL, kif, fdp, | ||||
KERN_FILEDESC_PACK_KINFO); | KERN_FILEDESC_PACK_KINFO); | ||||
FILEDESC_SUNLOCK(fdp); | FILEDESC_SUNLOCK(fdp); | ||||
kinfo_to_okinfo(kif, okif); | kinfo_to_okinfo(kif, okif); | ||||
error = SYSCTL_OUT(req, okif, sizeof(*okif)); | error = SYSCTL_OUT(req, okif, sizeof(*okif)); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Takes a locked proc as argument, and returns with the proc unlocked. | * Takes a locked proc as argument, and returns with the proc unlocked. | ||||
*/ | */ | ||||
int | int | ||||
kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) | kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct export_fd_buf *efbuf; | struct export_fd_buf *efbuf; | ||||
struct vnode *cdir; | |||||
int error; | int error; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
fdp = fdhold(p); | fdp = fdhold(p); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
if (fdp == NULL) | if (fdp == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK); | efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK); | ||||
efbuf->fdp = fdp; | efbuf->fdp = fdp; | ||||
efbuf->sb = sb; | efbuf->sb = sb; | ||||
efbuf->remainder = maxlen; | efbuf->remainder = maxlen; | ||||
FILEDESC_SLOCK(fdp); | FILEDESC_SLOCK(fdp); | ||||
if (fdp->fd_cdir == NULL) | cdir = fdp->fd_pwd->pwd_cdir; | ||||
if (cdir == NULL) { | |||||
error = EINVAL; | error = EINVAL; | ||||
else { | } else { | ||||
vrefact(fdp->fd_cdir); | vrefact(cdir); | ||||
error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, | error = export_vnode_to_sb(cdir, KF_FD_TYPE_CWD, FREAD, efbuf); | ||||
FREAD, efbuf); | |||||
} | } | ||||
FILEDESC_SUNLOCK(fdp); | FILEDESC_SUNLOCK(fdp); | ||||
fddrop(fdp); | fddrop(fdp); | ||||
free(efbuf, M_TEMP); | free(efbuf, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 398 Lines • Show Last 20 Lines |