Page MenuHomeFreeBSD

D58855.diff
No OneTemporary

D58855.diff

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -613,11 +613,25 @@
struct componentname *cnp;
struct thread *td;
struct pwd *pwd;
+ char *abi_symlink; /* abs symlink expansion from the ABI pass */
+ size_t abi_symlink_len;
+ size_t abi_suffix_len; /* leftover path past the saved target */
+ bool target_resolved; /* walk has consumed that target */
+ enum {
+ NAMEI_ABI_PASS_ABI = 0,
+ NAMEI_ABI_PASS_SYMLINK,
+ NAMEI_ABI_PASS_NATIVE,
+ } abi_pass;
int error;
enum cache_fpl_status status;
cnp = &ndp->ni_cnd;
td = curthread;
+ abi_symlink = NULL;
+ abi_symlink_len = 0;
+ abi_suffix_len = 0;
+ target_resolved = false;
+ abi_pass = NAMEI_ABI_PASS_ABI;
#ifdef INVARIANTS
KASSERT((ndp->ni_debugflags & NAMEI_DBG_CALLED) == 0,
("%s: repeated call to namei without NDREINIT", __func__));
@@ -655,7 +669,15 @@
ndp->ni_loopcnt = 0;
ndp->ni_vp = NULL;
- error = namei_getpath(ndp);
+ if (__predict_false(abi_pass == NAMEI_ABI_PASS_SYMLINK)) {
+ /*
+ * The expansion was installed when abi_pass became
+ * SYMLINK. It is not reloaded from userspace.
+ */
+ MPASS(cnp->cn_pnbuf != NULL);
+ error = 0;
+ } else
+ error = namei_getpath(ndp);
if (__predict_false(error != 0)) {
namei_cleanup_cnp(cnp);
nameicap_cleanup(ndp, error);
@@ -734,6 +756,8 @@
* Locked lookup.
*/
for (;;) {
+ size_t prev_pathlen;
+
ndp->ni_startdir = dp;
error = vfs_lookup(ndp);
if (error != 0) {
@@ -746,10 +770,50 @@
error == ENOENT && was_restarted == 0;
if (error != ERESTART && !abi_restart)
goto out;
+ /*
+ * One restart from the native root is allowed.
+ * abi_pass only moves ABI -> SYMLINK or ABI ->
+ * NATIVE; never backwards. If the target of an
+ * absolute symlink had not yet resolved when the
+ * ABI pass failed, restart walking the saved
+ * expansion in place of the original path: the
+ * target may name a file that exists only in the
+ * native namespace (host-integration symlinks
+ * under the ABI root, linprocfs' /proc/<pid>/exe).
+ * An ENOENT after the target resolved, or with
+ * nothing saved, restarts from the original path.
+ *
+ * The old path buffer is released before the
+ * expansion is installed, so namei_cleanup_cnp()
+ * does not free the saved symlink.
+ */
+ if (abi_symlink != NULL &&
+ ndp->ni_pathlen <= abi_suffix_len)
+ target_resolved = true;
nameicap_cleanup(ndp, error);
pwd_drop(pwd);
namei_cleanup_cnp(cnp);
NDRESET(ndp);
+ if (abi_restart && abi_symlink != NULL &&
+ !target_resolved) {
+ KASSERT(abi_pass == NAMEI_ABI_PASS_ABI,
+ ("%s: symlink restart from pass %d",
+ __func__, abi_pass));
+ abi_pass = NAMEI_ABI_PASS_SYMLINK;
+ cnp->cn_pnbuf = abi_symlink;
+ ndp->ni_pathlen = abi_symlink_len;
+ abi_symlink = NULL;
+ } else {
+ if (abi_restart) {
+ KASSERT(abi_pass ==
+ NAMEI_ABI_PASS_ABI,
+ ("%s: native restart from pass %d",
+ __func__, abi_pass));
+ abi_pass = NAMEI_ABI_PASS_NATIVE;
+ }
+ uma_zfree(namei_zone, abi_symlink);
+ abi_symlink = NULL;
+ }
if (abi_restart)
was_restarted = ISRESTARTED;
ndp->ni_cnd.cn_flags |= was_restarted;
@@ -764,14 +828,19 @@
ndp->ni_vp, false, ndp);
nameicap_cleanup(ndp, 0);
pwd_drop(pwd);
+ uma_zfree(namei_zone, abi_symlink);
NDVALIDATE(ndp);
return (0);
}
+ prev_pathlen = ndp->ni_pathlen;
error = namei_follow_link(ndp);
if (error != 0)
break;
vput(ndp->ni_vp);
dp = ndp->ni_dvp;
+ if (abi_symlink != NULL &&
+ prev_pathlen <= abi_suffix_len)
+ target_resolved = true;
/*
* Check if root directory should replace current directory.
*/
@@ -789,10 +858,38 @@
*/
if ((cnp->cn_flags & ISRESTARTED) != 0)
ndp->ni_rootdir = pwd->pwd_rdir;
+ else if (pwd->pwd_adir != pwd->pwd_rdir) {
+ /*
+ * Save the expansion, and the length of
+ * the not-yet-walked suffix appended past
+ * the target, so that should the target
+ * fail to resolve under the ABI root the
+ * ENOENT handling above can restart from
+ * the expansion in place of the original
+ * path.
+ */
+ if (abi_symlink == NULL)
+ abi_symlink = uma_zalloc(namei_zone,
+ M_WAITOK);
+ memcpy(abi_symlink, cnp->cn_pnbuf,
+ ndp->ni_pathlen);
+ abi_symlink_len = ndp->ni_pathlen;
+ abi_suffix_len = prev_pathlen;
+ target_resolved = false;
+ }
vrele(dp);
error = namei_handle_root(ndp, &dp);
if (error != 0)
goto out;
+ } else if (target_resolved) {
+ /*
+ * Target already consumed under the ABI root
+ * (relative symlink at or past the end of the
+ * saved expansion). A later ENOENT is no
+ * grounds to restart from that expansion.
+ */
+ uma_zfree(namei_zone, abi_symlink);
+ abi_symlink = NULL;
}
}
vput(ndp->ni_vp);
@@ -804,6 +901,7 @@
namei_cleanup_cnp(cnp);
nameicap_cleanup(ndp, error);
pwd_drop(pwd);
+ uma_zfree(namei_zone, abi_symlink);
return (error);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 11, 5:07 PM (20 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40387518
Default Alt Text
D58855.diff (5 KB)

Event Timeline