From: Shu-Chun Weng <scw@google.com>
To: qemu-devel@nongnu.org
Cc: Laurent Vivier <laurent@vivier.eu>,
Richard Henderson <richard.henderson@linaro.org>,
Shu-Chun Weng <scw@google.com>
Subject: [PATCH 2/2] linux-user: Fix openat() emulation to not modify atime
Date: Thu, 30 Nov 2023 19:21:40 -0800 [thread overview]
Message-ID: <20231201032140.2470599-3-scw@google.com> (raw)
In-Reply-To: <20231201032140.2470599-1-scw@google.com>
Commit b8002058 strengthened openat()'s /proc detection by calling
realpath(3) on the given path, which allows various paths and symlinks
that points to the /proc file system to be intercepted correctly.
Using realpath(3), though, has a side effect that it reads the symlinks
along the way, and thus changes their atime. The results in the
following code snippet already get ~now instead of the real atime:
int fd = open("/path/to/a/symlink", O_PATH | O_NOFOLLOW);
struct stat st;
fstat(fd, st);
return st.st_atime;
This change opens a path that doesn't appear to be part of /proc
directly and checks the destination of /proc/self/fd/n to determine if
it actually refers to a file in /proc.
Neither this nor the existing code works with symlinks or indirect paths
(e.g. /tmp/../proc/self/exe) that points to /proc/self/exe because it
is itself a symlink, and both realpath(3) and /proc/self/fd/n will
resolve into the location of QEMU.
Signed-off-by: Shu-Chun Weng <scw@google.com>
---
linux-user/syscall.c | 42 +++++++++++++++++++++++++++++++++---------
1 file changed, 33 insertions(+), 9 deletions(-)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e384e14248..25e2cda10a 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8308,8 +8308,6 @@ static int open_net_route(CPUArchState *cpu_env, int fd)
int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
int flags, mode_t mode, bool safe)
{
- g_autofree char *proc_name = NULL;
- const char *pathname;
struct fake_open {
const char *filename;
int (*fill)(CPUArchState *cpu_env, int fd);
@@ -8333,13 +8331,39 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
#endif
{ NULL, NULL, NULL }
};
+ char pathname[PATH_MAX];
- /* if this is a file from /proc/ filesystem, expand full name */
- proc_name = realpath(fname, NULL);
- if (proc_name && strncmp(proc_name, "/proc/", 6) == 0) {
- pathname = proc_name;
+ if (strncmp(fname, "/proc/", 6) == 0) {
+ pstrcpy(pathname, sizeof(pathname), fname);
} else {
- pathname = fname;
+ char procpath[PATH_MAX];
+ int fd, n;
+
+ if (safe) {
+ fd = safe_openat(dirfd, path(fname), flags, mode);
+ } else {
+ fd = openat(dirfd, path(fname), flags, mode);
+ }
+ if (fd < 0) {
+ return fd;
+ }
+
+ /*
+ * Try to get the real path of the file we just opened. We avoid calling
+ * `realpath(3)` because it calls `readlink(2)` on symlinks which
+ * changes their atime. Note that since `/proc/self/exe` is a symlink,
+ * `pathname` will never resolves to it (neither will `realpath(3)`).
+ * That's why we check `fname` against the "/proc/" prefix first.
+ */
+ snprintf(procpath, sizeof(procpath), "/proc/self/fd/%d", fd);
+ n = readlink(procpath, pathname, sizeof(pathname));
+ pathname[n < sizeof(pathname) ? n : sizeof(pathname)] = '\0';
+
+ /* if this is not a file from /proc/ filesystem, the fd is good as-is */
+ if (strncmp(pathname, "/proc/", 6) != 0) {
+ return fd;
+ }
+ close(fd);
}
if (is_proc_myself(pathname, "exe")) {
@@ -8390,9 +8414,9 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
}
if (safe) {
- return safe_openat(dirfd, path(pathname), flags, mode);
+ return safe_openat(dirfd, pathname, flags, mode);
} else {
- return openat(dirfd, path(pathname), flags, mode);
+ return openat(dirfd, pathname, flags, mode);
}
}
next prev parent reply other threads:[~2023-12-01 3:22 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-01 3:21 [PATCH 0/2] linux-user: openat() fixes Shu-Chun Weng
2023-12-01 3:21 ` [PATCH 1/2] linux-user: Define TARGET_O_LARGEFILE for aarch64 Shu-Chun Weng
2023-12-01 12:38 ` [PATCH-for-8.2? " Philippe Mathieu-Daudé
2023-12-03 13:28 ` [PATCH " Laurent Vivier
2023-12-01 3:21 ` Shu-Chun Weng [this message]
2023-12-01 12:42 ` [PATCH 2/2] linux-user: Fix openat() emulation to not modify atime Philippe Mathieu-Daudé
2023-12-01 18:51 ` Shu-Chun Weng
2023-12-04 13:39 ` Philippe Mathieu-Daudé
2023-12-04 15:34 ` Stefan Hajnoczi
2023-12-01 17:09 ` Helge Deller
2023-12-04 16:58 ` Daniel P. Berrangé
2023-12-08 20:52 ` Shu-Chun Weng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231201032140.2470599-3-scw@google.com \
--to=scw@google.com \
--cc=laurent@vivier.eu \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.