aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_descrip.c
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2023-05-29 08:15:28 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2023-05-29 08:15:28 +0000
commit3d2fec7db856c67e1a94a87a846d8ffe6f48b61f (patch)
treeddc1540446ecd5338bf50e6769bf39df02ef60d8 /sys/kern/kern_descrip.c
parent723e25f12893ea6af0c387b0a5070451cc79e20b (diff)
downloadsrc-3d2fec7db856c67e1a94a87a846d8ffe6f48b61f.tar.gz
src-3d2fec7db856c67e1a94a87a846d8ffe6f48b61f.zip
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
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r--sys/kern/kern_descrip.c61
1 files changed, 59 insertions, 2 deletions
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;
@@ -3998,6 +4007,40 @@ pwd_chdir(struct thread *td, struct vnode *vp)
}
/*
+ * 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.
*/
int
@@ -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);