From: Sun Haoyu <shyliuli@aosc.io>
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>
---
linux-user/syscall.c | 11 ++++++++++-
linux-user/syscall_defs.h | 7 ++++++-
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index bb95b96f29..f4b74ad350 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8856,7 +8856,16 @@ static int do_openat2(CPUArchState *cpu_env, abi_long dirfd,
if (fd > -2) {
ret = get_errno(fd);
} else {
- ret = get_errno(safe_openat2(dirfd, pathname, &how,
+ const char *host_pathname = pathname;
+ if (pathname[0] == '/' &&
+ !(how.resolve & (RESOLVE_IN_ROOT | RESOLVE_BENEATH))) {
+ /*
+ * RESOLVE_BENEATH rejects absolute paths; RESOLVE_IN_ROOT
+ * resolves them relative to dirfd.
+ */
+ host_pathname = path(pathname);
+ }
+ ret = get_errno(safe_openat2(dirfd, host_pathname, &how,
sizeof(struct open_how_ver0)));
}
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index aac8b0c574..679af640c0 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2774,7 +2774,12 @@ struct target_open_how_ver0 {
#ifndef RESOLVE_NO_SYMLINKS
#define RESOLVE_NO_SYMLINKS 0x04
#endif
-
+#ifndef RESOLVE_BENEATH
+#define RESOLVE_BENEATH 0x08
+#endif
+#ifndef RESOLVE_IN_ROOT
+#define RESOLVE_IN_ROOT 0x10
+#endif
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
(defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
defined(TARGET_M68K) || defined(TARGET_MICROBLAZE) || \
--
2.43.0