Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167633564
D58855.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D58855.id.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,17 @@
struct componentname *cnp;
struct thread *td;
struct pwd *pwd;
+ char *abi_symlink; /* abs symlink expansion from the ABI pass */
+ size_t abi_symlink_len;
+ bool abi_symlink_pass; /* this pass walks abi_symlink natively */
int error;
enum cache_fpl_status status;
cnp = &ndp->ni_cnd;
td = curthread;
+ abi_symlink = NULL;
+ abi_symlink_len = 0;
+ abi_symlink_pass = false;
#ifdef INVARIANTS
KASSERT((ndp->ni_debugflags & NAMEI_DBG_CALLED) == 0,
("%s: repeated call to namei without NDREINIT", __func__));
@@ -655,7 +661,18 @@
ndp->ni_loopcnt = 0;
ndp->ni_vp = NULL;
- error = namei_getpath(ndp);
+ if (__predict_false(abi_symlink_pass && abi_symlink != NULL)) {
+ /*
+ * Retry the saved absolute symlink expansion from the
+ * native root instead of reloading the original path;
+ * see the ENOENT handling after vfs_lookup() below.
+ */
+ cnp->cn_pnbuf = abi_symlink;
+ ndp->ni_pathlen = abi_symlink_len;
+ abi_symlink = NULL;
+ error = 0;
+ } else
+ error = namei_getpath(ndp);
if (__predict_false(error != 0)) {
namei_cleanup_cnp(cnp);
nameicap_cleanup(ndp, error);
@@ -738,13 +755,26 @@
error = vfs_lookup(ndp);
if (error != 0) {
uint64_t was_restarted;
- bool abi_restart;
+ bool abi_restart, symlink_retry;
was_restarted = ndp->ni_cnd.cn_flags &
ISRESTARTED;
abi_restart = pwd->pwd_adir != pwd->pwd_rdir &&
error == ENOENT && was_restarted == 0;
- if (error != ERESTART && !abi_restart)
+ /*
+ * If the walk of an absolute symlink expansion
+ * failed under the ABI root, retry the expansion
+ * from the native root before falling back to the
+ * original path: the target may name the file
+ * only in the native namespace (host-integration
+ * symlinks under the ABI root, linprocfs'
+ * /proc/<pid>/exe). If the native walk of the
+ * expansion also fails, fall back to the original
+ * path as before.
+ */
+ symlink_retry = abi_symlink_pass && error == ENOENT;
+ if (error != ERESTART && !abi_restart &&
+ !symlink_retry)
goto out;
nameicap_cleanup(ndp, error);
pwd_drop(pwd);
@@ -753,6 +783,12 @@
if (abi_restart)
was_restarted = ISRESTARTED;
ndp->ni_cnd.cn_flags |= was_restarted;
+ abi_symlink_pass = abi_restart &&
+ abi_symlink != NULL;
+ if (!abi_symlink_pass && abi_symlink != NULL) {
+ uma_zfree(namei_zone, abi_symlink);
+ abi_symlink = NULL;
+ }
goto restart;
}
@@ -764,6 +800,8 @@
ndp->ni_vp, false, ndp);
nameicap_cleanup(ndp, 0);
pwd_drop(pwd);
+ if (abi_symlink != NULL)
+ uma_zfree(namei_zone, abi_symlink);
NDVALIDATE(ndp);
return (0);
}
@@ -789,6 +827,22 @@
*/
if ((cnp->cn_flags & ISRESTARTED) != 0)
ndp->ni_rootdir = pwd->pwd_rdir;
+ else if (pwd->pwd_adir != pwd->pwd_rdir) {
+ /*
+ * Save the expansion so that, should the
+ * walk of the target under the ABI root
+ * fail, the ENOENT handling above can retry
+ * it from the native root, giving symlink
+ * targets the same ABI-first native-fallback
+ * treatment original paths receive.
+ */
+ 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;
+ }
vrele(dp);
error = namei_handle_root(ndp, &dp);
if (error != 0)
@@ -804,6 +858,8 @@
namei_cleanup_cnp(cnp);
nameicap_cleanup(ndp, error);
pwd_drop(pwd);
+ if (abi_symlink != NULL)
+ uma_zfree(namei_zone, abi_symlink);
return (error);
}
diff --git a/tests/sys/vfs/Makefile b/tests/sys/vfs/Makefile
--- a/tests/sys/vfs/Makefile
+++ b/tests/sys/vfs/Makefile
@@ -5,6 +5,8 @@
ATF_TESTS_C+= lookup_cap_dotdot
CFLAGS.lookup_cap_dotdot.c+= -I${SRCTOP}/tests
+ATF_TESTS_SH+= abi_root_symlink
+
#ATF_TESTS_SH+= lookup_test
TAP_TESTS_SH+= trailing_slash
diff --git a/tests/sys/vfs/abi_root_symlink.sh b/tests/sys/vfs/abi_root_symlink.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/vfs/abi_root_symlink.sh
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2026 Devin Teske <dteske@FreeBSD.org>
+#
+# Regression tests for absolute symlink resolution under an ABI root
+# (compat.linux.emul_path). namei(9) resolves paths for Linux ABI
+# processes by trying the ABI root first and falling back to the
+# native root. Absolute symlink targets receive the same treatment:
+# a target is first resolved under the ABI root (so self-contained
+# Linux userlands keep working, PR 289739) and retried from the
+# native root when that fails (so symlinks pointing at host paths,
+# and linprocfs' /proc/<pid>/exe, keep working, PR 297426).
+#
+# These tests require the Linux ABI (linux_enable=YES) and a Linux
+# userland (e.g. emulators/linux_base-rl9) providing ${emul_path}/bin/sh.
+
+require_linux()
+{
+ emul=$(sysctl -n compat.linux.emul_path 2>/dev/null)
+ [ "$emul" ] || atf_skip "Linux ABI not present (compat.linux.emul_path)"
+ kldstat -q -m linux64 || kldstat -q -m linux ||
+ atf_skip "linux(4) not loaded"
+ lsh="$emul/bin/sh"
+ [ -x "$lsh" ] || atf_skip "Linux userland not installed ($lsh)"
+ # Mirror of the ATF work directory under the ABI root.
+ wd=$(pwd)
+ abiwd="$emul$wd"
+ atf_check mkdir -p "$abiwd"
+}
+
+cleanup_linux()
+{
+ emul=$(sysctl -n compat.linux.emul_path 2>/dev/null)
+ [ "$emul" ] || return 0
+ rm -rf "$emul$(pwd)" 2>/dev/null
+ # Remove now-empty parents mirrored under the ABI root.
+ rmdir -p "$emul$(dirname "$(pwd)")" 2>/dev/null
+ return 0
+}
+
+atf_test_case symlink_target_in_abi_root cleanup
+symlink_target_in_abi_root_head()
+{
+ atf_set "descr" "Absolute symlink target under the ABI root wins" \
+ "over an identically named native file (PR 289739)"
+ atf_set "require.user" "root"
+}
+symlink_target_in_abi_root_body()
+{
+ require_linux
+ printf native > "$wd/f-both"
+ printf abi > "$abiwd/f-both"
+ atf_check ln -s "$wd/f-both" "$abiwd/link-both"
+ atf_check -o inline:"abi" "$lsh" -c "cat $wd/link-both"
+}
+symlink_target_in_abi_root_cleanup()
+{
+ cleanup_linux
+}
+
+atf_test_case symlink_target_native_only cleanup
+symlink_target_native_only_head()
+{
+ atf_set "descr" "Absolute symlink under the ABI root pointing at" \
+ "a native-only file falls back to the native root (PR 297426)"
+ atf_set "require.user" "root"
+}
+symlink_target_native_only_body()
+{
+ require_linux
+ printf native > "$wd/f-native"
+ atf_check ln -s "$wd/f-native" "$abiwd/link-native"
+ atf_check -o inline:"native" "$lsh" -c "cat $wd/link-native"
+}
+symlink_target_native_only_cleanup()
+{
+ cleanup_linux
+}
+
+atf_test_case symlink_target_native_only_midpath cleanup
+symlink_target_native_only_midpath_head()
+{
+ atf_set "descr" "Absolute directory symlink under the ABI root" \
+ "pointing at a native-only directory falls back to the native" \
+ "root for lookups through it (PR 297426); the shape of" \
+ "linux-rl9-fontconfig's /etc/fonts -> /usr/local/etc/fonts"
+ atf_set "require.user" "root"
+}
+symlink_target_native_only_midpath_body()
+{
+ require_linux
+ atf_check mkdir "$wd/ndir"
+ printf native > "$wd/ndir/f"
+ atf_check ln -s "$wd/ndir" "$abiwd/dirlink"
+ atf_check -o inline:"native" "$lsh" -c "cat $wd/dirlink/f"
+}
+symlink_target_native_only_midpath_cleanup()
+{
+ cleanup_linux
+}
+
+atf_test_case plain_native_fallback cleanup
+plain_native_fallback_head()
+{
+ atf_set "descr" "Plain path (no symlink) absent under the ABI root" \
+ "still falls back to the native root"
+ atf_set "require.user" "root"
+}
+plain_native_fallback_body()
+{
+ require_linux
+ printf native > "$wd/f-plain"
+ atf_check -o inline:"native" "$lsh" -c "cat $wd/f-plain"
+}
+plain_native_fallback_cleanup()
+{
+ cleanup_linux
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case symlink_target_in_abi_root
+ atf_add_test_case symlink_target_native_only
+ atf_add_test_case symlink_target_native_only_midpath
+ atf_add_test_case plain_native_fallback
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Aug 24, 8:53 AM (1 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37179174
Default Alt Text
D58855.id.diff (7 KB)
Attached To
Mode
D58855: namei: retry absolute symlink expansions from the native root
Attached
Detach File
Event Timeline
Log In to Comment