diff mbox series

[pseudo,10/11] pseudo_util.c: Fix symlink processing for symlinkat and related

Message ID 1777312601-1393-11-git-send-email-mark.hatle@kernel.crashing.org
State New
Headers show
Series Various fixes, release 1.9.6 | expand

Commit Message

Mark Hatle April 27, 2026, 5:56 p.m. UTC
From: Mark Hatle <mark.hatle@amd.com>

If the symlink is absolute (starts with a '/') we need to ensure that
it is still presented as if it was inside of the chroot.  This was
discovered by the openat2 chroot test case, but only when looking at
a symlink and helped indicate that symlinkat (and similar) users
were affected.

AI-Generated: Fixed by github copilot (claude opus 4.6)

Signed-off-by: Mark Hatle <mark.hatle@amd.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
 pseudo_util.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
diff mbox series

Patch

diff --git a/pseudo_util.c b/pseudo_util.c
index 3a06027..2b0cc04 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -729,7 +729,21 @@  pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
 			linkbuf[linklen] = '\0';
 			/* absolute symlink means go back to root */
 			if (*linkbuf == '/') {
+				size_t rootlen = root - newpath;
 				current = root;
+				/* If we're in a chroot (rootlen > 0) and the
+				 * symlink target starts with the chroot prefix,
+				 * strip it.  This happens when symlinkat expanded
+				 * an absolute target to include the chroot path
+				 * on disk; without stripping, we'd double-apply
+				 * the chroot prefix during resolution.
+				 */
+				if (rootlen > 0 && (size_t)linklen > rootlen &&
+				    !memcmp(linkbuf, newpath, rootlen) &&
+				    (linkbuf[rootlen] == '/' || linkbuf[rootlen] == '\0')) {
+					memmove(linkbuf, linkbuf + rootlen, linklen - rootlen + 1);
+					linklen -= rootlen;
+				}
 			} else {
 #ifdef PSEUDO_PORT_LINUX
 				if (is_proc) {