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

Sun Haoyu via qemu development posted 1 patch 2 weeks, 6 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260317053827.25051-1-shyliuli@aosc.io
Maintainers: Laurent Vivier <laurent@vivier.eu>, Pierrick Bouvier <pierrick.bouvier@linaro.org>
linux-user/syscall.c      | 11 ++++++++++-
linux-user/syscall_defs.h |  7 ++++++-
2 files changed, 16 insertions(+), 2 deletions(-)
[PATCH] linux-user: Make openat2() use -L for absolute paths
Posted by Sun Haoyu via qemu development 2 weeks, 6 days ago
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>
---
 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 064bc604c9..cff487f014 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8848,7 +8848,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 20d862fd8b..6a62a45847 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2777,7 +2777,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.53.0
Re: [PATCH] linux-user: Make openat2() use -L for absolute paths
Posted by Peter Maydell 2 weeks, 3 days ago
On Tue, 17 Mar 2026 at 05:38, Sun Haoyu <shyliuli@aosc.io> wrote:
>
> 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>
> ---
>  linux-user/syscall.c      | 11 ++++++++++-
>  linux-user/syscall_defs.h |  7 ++++++-
>  2 files changed, 16 insertions(+), 2 deletions(-)

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Re: [PATCH] linux-user: Make openat2() use -L for absolute paths
Posted by Peter Maydell 6 days, 6 hours ago
On Fri, 20 Mar 2026 at 10:13, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 17 Mar 2026 at 05:38, Sun Haoyu <shyliuli@aosc.io> wrote:
> >
> > 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>
> > ---
> >  linux-user/syscall.c      | 11 ++++++++++-
> >  linux-user/syscall_defs.h |  7 ++++++-
> >  2 files changed, 16 insertions(+), 2 deletions(-)
>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

I'll collect up this patch for a pullreq for rc2.

thanks
-- PMM