@samitouri / QOSamiQemu / commits / fa6dfcc373

linux-user: Make openat2() use -L for absolute paths

openat2() ignored the -L prefix and opened host files directly. For example, openat2("/tmp/file") opened /tmp/file on the host, not QEMU_LD_PREFIX/tmp/file like openat() does. Fix this by using path() to rewrite absolute paths. Skip this when RESOLVE_BENEATH or RESOLVE_IN_ROOT is set: - RESOLVE_BENEATH rejects absolute paths anyway - RESOLVE_IN_ROOT resolves relative to dirfd Now openat() and openat2() work in the same way. Link: https://gitlab.com/qemu-project/qemu/-/work_items/3341 Signed-off-by: Sun Haoyu <shyliuli@aosc.io> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260317053827.25051-1-shyliuli@aosc.io Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Sun Haoyu committed Mar 17, 2026 at 13:38 UTC fa6dfcc373c244a767be04d236e0cdd075b80e69
2 files changed +16 -2
linux-user/syscall.c
+10 -1
@@ -8856,7 +8856,16 @@ static int do_openat2(CPUArchState *cpu_env, abi_long dirfd,
8856 if (fd > -2) {
8857 ret = get_errno(fd);
8858 } else {
8859 - ret = get_errno(safe_openat2(dirfd, pathname, &how,
8859 + const char *host_pathname = pathname;
8860 + if (pathname[0] == '/' &&
8861 + !(how.resolve & (RESOLVE_IN_ROOT | RESOLVE_BENEATH))) {
8862 + /*
8863 + * RESOLVE_BENEATH rejects absolute paths; RESOLVE_IN_ROOT
8864 + * resolves them relative to dirfd.
8865 + */
8866 + host_pathname = path(pathname);
8867 + }
8868 + ret = get_errno(safe_openat2(dirfd, host_pathname, &how,
8869 sizeof(struct open_how_ver0)));
8870 }
8871
linux-user/syscall_defs.h
+6 -1
@@ -2774,7 +2774,12 @@ struct target_open_how_ver0 {
2774 #ifndef RESOLVE_NO_SYMLINKS
2775 #define RESOLVE_NO_SYMLINKS 0x04
2776 #endif
2777 -
2777 +#ifndef RESOLVE_BENEATH
2778 +#define RESOLVE_BENEATH 0x08
2779 +#endif
2780 +#ifndef RESOLVE_IN_ROOT
2781 +#define RESOLVE_IN_ROOT 0x10
2782 +#endif
2783 #if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
2784 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
2785 defined(TARGET_M68K) || defined(TARGET_MICROBLAZE) || \