From 3d2fec7db856c67e1a94a87a846d8ffe6f48b61f Mon Sep 17 00:00:00 2001 From: Dmitry Chagin Date: Mon, 29 May 2023 11:15:28 +0300 Subject: namei: Add the abilty for the ABI to specify an alternate root path For now a non-native ABI (i.e., Linux) uses the kern_alternate_path() facility to dynamically reroot lookups. First, an attempt is made to lookup the file in /compat/linux/original-path. If that fails, the lookup is done in /original-path. Thats requires a bit of code in every ABI syscall implementation where path name translation is needed. Also our kern_alternate_path() does not properly lookups absolute symlinks in second attempt, i.e., does not append /compat/linux part to the resolved link. The change is intended to avoid this by specifiyng the ABI root directory for namei(), using one call to pwd_altroot() during exec-time into the ABI. In that case namei() will dynamically reroot lookups as mentioned above. PR: 72920 Reviewed by: kib Differential revision: https://reviews.freebsd.org/D38933 MFC after: 2 month --- sys/kern/kern_descrip.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'sys/kern/kern_descrip.c') diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 0be59e930dd4..908c3352514b 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -3839,6 +3839,11 @@ pwd_fill(struct pwd *oldpwd, struct pwd *newpwd) vrefact(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 * @@ -3930,6 +3935,8 @@ pwd_drop(struct pwd *pwd) vrele(pwd->pwd_rdir); if (pwd->pwd_jdir != NULL) vrele(pwd->pwd_jdir); + if (pwd->pwd_adir != NULL) + vrele(pwd->pwd_adir); uma_zfree_smr(pwd_zone, pwd); } @@ -3967,6 +3974,8 @@ pwd_chroot(struct thread *td, struct vnode *vp) vrefact(vp); newpwd->pwd_rdir = vp; + vrefact(vp); + newpwd->pwd_adir = vp; if (oldpwd->pwd_jdir == NULL) { vrefact(vp); newpwd->pwd_jdir = vp; @@ -3997,6 +4006,40 @@ pwd_chdir(struct thread *td, struct vnode *vp) pwd_drop(oldpwd); } +/* + * Process is transitioning to/from a non-native ABI. + */ +void +pwd_altroot(struct thread *td, struct vnode *altroot_vp) +{ + 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 (altroot_vp != NULL) { + /* + * Native process to a non-native ABI. + */ + + vrefact(altroot_vp); + newpwd->pwd_adir = altroot_vp; + } else { + /* + * Non-native process to the native ABI. + */ + + vrefact(oldpwd->pwd_rdir); + newpwd->pwd_adir = oldpwd->pwd_rdir; + } + pwd_fill(oldpwd, newpwd); + pwd_set(pdp, newpwd); + PWDDESC_XUNLOCK(pdp); + pwd_drop(oldpwd); +} + /* * jail_attach(2) changes both root and working directories. */ @@ -4030,6 +4073,8 @@ pwd_chroot_chdir(struct thread *td, struct vnode *vp) vrefact(vp); newpwd->pwd_jdir = vp; } + vrefact(vp); + newpwd->pwd_adir = vp; pwd_fill(oldpwd, newpwd); pwd_set(pdp, newpwd); PWDDESC_XUNLOCK(pdp); @@ -4046,7 +4091,8 @@ pwd_ensure_dirs(void) pdp = curproc->p_pd; PWDDESC_XLOCK(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); return; } @@ -4064,6 +4110,10 @@ pwd_ensure_dirs(void) vrefact(rootvnode); newpwd->pwd_rdir = rootvnode; } + if (newpwd->pwd_adir == NULL) { + vrefact(rootvnode); + newpwd->pwd_adir = rootvnode; + } pwd_set(pdp, newpwd); PWDDESC_XUNLOCK(pdp); pwd_drop(oldpwd); @@ -4084,6 +4134,8 @@ pwd_set_rootvnode(void) newpwd->pwd_cdir = rootvnode; vrefact(rootvnode); newpwd->pwd_rdir = rootvnode; + vrefact(rootvnode); + newpwd->pwd_adir = rootvnode; pwd_fill(oldpwd, newpwd); pwd_set(pdp, newpwd); PWDDESC_XUNLOCK(pdp); @@ -4119,7 +4171,8 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp) if (oldpwd == NULL || (oldpwd->pwd_cdir != olddp && oldpwd->pwd_rdir != olddp && - oldpwd->pwd_jdir != olddp)) { + oldpwd->pwd_jdir != olddp && + oldpwd->pwd_adir != olddp)) { PWDDESC_XUNLOCK(pdp); pddrop(pdp); continue; @@ -4136,6 +4189,10 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp) vrefact(newdp); newpwd->pwd_jdir = newdp; } + if (oldpwd->pwd_adir == olddp) { + vrefact(newdp); + newpwd->pwd_adir = newdp; + } pwd_fill(oldpwd, newpwd); pwd_set(pdp, newpwd); PWDDESC_XUNLOCK(pdp); -- cgit v1.2.3