Whenever possible, resolve all symlinks as if the sysroot path were a chroot environment. This prevents potential interactions with files from the host filesystem.
Signed-off-by: Michal Sekletar <msekl...@redhat.com> --- configure.ac | 17 +++++++++++++++++ libdwfl/dwfl_segment_report_module.c | 21 +++++++++++++++++++++ libdwfl/link_map.c | 27 ++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3298f7fc..22f7258a 100644 --- a/configure.ac +++ b/configure.ac @@ -283,6 +283,23 @@ case "$CFLAGS" in ;; esac +AC_MSG_CHECKING([for openat2 with RESOLVE_IN_ROOT support]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ + #include <fcntl.h> + #include <linux/openat2.h> + #include <sys/syscall.h> + #include <unistd.h> + #include <stdlib.h> + ]], [[ + struct open_how how = { .flags = O_RDONLY|O_DIRECTORY, .resolve = RESOLVE_IN_ROOT }; + return syscall (SYS_openat2, AT_FDCWD, ".", &how, sizeof(how)) >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; + ]])], + [AC_DEFINE([HAVE_OPENAT2_RESOLVE_IN_ROOT], [1], [Define if openat2 is available]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)] +) + dnl enable debugging of branch prediction. AC_ARG_ENABLE([debugpred], AS_HELP_STRING([--enable-debugpred],[build binaries with support to debug branch prediction]), diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c index 32f44af8..53b938b9 100644 --- a/libdwfl/dwfl_segment_report_module.c +++ b/libdwfl/dwfl_segment_report_module.c @@ -37,6 +37,12 @@ #include <inttypes.h> #include <fcntl.h> +#if HAVE_OPENAT2_RESOLVE_IN_ROOT +#include <linux/openat2.h> +#include <sys/syscall.h> +#include <unistd.h> +#endif + #include <system.h> @@ -784,6 +790,19 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, sysroot if it is set. */ if (dwfl->sysroot && !executable) { +#if HAVE_OPENAT2_RESOLVE_IN_ROOT + int sysrootfd; + struct open_how how = { + .flags = O_RDONLY, + .resolve = RESOLVE_IN_ROOT, + }; + + sysrootfd = open (dwfl->sysroot, O_DIRECTORY|O_PATH); + if (sysrootfd < 0) + return -1; + fd = syscall (SYS_openat2, sysrootfd, name, &how, sizeof(how)); + close (sysrootfd); +#else int r; char *n; @@ -793,6 +812,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, fd = open (n, O_RDONLY); free (n); } + +#endif } else fd = open (name, O_RDONLY); diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 8ab14862..761e9b03 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -34,6 +34,12 @@ #include <fcntl.h> +#if HAVE_OPENAT2_RESOLVE_IN_ROOT +#include <linux/openat2.h> +#include <sys/syscall.h> +#include <unistd.h> +#endif + /* This element is always provided and always has a constant value. This makes it an easy thing to scan for to discern the format. */ #define PROBE_TYPE AT_PHENT @@ -418,7 +424,25 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, /* This code is mostly inlined dwfl_report_elf. */ char *sysroot_name = NULL; const char *sysroot = dwfl->sysroot; + int fd; +#if HAVE_OPENAT2_RESOLVE_IN_ROOT + if (sysroot) + { + int sysrootfd; + + struct open_how how = { + .flags = O_RDONLY, + .resolve = RESOLVE_IN_ROOT, + }; + + sysrootfd = open (sysroot, O_DIRECTORY|O_PATH); + if (sysrootfd < 0) + return -1; + fd = syscall (SYS_openat2, sysrootfd, name, &how, sizeof(how)); + close (sysrootfd); + } +#else /* Don't use the sysroot if the path is already inside it. */ bool name_in_sysroot = sysroot && startswith (name, sysroot); @@ -430,7 +454,8 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, name = sysroot_name; } - int fd = open (name, O_RDONLY); + fd = open (name, O_RDONLY); +#endif if (fd >= 0) { Elf *elf; -- 2.39.5 (Apple Git-154)