Changeset View
Standalone View
sys/kern/kern_descrip.c
Show First 20 Lines • Show All 3,833 Lines • ▼ Show 20 Lines | if (newpwd->pwd_rdir == NULL && oldpwd->pwd_rdir != NULL) { | |||||||||||
vrefact(oldpwd->pwd_rdir); | vrefact(oldpwd->pwd_rdir); | |||||||||||
newpwd->pwd_rdir = oldpwd->pwd_rdir; | newpwd->pwd_rdir = oldpwd->pwd_rdir; | |||||||||||
} | } | |||||||||||
if (newpwd->pwd_jdir == NULL && oldpwd->pwd_jdir != NULL) { | if (newpwd->pwd_jdir == NULL && oldpwd->pwd_jdir != NULL) { | |||||||||||
vrefact(oldpwd->pwd_jdir); | vrefact(oldpwd->pwd_jdir); | |||||||||||
newpwd->pwd_jdir = oldpwd->pwd_jdir; | newpwd->pwd_jdir = oldpwd->pwd_jdir; | |||||||||||
} | } | |||||||||||
if (newpwd->pwd_adir == NULL && oldpwd->pwd_adir != NULL) { | ||||||||||||
vrefact(oldpwd->pwd_adir); | ||||||||||||
newpwd->pwd_adir = oldpwd->pwd_adir; | ||||||||||||
} | } | |||||||||||
} | ||||||||||||
struct pwd * | struct pwd * | |||||||||||
pwd_hold_pwddesc(struct pwddesc *pdp) | pwd_hold_pwddesc(struct pwddesc *pdp) | |||||||||||
{ | { | |||||||||||
struct pwd *pwd; | struct pwd *pwd; | |||||||||||
PWDDESC_ASSERT_XLOCKED(pdp); | PWDDESC_ASSERT_XLOCKED(pdp); | |||||||||||
pwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | pwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | |||||||||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | if (!refcount_release(&pwd->pwd_refcount)) | |||||||||||
return; | return; | |||||||||||
if (pwd->pwd_cdir != NULL) | if (pwd->pwd_cdir != NULL) | |||||||||||
vrele(pwd->pwd_cdir); | vrele(pwd->pwd_cdir); | |||||||||||
if (pwd->pwd_rdir != NULL) | if (pwd->pwd_rdir != NULL) | |||||||||||
vrele(pwd->pwd_rdir); | vrele(pwd->pwd_rdir); | |||||||||||
if (pwd->pwd_jdir != NULL) | if (pwd->pwd_jdir != NULL) | |||||||||||
vrele(pwd->pwd_jdir); | vrele(pwd->pwd_jdir); | |||||||||||
if (pwd->pwd_adir != NULL) | ||||||||||||
vrele(pwd->pwd_adir); | ||||||||||||
uma_zfree_smr(pwd_zone, pwd); | uma_zfree_smr(pwd_zone, pwd); | |||||||||||
} | } | |||||||||||
/* | /* | |||||||||||
* The caller is responsible for invoking priv_check() and | * The caller is responsible for invoking priv_check() and | |||||||||||
* mac_vnode_check_chroot() to authorize this operation. | * mac_vnode_check_chroot() to authorize this operation. | |||||||||||
*/ | */ | |||||||||||
int | int | |||||||||||
Show All 21 Lines | if (error != 0) { | |||||||||||
return (error); | return (error); | |||||||||||
} | } | |||||||||||
} else { | } else { | |||||||||||
FILEDESC_SUNLOCK(fdp); | FILEDESC_SUNLOCK(fdp); | |||||||||||
} | } | |||||||||||
vrefact(vp); | vrefact(vp); | |||||||||||
newpwd->pwd_rdir = vp; | newpwd->pwd_rdir = vp; | |||||||||||
vrefact(vp); | ||||||||||||
newpwd->pwd_adir = vp; | ||||||||||||
if (oldpwd->pwd_jdir == NULL) { | if (oldpwd->pwd_jdir == NULL) { | |||||||||||
vrefact(vp); | vrefact(vp); | |||||||||||
newpwd->pwd_jdir = vp; | newpwd->pwd_jdir = vp; | |||||||||||
} | } | |||||||||||
pwd_fill(oldpwd, newpwd); | pwd_fill(oldpwd, newpwd); | |||||||||||
pwd_set(pdp, newpwd); | pwd_set(pdp, newpwd); | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pwd_drop(oldpwd); | pwd_drop(oldpwd); | |||||||||||
Show All 15 Lines | pwd_chdir(struct thread *td, struct vnode *vp) | |||||||||||
newpwd->pwd_cdir = vp; | newpwd->pwd_cdir = vp; | |||||||||||
pwd_fill(oldpwd, newpwd); | pwd_fill(oldpwd, newpwd); | |||||||||||
pwd_set(pdp, newpwd); | pwd_set(pdp, newpwd); | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pwd_drop(oldpwd); | pwd_drop(oldpwd); | |||||||||||
} | } | |||||||||||
/* | /* | |||||||||||
* Process is transitioning to/from a non-native ABI. | ||||||||||||
kibUnsubmitted Done Inline Actions
kib: | ||||||||||||
*/ | ||||||||||||
void | ||||||||||||
pwd_exec(struct thread *td, struct vnode *vp) | ||||||||||||
kibUnsubmitted Not Done Inline ActionsName the 'vp' parameter more vividly, to indicate that this is the alternate root. kib: Name the 'vp' parameter more vividly, to indicate that this is the alternate root.
Might be… | ||||||||||||
{ | ||||||||||||
struct pwddesc *pdp; | ||||||||||||
struct pwd *newpwd, *oldpwd; | ||||||||||||
newpwd = pwd_alloc(); | ||||||||||||
pdp = td->td_proc->p_pd; | ||||||||||||
PWDDESC_XLOCK(pdp); | ||||||||||||
oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | ||||||||||||
if (vp != NULL) { | ||||||||||||
/* | ||||||||||||
* Native process to a non-native ABI. | ||||||||||||
*/ | ||||||||||||
vrefact(vp); | ||||||||||||
newpwd->pwd_adir = vp; | ||||||||||||
Not Done Inline ActionsBut why? Cannot the process be chrooted? kib: But why? Cannot the process be chrooted? | ||||||||||||
Not Done Inline ActionsI think I understand what you are concerned with. You want to prevent the chroot escape? Then perhaps, if the process is chrooted, it should get pwd_adir set to NULL. BTW, what about jailed processes? kib: I think I understand what you are concerned with. You want to prevent the chroot escape? Then… | ||||||||||||
Done Inline ActionsI want to minimize the amount of checks for setup and restart namei() for the native ABI, so that it would be sufficient a comparison of pwd_adir vs pwd_rdir. So the pwd_adir should be changed if the process is jailed or if not chrooted. Also, chrooted ABI process should acts like native process from namei() perspective, ie not restarts name(). This condition could be checked in pwd_exec() or on a ABI side. The first is not effective due to pwd_alloc(), so I moved it to the ABI - linux_pwd_onexec(). Therefore asserts was used to garantie properly usage of pwd_exec(). Removed now. Jails fixed. However, jexec $jail chroot /compat/$abi /bin/bash is not supposed to work in my POV, or it should? dchagin: I want to minimize the amount of checks for setup and restart namei() for the native ABI, so… | ||||||||||||
Not Done Inline ActionsSo there are two issues.
kib: So there are two issues.
1. We need to ensure that there is no jail or chroot escape. The… | ||||||||||||
Done Inline Actions
Sure, pwd_adir is initialized in the pwd_chroot() or pwd_chroot_chdir() unconditionally, so it fully consistent with what you have written.
Reworked, look at linux_pwd_onexec(), please, now if emul_path exists in chroot or jail it is used. Thank you
After the patch the running process will continue execution with proper environment. I like this behaviour. dchagin: > So there are two issues.
> 1. We need to ensure that there is no jail or chroot escape. The… | ||||||||||||
} else { | ||||||||||||
/* | ||||||||||||
* Non-native process to the native ABI. | ||||||||||||
*/ | ||||||||||||
vrefact(oldpwd->pwd_rdir); | ||||||||||||
newpwd->pwd_adir = oldpwd->pwd_rdir; | ||||||||||||
Done Inline Actions
kib: | ||||||||||||
Done Inline ActionsAfter re-reading, _unexec is the weird name. Could you merge pwd_exec with pwd_unexec, indicating unexec case by vp == NULL? kib: After re-reading, _unexec is the weird name. Could you merge pwd_exec with pwd_unexec… | ||||||||||||
} | ||||||||||||
pwd_fill(oldpwd, newpwd); | ||||||||||||
pwd_set(pdp, newpwd); | ||||||||||||
Not Done Inline ActionsSame. kib: Same. | ||||||||||||
PWDDESC_XUNLOCK(pdp); | ||||||||||||
pwd_drop(oldpwd); | ||||||||||||
} | ||||||||||||
/* | ||||||||||||
* jail_attach(2) changes both root and working directories. | * jail_attach(2) changes both root and working directories. | |||||||||||
*/ | */ | |||||||||||
int | int | |||||||||||
pwd_chroot_chdir(struct thread *td, struct vnode *vp) | pwd_chroot_chdir(struct thread *td, struct vnode *vp) | |||||||||||
{ | { | |||||||||||
struct pwddesc *pdp; | struct pwddesc *pdp; | |||||||||||
struct filedesc *fdp; | struct filedesc *fdp; | |||||||||||
struct pwd *newpwd, *oldpwd; | struct pwd *newpwd, *oldpwd; | |||||||||||
Show All 16 Lines | pwd_chroot_chdir(struct thread *td, struct vnode *vp) | |||||||||||
vrefact(vp); | vrefact(vp); | |||||||||||
newpwd->pwd_rdir = vp; | newpwd->pwd_rdir = vp; | |||||||||||
vrefact(vp); | vrefact(vp); | |||||||||||
newpwd->pwd_cdir = vp; | newpwd->pwd_cdir = vp; | |||||||||||
if (oldpwd->pwd_jdir == NULL) { | if (oldpwd->pwd_jdir == NULL) { | |||||||||||
vrefact(vp); | vrefact(vp); | |||||||||||
newpwd->pwd_jdir = vp; | newpwd->pwd_jdir = vp; | |||||||||||
} | } | |||||||||||
vrefact(vp); | ||||||||||||
newpwd->pwd_adir = vp; | ||||||||||||
pwd_fill(oldpwd, newpwd); | pwd_fill(oldpwd, newpwd); | |||||||||||
pwd_set(pdp, newpwd); | pwd_set(pdp, newpwd); | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pwd_drop(oldpwd); | pwd_drop(oldpwd); | |||||||||||
return (0); | return (0); | |||||||||||
} | } | |||||||||||
void | void | |||||||||||
pwd_ensure_dirs(void) | pwd_ensure_dirs(void) | |||||||||||
{ | { | |||||||||||
struct pwddesc *pdp; | struct pwddesc *pdp; | |||||||||||
struct pwd *oldpwd, *newpwd; | struct pwd *oldpwd, *newpwd; | |||||||||||
pdp = curproc->p_pd; | pdp = curproc->p_pd; | |||||||||||
PWDDESC_XLOCK(pdp); | PWDDESC_XLOCK(pdp); | |||||||||||
oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | |||||||||||
if (oldpwd->pwd_cdir != NULL && oldpwd->pwd_rdir != NULL) { | if (oldpwd->pwd_cdir != NULL && oldpwd->pwd_rdir != NULL && | |||||||||||
oldpwd->pwd_adir != NULL) { | ||||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
return; | return; | |||||||||||
} | } | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
newpwd = pwd_alloc(); | newpwd = pwd_alloc(); | |||||||||||
PWDDESC_XLOCK(pdp); | PWDDESC_XLOCK(pdp); | |||||||||||
oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | |||||||||||
pwd_fill(oldpwd, newpwd); | pwd_fill(oldpwd, newpwd); | |||||||||||
if (newpwd->pwd_cdir == NULL) { | if (newpwd->pwd_cdir == NULL) { | |||||||||||
vrefact(rootvnode); | vrefact(rootvnode); | |||||||||||
newpwd->pwd_cdir = rootvnode; | newpwd->pwd_cdir = rootvnode; | |||||||||||
} | } | |||||||||||
if (newpwd->pwd_rdir == NULL) { | if (newpwd->pwd_rdir == NULL) { | |||||||||||
vrefact(rootvnode); | vrefact(rootvnode); | |||||||||||
newpwd->pwd_rdir = rootvnode; | newpwd->pwd_rdir = rootvnode; | |||||||||||
} | } | |||||||||||
if (newpwd->pwd_adir == NULL) { | ||||||||||||
vrefact(rootvnode); | ||||||||||||
newpwd->pwd_adir = rootvnode; | ||||||||||||
} | ||||||||||||
pwd_set(pdp, newpwd); | pwd_set(pdp, newpwd); | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pwd_drop(oldpwd); | pwd_drop(oldpwd); | |||||||||||
} | } | |||||||||||
void | void | |||||||||||
pwd_set_rootvnode(void) | pwd_set_rootvnode(void) | |||||||||||
{ | { | |||||||||||
struct pwddesc *pdp; | struct pwddesc *pdp; | |||||||||||
struct pwd *oldpwd, *newpwd; | struct pwd *oldpwd, *newpwd; | |||||||||||
pdp = curproc->p_pd; | pdp = curproc->p_pd; | |||||||||||
newpwd = pwd_alloc(); | newpwd = pwd_alloc(); | |||||||||||
PWDDESC_XLOCK(pdp); | PWDDESC_XLOCK(pdp); | |||||||||||
oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | |||||||||||
vrefact(rootvnode); | vrefact(rootvnode); | |||||||||||
newpwd->pwd_cdir = rootvnode; | newpwd->pwd_cdir = rootvnode; | |||||||||||
vrefact(rootvnode); | vrefact(rootvnode); | |||||||||||
newpwd->pwd_rdir = rootvnode; | newpwd->pwd_rdir = rootvnode; | |||||||||||
vrefact(rootvnode); | ||||||||||||
newpwd->pwd_adir = rootvnode; | ||||||||||||
pwd_fill(oldpwd, newpwd); | pwd_fill(oldpwd, newpwd); | |||||||||||
pwd_set(pdp, newpwd); | pwd_set(pdp, newpwd); | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pwd_drop(oldpwd); | 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 | |||||||||||
Show All 19 Lines | FOREACH_PROC_IN_SYSTEM(p) { | |||||||||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | |||||||||||
if (pdp == NULL) | if (pdp == NULL) | |||||||||||
continue; | continue; | |||||||||||
PWDDESC_XLOCK(pdp); | PWDDESC_XLOCK(pdp); | |||||||||||
oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp); | |||||||||||
if (oldpwd == NULL || | if (oldpwd == NULL || | |||||||||||
(oldpwd->pwd_cdir != olddp && | (oldpwd->pwd_cdir != olddp && | |||||||||||
oldpwd->pwd_rdir != olddp && | oldpwd->pwd_rdir != olddp && | |||||||||||
oldpwd->pwd_jdir != olddp)) { | oldpwd->pwd_jdir != olddp && | |||||||||||
oldpwd->pwd_adir != olddp)) { | ||||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pddrop(pdp); | pddrop(pdp); | |||||||||||
continue; | continue; | |||||||||||
} | } | |||||||||||
if (oldpwd->pwd_cdir == olddp) { | if (oldpwd->pwd_cdir == olddp) { | |||||||||||
vrefact(newdp); | vrefact(newdp); | |||||||||||
newpwd->pwd_cdir = newdp; | newpwd->pwd_cdir = newdp; | |||||||||||
} | } | |||||||||||
if (oldpwd->pwd_rdir == olddp) { | if (oldpwd->pwd_rdir == olddp) { | |||||||||||
vrefact(newdp); | vrefact(newdp); | |||||||||||
newpwd->pwd_rdir = newdp; | newpwd->pwd_rdir = newdp; | |||||||||||
} | } | |||||||||||
if (oldpwd->pwd_jdir == olddp) { | if (oldpwd->pwd_jdir == olddp) { | |||||||||||
vrefact(newdp); | vrefact(newdp); | |||||||||||
newpwd->pwd_jdir = newdp; | newpwd->pwd_jdir = newdp; | |||||||||||
} | ||||||||||||
if (oldpwd->pwd_adir == olddp) { | ||||||||||||
vrefact(newdp); | ||||||||||||
newpwd->pwd_adir = newdp; | ||||||||||||
} | } | |||||||||||
pwd_fill(oldpwd, newpwd); | pwd_fill(oldpwd, newpwd); | |||||||||||
pwd_set(pdp, newpwd); | pwd_set(pdp, newpwd); | |||||||||||
PWDDESC_XUNLOCK(pdp); | PWDDESC_XUNLOCK(pdp); | |||||||||||
pwd_drop(oldpwd); | pwd_drop(oldpwd); | |||||||||||
pddrop(pdp); | pddrop(pdp); | |||||||||||
newpwd = pwd_alloc(); | newpwd = pwd_alloc(); | |||||||||||
} | } | |||||||||||
▲ Show 20 Lines • Show All 1,165 Lines • Show Last 20 Lines |