diff options
author | Andreas Schwab <schwab@suse.de> | 2013-07-02 14:04:12 +0100 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2013-07-05 15:45:40 +0300 |
commit | 463d8e7393681b300946d6bf9f9d5b7035d718c6 (patch) | |
tree | bceafbfd3b61dad838e7e2332c40a8ffe3eb3713 /linux-user/syscall.c | |
parent | ab8bf29078e0ab8347e2ff8b4e5542f7a0c751cf (diff) |
linux-user: handle /proc/$$ like /proc/self
Some applications use /proc/$$/... (where $$ is the own pid) instead of
/proc/self/... to refer to their own proc files. Extend the interception
for open and readlink to handle this case. Also, do the same interception
in readlinkat.
Signed-off-by: Andreas Schwab <schwab@suse.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cdd0c28fff..ed2c9305b1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4973,6 +4973,30 @@ static int open_self_auxv(void *cpu_env, int fd) return 0; } +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/"); + } else if (*filename >= '1' && *filename <= '9') { + char myself[80]; + snprintf(myself, sizeof(myself), "%d/", getpid()); + if (!strncmp(filename, myself, strlen(myself))) { + filename += strlen(myself); + } else { + return 0; + } + } else { + return 0; + } + if (!strcmp(filename, entry)) { + return 1; + } + } + return 0; +} + static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { struct fake_open { @@ -4981,15 +5005,14 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) }; const struct fake_open *fake_open; static const struct fake_open fakes[] = { - { "/proc/self/maps", open_self_maps }, - { "/proc/self/stat", open_self_stat }, - { "/proc/self/auxv", open_self_auxv }, + { "maps", open_self_maps }, + { "stat", open_self_stat }, + { "auxv", open_self_auxv }, { NULL, NULL } }; for (fake_open = fakes; fake_open->filename; fake_open++) { - if (!strncmp(pathname, fake_open->filename, - strlen(fake_open->filename))) { + if (is_proc_myself(pathname, fake_open->filename)) { break; } } @@ -6262,20 +6285,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_readlink: { - void *p2, *temp; + void *p2; p = lock_user_string(arg1); p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); - if (!p || !p2) + if (!p || !p2) { ret = -TARGET_EFAULT; - else { - if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) { - char real[PATH_MAX]; - temp = realpath(exec_path,real); - ret = (temp==NULL) ? get_errno(-1) : strlen(real) ; - snprintf((char *)p2, arg3, "%s", real); - } - else - ret = get_errno(readlink(path(p), p2, arg3)); + } else if (is_proc_myself((const char *)p, "exe")) { + char real[PATH_MAX], *temp; + temp = realpath(exec_path, real); + ret = temp == NULL ? get_errno(-1) : strlen(real) ; + snprintf((char *)p2, arg3, "%s", real); + } else { + ret = get_errno(readlink(path(p), p2, arg3)); } unlock_user(p2, arg2, ret); unlock_user(p, arg1, 0); @@ -6287,10 +6308,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg2); p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); - if (!p || !p2) - ret = -TARGET_EFAULT; - else + if (!p || !p2) { + ret = -TARGET_EFAULT; + } else if (is_proc_myself((const char *)p, "exe")) { + char real[PATH_MAX], *temp; + temp = realpath(exec_path, real); + ret = temp == NULL ? get_errno(-1) : strlen(real) ; + snprintf((char *)p2, arg4, "%s", real); + } else { ret = get_errno(readlinkat(arg1, path(p), p2, arg4)); + } unlock_user(p2, arg3, ret); unlock_user(p, arg2, 0); } |