From: Shu-Chun Weng via Qemu-devel <qemu-devel@nongnu.org>
To: Laurent Vivier <laurent@vivier.eu>
Cc: Riku Voipio <riku.voipio@iki.fi>,
qemu-devel@nongnu.org, Shu-Chun Weng <scw@google.com>
Subject: [Qemu-devel] [PATCH] linux-user: hijack open() for thread directories
Date: Wed, 21 Aug 2019 13:19:21 -0700 [thread overview]
Message-ID: <20190821201921.106902-1-scw@google.com> (raw)
Besides /proc/self|<pid>, files under /proc/thread-self and
/proc/self|<pid>/task/<tid> also expose host information to the guest
program. This patch adds them to the hijack infrastracture. Note that
is_proc_myself() does not check if the <tid> matches the current thread
and is thus only suitable for procfs files that are identical for all
threads in the same process.
Behavior verified with guest program:
long main_thread_tid;
long gettid() {
return syscall(SYS_gettid);
}
void print_info(const char* cxt, const char* dir) {
char buf[1024];
FILE* fp;
snprintf(buf, sizeof(buf), "%s/cmdline", dir);
fp = fopen(buf, "r");
if (fp == NULL) {
printf("%s: can't open %s\n", cxt, buf);
} else {
fgets(buf, sizeof(buf), fp);
printf("%s %s cmd: %s\n", cxt, dir, buf);
fclose(fp);
}
snprintf(buf, sizeof(buf), "%s/maps", dir);
fp = fopen(buf, "r");
if (fp == NULL) {
printf("%s: can't open %s\n", cxt, buf);
} else {
char seen[128][128];
int n = 0, is_new = 0;
while(fgets(buf, sizeof(buf), fp) != NULL) {
const char* p = strrchr(buf, ' ');
if (p == NULL || *(p + 1) == '\n') {
continue;
}
++p;
is_new = 1;
for (int i = 0; i < n; ++i) {
if (strncmp(p, seen[i], sizeof(seen[i])) == 0) {
is_new = 0;
break;
}
}
if (is_new) {
printf("%s %s map: %s", cxt, dir, p);
if (n < 128) {
strncpy(seen[n], p, sizeof(seen[n]));
seen[n][sizeof(seen[n]) - 1] = '\0';
++n;
}
}
}
fclose(fp);
}
}
void* thread_main(void* _) {
char buf[1024];
print_info("Child", "/proc/thread-self");
snprintf(buf, sizeof(buf), "/proc/%ld/task/%ld", (long) getpid(), main_thread_tid);
print_info("Child", buf);
snprintf(buf, sizeof(buf), "/proc/%ld/task/%ld", (long) getpid(), (long) gettid());
print_info("Child", buf);
return NULL;
}
int main() {
char buf[1024];
pthread_t thread;
int ret;
print_info("Main", "/proc/thread-self");
print_info("Main", "/proc/self");
snprintf(buf, sizeof(buf), "/proc/%ld", (long) getpid());
print_info("Main", buf);
main_thread_tid = gettid();
snprintf(buf, sizeof(buf), "/proc/self/task/%ld", main_thread_tid);
print_info("Main", buf);
snprintf(buf, sizeof(buf), "/proc/%ld/task/%ld", (long) getpid(), main_thread_tid);
print_info("Main", buf);
if ((ret = pthread_create(&thread, NULL, &thread_main, NULL)) < 0) {
printf("ptherad_create failed: %s (%d)\n", strerror(ret), ret);
}
pthread_join(thread, NULL);
return 0;
}
Signed-off-by: Shu-Chun Weng <scw@google.com>
---
linux-user/syscall.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8367cb138d..73fe82bcc7 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6968,17 +6968,57 @@ static int open_self_auxv(void *cpu_env, int fd)
return 0;
}
+static int consume_task_directories(const char **filename)
+{
+ if (!strncmp(*filename, "task/", strlen("task/"))) {
+ *filename += strlen("task/");
+ if (**filename < '1' || **filename > '9') {
+ return 0;
+ }
+ /*
+ * Don't care about the exact tid.
+ * XXX: this allows opening files under /proc/self|<pid>/task/<n> where
+ * <n> is not a valid thread id. Consider checking if the file
+ * actually exists.
+ */
+ const char *p = *filename + 1;
+ while (*p >= '0' && *p <= '9') {
+ ++p;
+ }
+ if (*p == '/') {
+ *filename = p + 1;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Determines if filename refer to a procfs file for the current process or any
+ * thread within the current process. This function should only be used to check
+ * for files that have identical contents in all threads, e.g. exec, maps, etc.
+ */
static int is_proc_myself(const char *filename, const char *entry)
{
if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
filename += strlen("/proc/");
if (!strncmp(filename, "self/", strlen("self/"))) {
filename += strlen("self/");
+ if (!consume_task_directories(&filename)) {
+ return 0;
+ }
+ } else if (!strncmp(filename, "thread-self/", strlen("thread-self/"))) {
+ filename += strlen("thread-self/");
} else if (*filename >= '1' && *filename <= '9') {
char myself[80];
snprintf(myself, sizeof(myself), "%d/", getpid());
if (!strncmp(filename, myself, strlen(myself))) {
filename += strlen(myself);
+ if (!consume_task_directories(&filename)) {
+ return 0;
+ }
} else {
return 0;
}
--
2.23.0.rc1.153.gdeed80330f-goog
next reply other threads:[~2019-08-21 20:20 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-21 20:19 Shu-Chun Weng via Qemu-devel [this message]
2019-08-21 20:32 ` [Qemu-devel] [PATCH] linux-user: hijack open() for thread directories no-reply
2019-09-06 18:52 ` Shu-Chun Weng via Qemu-devel
2019-09-06 18:55 ` mailer
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=20190821201921.106902-1-scw@google.com \
--to=qemu-devel@nongnu.org \
--cc=laurent@vivier.eu \
--cc=riku.voipio@iki.fi \
--cc=scw@google.com \
/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.