pseudo_util: Fix handling of absolute links

Message ID 20220328161348.32725-1-chaitanya.vadrevu@ni.com
State New
Headers show
Series pseudo_util: Fix handling of absolute links | expand

Commit Message

Chaitanya Vadrevu March 28, 2022, 4:13 p.m. UTC
Absolute links should be evaluated starting from the chroot path but the
existing implementation drops the whole base path (which includes the
chroot path) when it encounters an absolute link.

Encountered the issue during root image creation process in an OE build
where ldconfig was deleting some absolute links as stat64 calls failed
and the symlinks were deemed dead.

Signed-off-by: Chaitanya Vadrevu <chaitanya.vadrevu@ni.com>
---
 pseudo_util.c               |  6 ++----
 test/test-chroot-symlink.c  | 28 ++++++++++++++++++++++++++++
 test/test-chroot-symlink.sh | 19 +++++++++++++++++++
 3 files changed, 49 insertions(+), 4 deletions(-)
 create mode 100644 test/test-chroot-symlink.c
 create mode 100755 test/test-chroot-symlink.sh

Patch

diff --git a/pseudo_util.c b/pseudo_util.c
index 5f8ff19..f150a1b 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -694,9 +694,9 @@  pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
 			}
 			/* null-terminate buffer */
 			linkbuf[linklen] = '\0';
-			/* absolute symlink means start over! */
+			/* absolute symlink means go back to root */
 			if (*linkbuf == '/') {
-				current = newpath;
+				current = root;
 			} else {
 				/* point back at the end of the previous path... */
 				current -= (elen + 1);
@@ -794,8 +794,6 @@  static int pathbuf = 0;
  * path of baselen characters, presumed not to end in a /.  path is
  * the new path to be canonicalized.  The tricky part is that path may
  * contain symlinks, which must be resolved.
- * if "path" starts with a /, then it is an absolute path, and
- * we ignore base.
  */
 char *
 pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t baselen, size_t *lenp, int leave_last) {
diff --git a/test/test-chroot-symlink.c b/test/test-chroot-symlink.c
new file mode 100644
index 0000000..469cb49
--- /dev/null
+++ b/test/test-chroot-symlink.c
@@ -0,0 +1,28 @@ 
+/*
+ * Test that stat'ing absolute/relative symlinks in a chroot environment works
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+    struct stat buf;
+
+    if (argc != 2) {
+        perror("args");
+	return 2;
+    }
+    if (chroot(argv[1]) == -1) {
+        perror("chroot");
+        return 1;
+    }
+    if (stat("symlink", &buf) == -1) {
+        perror("stat symlink");
+        return 1;
+    }
+    return 0;
+}
diff --git a/test/test-chroot-symlink.sh b/test/test-chroot-symlink.sh
new file mode 100755
index 0000000..91092c1
--- /dev/null
+++ b/test/test-chroot-symlink.sh
@@ -0,0 +1,19 @@ 
+#!/bin/bash
+#
+# Test that stat'ing absolute/relative symlinks in a chroot environment works
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+
+set -e
+
+touch symlink_target
+trap "rm -f symlink_target symlink" 0
+
+# Absolute symlink
+ln -s /symlink_target symlink
+./test/test-chroot-symlink `pwd`
+rm symlink
+
+# Relative symlink
+ln -s symlink_target symlink
+./test/test-chroot-symlink `pwd`