Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F175415226
D58855.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D58855.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58855: namei: retry absolute symlink expansions from the native root
Attached
Detach File
Event Timeline
Log In to Comment