From patchwork Sat Aug 18 19:01:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 144504 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp2204775ljj; Sat, 18 Aug 2018 12:08:11 -0700 (PDT) X-Google-Smtp-Source: AA+uWPwdeX981QilQ4rHurxgl6gMNpxmToe7NM4u7NZ2LNnRefpVie8/9v1DOyskrk+xKR0cnZ7e X-Received: by 2002:ac8:60d7:: with SMTP id i23-v6mr2157505qtm.403.1534619291649; Sat, 18 Aug 2018 12:08:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1534619291; cv=none; d=google.com; s=arc-20160816; b=aHXxrkXMEAdFx/fI6EfpXiPmsVchNku/MlCAv1+pApDpqanIDKruf3+Kttq8UYgF86 Eb2eF9q4RzkDtH08cxvVjupx+B02q7gyR7XYhOesnMiUaSxXYBuwzPQCJn7cXWLn9vH2 g5NKMIhi+ssrbqIJdfAJGZtEgT73jgKGPCwtmyYiDjRWNSdF/Cb2eW7EqdCk0EcQEjIE kgPHMrsLN0qnaAERFWPML1jlrdev/iDRCiqjZy71w7CE5/LtMN7LK1czGTjXCyihi4cy 3mQ1w/HdGaX0w7Lwyhev8g8HMqRIJHj5bp6tOCG6sbPNtGChEci2vLR2ULtRsyKy+Tpf AjAA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature:arc-authentication-results; bh=DTrWzgSCl4Qjb3hXn8PP2cYbogkp5c70fsgpLsO4NG8=; b=geBm6MGSb3yNZ8oJqSFtfwYl0RnYsaf6XiU4gsAF02Xpcoy3WaEVOJrk5Zvkz4eylx uR5jXej8NCbxHEz37ZdzoA9tWaH78Kasq+iE8NiklY9d8982SBpYCdOpCvHv6CPV8lp2 6PpQSIvpfJnzEpvrsExQCeeNv1G0Y9UmzwRYtASSPKqYY0kh7fd+Fasv1Pe1uUdm3/Z4 q9OyXyz/dHjV+ath/yH10qnka7aZnr9IEhkwnEVLJCT4mJCZGfFfWvQ6+DhnhoYtMo/g 83e4GZzp3O/T3UvfqzAOye1n0W0bERAikmJXCDTPA6wGtyR4+0UVpnisN7IaYMkDs5zs leWg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=ZSs2Zv1Q; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id t2-v6si4483763qvn.81.2018.08.18.12.08.11 for (version=TLS1 cipher=AES128-SHA bits=128/128); Sat, 18 Aug 2018 12:08:11 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=ZSs2Zv1Q; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:40144 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fr6a2-00015Q-V7 for patch@linaro.org; Sat, 18 Aug 2018 15:08:11 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55292) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fr6Tl-0005Jm-2b for qemu-devel@nongnu.org; Sat, 18 Aug 2018 15:01:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fr6Ti-0007F0-E2 for qemu-devel@nongnu.org; Sat, 18 Aug 2018 15:01:41 -0400 Received: from mail-pg1-x533.google.com ([2607:f8b0:4864:20::533]:45557) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fr6Ti-0007Ee-43 for qemu-devel@nongnu.org; Sat, 18 Aug 2018 15:01:38 -0400 Received: by mail-pg1-x533.google.com with SMTP id f1-v6so4943739pgq.12 for ; Sat, 18 Aug 2018 12:01:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=DTrWzgSCl4Qjb3hXn8PP2cYbogkp5c70fsgpLsO4NG8=; b=ZSs2Zv1Qq/ZHAemwAQJli+p8RJ5U3zIB6guOLRcPRCXeeitszRaTv21tROZDb5b1Z1 cQsZE1WFdFPKqRBwbWfW/i0FyqD2hYsuOC1ea1zn/eB8lhtTGS7WsBXy5cReA8nP3G5D f6Ke/BvLZLJKHuXr3O3pQoL91jFcCGYtGIER8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=DTrWzgSCl4Qjb3hXn8PP2cYbogkp5c70fsgpLsO4NG8=; b=gAXqR32nY+ugU60F01kwiiq3wJDnlfOML6o92T5Widbyr/w8pGyRx5ZGimrp2uLYkM Vc092/7X2cKt2Q5WTIvchJrFO7dvA78IK7dTJYASmMWgOdMOH927UxZRVZKNfwuu+IW/ QE/D9elshhpBO6u3+KLr/vxvUWFEKjIrPe2+uZNlf1Vh2WrUaRDsx/rf73/AdXjaelt4 mNnkE4S2UsH+2JL/YwC8sgdbTBUmhtj/T7FmjDBpvLdQsLlT0DcG0S+yMWvs6x3TW/A/ P7GusVFu9qhLjJO1UM1QiuEgvOGlU1GN8Goq4VbeuiWwqc7Hnwm6eEXDld3QBG7fCeJW 1vSA== X-Gm-Message-State: AOUpUlEcP+My4m1bKP0XMf2g9Qq6njHYdRFhRjHa/MtkFy1YkYKhADAj Zl1zv7UJqLhhaPJiTPL9yqLpQY+9ai8= X-Received: by 2002:a63:1b49:: with SMTP id b9-v6mr36806839pgm.72.1534618895482; Sat, 18 Aug 2018 12:01:35 -0700 (PDT) Received: from cloudburst.twiddle.net (97-113-8-179.tukw.qwest.net. [97.113.8.179]) by smtp.gmail.com with ESMTPSA id q85-v6sm9362783pfa.151.2018.08.18.12.01.33 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sat, 18 Aug 2018 12:01:33 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Sat, 18 Aug 2018 12:01:12 -0700 Message-Id: <20180818190118.12911-11-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180818190118.12911-1-richard.henderson@linaro.org> References: <20180818190118.12911-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::533 Subject: [Qemu-devel] [PATCH v4 10/16] linux-user: Split out some simple file syscalls X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: laurent@vivier.eu Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" This includes close, open, openat, read, readlink, readlinkat, write. Signed-off-by: Richard Henderson --- linux-user/strace.c | 64 ----- linux-user/syscall-file.inc.c | 440 ++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 393 ++---------------------------- linux-user/strace.list | 21 -- 4 files changed, 463 insertions(+), 455 deletions(-) create mode 100644 linux-user/syscall-file.inc.c -- 2.17.1 diff --git a/linux-user/strace.c b/linux-user/strace.c index 792644cc0d..11e0c86554 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -2213,41 +2213,6 @@ print_mq_open(const struct syscallname *name, } #endif -#ifdef TARGET_NR_open -static void -print_open(const struct syscallname *name, - abi_long arg0, abi_long arg1, abi_long arg2, - abi_long arg3, abi_long arg4, abi_long arg5) -{ - int is_creat = (arg1 & TARGET_O_CREAT); - - print_syscall_prologue(name); - print_string(arg0, 0); - print_open_flags(arg1, (is_creat == 0)); - if (is_creat) - print_file_mode(arg2, 1); - print_syscall_epilogue(name); -} -#endif - -#ifdef TARGET_NR_openat -static void -print_openat(const struct syscallname *name, - abi_long arg0, abi_long arg1, abi_long arg2, - abi_long arg3, abi_long arg4, abi_long arg5) -{ - int is_creat = (arg2 & TARGET_O_CREAT); - - print_syscall_prologue(name); - print_at_dirfd(arg0, 0); - print_string(arg1, 0); - print_open_flags(arg2, (is_creat == 0)); - if (is_creat) - print_file_mode(arg3, 1); - print_syscall_epilogue(name); -} -#endif - #ifdef TARGET_NR_mq_unlink static void print_mq_unlink(const struct syscallname *name, @@ -2276,35 +2241,6 @@ print_fstatat64(const struct syscallname *name, #define print_newfstatat print_fstatat64 #endif -#ifdef TARGET_NR_readlink -static void -print_readlink(const struct syscallname *name, - abi_long arg0, abi_long arg1, abi_long arg2, - abi_long arg3, abi_long arg4, abi_long arg5) -{ - print_syscall_prologue(name); - print_string(arg0, 0); - print_pointer(arg1, 0); - print_raw_param("%u", arg2, 1); - print_syscall_epilogue(name); -} -#endif - -#ifdef TARGET_NR_readlinkat -static void -print_readlinkat(const struct syscallname *name, - abi_long arg0, abi_long arg1, abi_long arg2, - abi_long arg3, abi_long arg4, abi_long arg5) -{ - print_syscall_prologue(name); - print_at_dirfd(arg0, 0); - print_string(arg1, 0); - print_pointer(arg2, 0); - print_raw_param("%u", arg3, 1); - print_syscall_epilogue(name); -} -#endif - #ifdef TARGET_NR_rename static void print_rename(const struct syscallname *name, diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c new file mode 100644 index 0000000000..aecc63682f --- /dev/null +++ b/linux-user/syscall-file.inc.c @@ -0,0 +1,440 @@ +/* + * Linux file-related syscalls + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + + +/* + * Helpers for do_openat, manipulating /proc/self/foo. + */ + +static int open_self_cmdline(void *cpu_env, int fd) +{ + CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); + struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm; + int i; + + for (i = 0; i < bprm->argc; i++) { + size_t len = strlen(bprm->argv[i]) + 1; + + if (write(fd, bprm->argv[i], len) != len) { + return -1; + } + } + + return 0; +} + +static int open_self_maps(void *cpu_env, int fd) +{ + CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); + TaskState *ts = cpu->opaque; + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t read; + + fp = fopen("/proc/self/maps", "r"); + if (fp == NULL) { + return -1; + } + + while ((read = getline(&line, &len, fp)) != -1) { + int fields, dev_maj, dev_min, inode; + uint64_t min, max, offset; + char flag_r, flag_w, flag_x, flag_p; + char path[512] = ""; + + fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %" + PRIx64" %x:%x %d %512s", + &min, &max, &flag_r, &flag_w, &flag_x, + &flag_p, &offset, &dev_maj, &dev_min, &inode, path); + + if ((fields < 10) || (fields > 11)) { + continue; + } + if (h2g_valid(min)) { + int flags = page_get_flags(h2g(min)); + + if (!h2g_valid(max - 1)) { + max = (uintptr_t)g2h(GUEST_ADDR_MAX) + 1; + } + if (page_check_range(h2g(min), max - min, flags) == -1) { + continue; + } + if (h2g(min) == ts->info->stack_limit) { + pstrcpy(path, sizeof(path), " [stack]"); + } + dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx + " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n", + h2g(min), h2g(max - 1) + 1, flag_r, flag_w, + flag_x, flag_p, offset, dev_maj, dev_min, inode, + path[0] ? " " : "", path); + } + } + + free(line); + fclose(fp); + + return 0; +} + +static int open_self_stat(void *cpu_env, int fd) +{ + CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); + TaskState *ts = cpu->opaque; + abi_ulong start_stack = ts->info->start_stack; + int i; + + for (i = 0; i < 44; i++) { + char buf[128]; + int len; + uint64_t val = 0; + + if (i == 0) { + /* pid */ + val = getpid(); + snprintf(buf, sizeof(buf), "%"PRId64 " ", val); + } else if (i == 1) { + /* app name */ + snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]); + } else if (i == 27) { + /* stack bottom */ + val = start_stack; + snprintf(buf, sizeof(buf), "%"PRId64 " ", val); + } else { + /* for the rest, there is MasterCard */ + snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' '); + } + + len = strlen(buf); + if (write(fd, buf, len) != len) { + return -1; + } + } + + return 0; +} + +static int open_self_auxv(void *cpu_env, int fd) +{ + CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); + TaskState *ts = cpu->opaque; + abi_ulong auxv = ts->info->saved_auxv; + abi_ulong len = ts->info->auxv_len; + char *ptr; + + /* + * Auxiliary vector is stored in target process stack. + * read in whole auxv vector and copy it to file + */ + ptr = lock_user(VERIFY_READ, auxv, len, 0); + if (ptr != NULL) { + while (len > 0) { + ssize_t r; + r = write(fd, ptr, len); + if (r <= 0) { + break; + } + len -= r; + ptr += r; + } + lseek(fd, 0, SEEK_SET); + unlock_user(ptr, auxv, len); + } + + 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; +} + +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +static int is_proc(const char *filename, const char *entry) +{ + return strcmp(filename, entry) == 0; +} + +static int open_net_route(void *cpu_env, int fd) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t read; + + fp = fopen("/proc/net/route", "r"); + if (fp == NULL) { + return -1; + } + + /* read header */ + + read = getline(&line, &len, fp); + dprintf(fd, "%s", line); + + /* read routes */ + + while ((read = getline(&line, &len, fp)) != -1) { + char iface[16]; + uint32_t dest, gw, mask; + unsigned int flags, refcnt, use, metric, mtu, window, irtt; + sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n", + iface, &dest, &gw, &flags, &refcnt, &use, &metric, + &mask, &mtu, &window, &irtt); + dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n", + iface, tswap32(dest), tswap32(gw), flags, refcnt, use, + metric, tswap32(mask), mtu, window, irtt); + } + + free(line); + fclose(fp); + + return 0; +} +#endif + +static abi_long do_openat(void *cpu_env, int dirfd, abi_ulong target_path, + int target_flags, int mode) +{ + struct fake_open { + const char *filename; + int (*fill)(void *cpu_env, int fd); + int (*cmp)(const char *s1, const char *s2); + }; + static const struct fake_open fakes[] = { + { "maps", open_self_maps, is_proc_myself }, + { "stat", open_self_stat, is_proc_myself }, + { "auxv", open_self_auxv, is_proc_myself }, + { "cmdline", open_self_cmdline, is_proc_myself }, +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) + { "/proc/net/route", open_net_route, is_proc }, +#endif + }; + + char *pathname = lock_user_string(target_path); + int flags = target_to_host_bitmask(target_flags, fcntl_flags_tbl); + int i, ret; + + if (!pathname) { + return -TARGET_EFAULT; + } + + if (is_proc_myself(pathname, "exe")) { + ret = qemu_getauxval(AT_EXECFD); + if (ret == 0) { + ret = get_errno(safe_openat(dirfd, exec_path, flags, mode)); + } + goto done; + } + + for (i = 0; i < ARRAY_SIZE(fakes); ++i) { + if (fakes[i].cmp(pathname, fakes[i].filename)) { + const char *tmpdir; + char filename[PATH_MAX]; + int r; + + /* Create temporary file. */ + tmpdir = getenv("TMPDIR"); + if (!tmpdir) { + tmpdir = "/tmp"; + } + snprintf(filename, sizeof(filename), + "%s/qemu-open.XXXXXX", tmpdir); + ret = mkstemp(filename); + if (ret < 0) { + ret = -TARGET_ENOENT; + goto done; + } + unlink(filename); + + /* Add contents to the temporary file. */ + r = fakes[i].fill(cpu_env, ret); + if (r) { + close(ret); + ret = -TARGET_ENOENT; + goto done; + } + + /* Reset pointer to the beginning. */ + lseek(ret, 0, SEEK_SET); + goto done; + } + } + ret = get_errno(safe_openat(dirfd, path(pathname), flags, mode)); + + done: + fd_trans_unregister(ret); + unlock_user(pathname, target_path, 0); + return ret; +} + +SYSCALL_IMPL(close) +{ + fd_trans_unregister(arg1); + return get_errno(close(arg1)); +} +SYSCALL_DEF(close, ARG_DEC); + +#ifdef TARGET_NR_open +SYSCALL_IMPL(open) +{ + return do_openat(cpu_env, AT_FDCWD, arg1, arg2, arg3); +} +SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG); +#endif + +SYSCALL_IMPL(openat) +{ + return do_openat(cpu_env, arg1, arg2, arg3, arg4); +} +SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG); + +SYSCALL_IMPL(read) +{ + abi_long ret; + void *p; + + if (arg3 == 0) { + return 0; + } + p = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p) { + return -TARGET_EFAULT; + } + ret = get_errno(safe_read(arg1, p, arg3)); + + if (!is_error(ret)) { + TargetFdDataFunc trans = fd_trans_host_to_target_data(arg1); + if (trans) { + ret = trans(p, ret); + } + } + unlock_user(p, arg2, ret); + return ret; +} +SYSCALL_DEF(read, ARG_DEC, ARG_PTR, ARG_DEC); + +static abi_long do_readlink_proc_exe(char *buf, abi_ulong bufsiz) +{ + char real[PATH_MAX]; + char *temp = realpath(exec_path, real); + abi_long ret; + + /* Return value is # of bytes that we wrote to the buffer. */ + if (temp == NULL) { + return -host_to_target_errno(errno); + } + ret = MIN(strlen(real), bufsiz); + /* We cannot NUL terminate the string. */ + memcpy(buf, real, ret); + return ret; +} + +#ifdef TARGET_NR_readlink +SYSCALL_IMPL(readlink) +{ + char *p = lock_user_string(arg1); + abi_ulong bufsiz = arg3; + void *buf = lock_user(VERIFY_WRITE, arg2, bufsiz, 0); + abi_long ret; + + if (!p || !buf) { + ret = -TARGET_EFAULT; + } else if (!bufsiz) { + /* Short circuit this for the magic exe check. */ + ret = -TARGET_EINVAL; + } else if (is_proc_myself(p, "exe")) { + ret = do_readlink_proc_exe(buf, bufsiz); + } else { + ret = get_errno(readlink(path(p), buf, bufsiz)); + } + unlock_user(buf, arg2, ret); + unlock_user(p, arg1, 0); + return ret; +} +SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC); +#endif + +#ifdef TARGET_NR_readlinkat +SYSCALL_IMPL(readlinkat) +{ + char *p = lock_user_string(arg2); + abi_ulong bufsiz = arg4; + void *buf = lock_user(VERIFY_WRITE, arg3, bufsiz, 0); + abi_long ret; + + if (!p || !buf) { + ret = -TARGET_EFAULT; + } else if (!bufsiz) { + /* Short circuit this for the magic exe check. */ + ret = -TARGET_EINVAL; + } else if (is_proc_myself(p, "exe")) { + ret = do_readlink_proc_exe(buf, bufsiz); + } else { + ret = get_errno(readlinkat(arg1, path(p), buf, bufsiz)); + } + unlock_user(buf, arg3, ret); + unlock_user(p, arg2, 0); + return ret; +} +SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC); +#endif + +SYSCALL_IMPL(write) +{ + TargetFdDataFunc trans = fd_trans_target_to_host_data(arg1); + void *p = lock_user(VERIFY_READ, arg2, arg3, 1); + abi_long ret; + + if (!p) { + return -TARGET_EFAULT; + } + if (trans) { + void *copy = g_malloc(arg3); + memcpy(copy, p, arg3); + ret = trans(copy, arg3); + if (ret >= 0) { + ret = get_errno(safe_write(arg1, copy, ret)); + } + g_free(copy); + } else { + ret = get_errno(safe_write(arg1, p, arg3)); + } + unlock_user(p, arg2, 0); + return ret; +} +SYSCALL_DEF(write, ARG_DEC, ARG_PTR, ARG_DEC); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3b59f7ed65..f757ae87b0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7589,267 +7589,6 @@ int host_to_target_waitstatus(int status) return status; } -static int open_self_cmdline(void *cpu_env, int fd) -{ - CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); - struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm; - int i; - - for (i = 0; i < bprm->argc; i++) { - size_t len = strlen(bprm->argv[i]) + 1; - - if (write(fd, bprm->argv[i], len) != len) { - return -1; - } - } - - return 0; -} - -static int open_self_maps(void *cpu_env, int fd) -{ - CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); - TaskState *ts = cpu->opaque; - FILE *fp; - char *line = NULL; - size_t len = 0; - ssize_t read; - - fp = fopen("/proc/self/maps", "r"); - if (fp == NULL) { - return -1; - } - - while ((read = getline(&line, &len, fp)) != -1) { - int fields, dev_maj, dev_min, inode; - uint64_t min, max, offset; - char flag_r, flag_w, flag_x, flag_p; - char path[512] = ""; - fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d" - " %512s", &min, &max, &flag_r, &flag_w, &flag_x, - &flag_p, &offset, &dev_maj, &dev_min, &inode, path); - - if ((fields < 10) || (fields > 11)) { - continue; - } - if (h2g_valid(min)) { - int flags = page_get_flags(h2g(min)); - max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1; - if (page_check_range(h2g(min), max - min, flags) == -1) { - continue; - } - if (h2g(min) == ts->info->stack_limit) { - pstrcpy(path, sizeof(path), " [stack]"); - } - dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx - " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n", - h2g(min), h2g(max - 1) + 1, flag_r, flag_w, - flag_x, flag_p, offset, dev_maj, dev_min, inode, - path[0] ? " " : "", path); - } - } - - free(line); - fclose(fp); - - return 0; -} - -static int open_self_stat(void *cpu_env, int fd) -{ - CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); - TaskState *ts = cpu->opaque; - abi_ulong start_stack = ts->info->start_stack; - int i; - - for (i = 0; i < 44; i++) { - char buf[128]; - int len; - uint64_t val = 0; - - if (i == 0) { - /* pid */ - val = getpid(); - snprintf(buf, sizeof(buf), "%"PRId64 " ", val); - } else if (i == 1) { - /* app name */ - snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]); - } else if (i == 27) { - /* stack bottom */ - val = start_stack; - snprintf(buf, sizeof(buf), "%"PRId64 " ", val); - } else { - /* for the rest, there is MasterCard */ - snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' '); - } - - len = strlen(buf); - if (write(fd, buf, len) != len) { - return -1; - } - } - - return 0; -} - -static int open_self_auxv(void *cpu_env, int fd) -{ - CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); - TaskState *ts = cpu->opaque; - abi_ulong auxv = ts->info->saved_auxv; - abi_ulong len = ts->info->auxv_len; - char *ptr; - - /* - * Auxiliary vector is stored in target process stack. - * read in whole auxv vector and copy it to file - */ - ptr = lock_user(VERIFY_READ, auxv, len, 0); - if (ptr != NULL) { - while (len > 0) { - ssize_t r; - r = write(fd, ptr, len); - if (r <= 0) { - break; - } - len -= r; - ptr += r; - } - lseek(fd, 0, SEEK_SET); - unlock_user(ptr, auxv, len); - } - - 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; -} - -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) -static int is_proc(const char *filename, const char *entry) -{ - return strcmp(filename, entry) == 0; -} - -static int open_net_route(void *cpu_env, int fd) -{ - FILE *fp; - char *line = NULL; - size_t len = 0; - ssize_t read; - - fp = fopen("/proc/net/route", "r"); - if (fp == NULL) { - return -1; - } - - /* read header */ - - read = getline(&line, &len, fp); - dprintf(fd, "%s", line); - - /* read routes */ - - while ((read = getline(&line, &len, fp)) != -1) { - char iface[16]; - uint32_t dest, gw, mask; - unsigned int flags, refcnt, use, metric, mtu, window, irtt; - sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n", - iface, &dest, &gw, &flags, &refcnt, &use, &metric, - &mask, &mtu, &window, &irtt); - dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n", - iface, tswap32(dest), tswap32(gw), flags, refcnt, use, - metric, tswap32(mask), mtu, window, irtt); - } - - free(line); - fclose(fp); - - return 0; -} -#endif - -static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) -{ - struct fake_open { - const char *filename; - int (*fill)(void *cpu_env, int fd); - int (*cmp)(const char *s1, const char *s2); - }; - const struct fake_open *fake_open; - static const struct fake_open fakes[] = { - { "maps", open_self_maps, is_proc_myself }, - { "stat", open_self_stat, is_proc_myself }, - { "auxv", open_self_auxv, is_proc_myself }, - { "cmdline", open_self_cmdline, is_proc_myself }, -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) - { "/proc/net/route", open_net_route, is_proc }, -#endif - { NULL, NULL, NULL } - }; - - if (is_proc_myself(pathname, "exe")) { - int execfd = qemu_getauxval(AT_EXECFD); - return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode); - } - - for (fake_open = fakes; fake_open->filename; fake_open++) { - if (fake_open->cmp(pathname, fake_open->filename)) { - break; - } - } - - if (fake_open->filename) { - const char *tmpdir; - char filename[PATH_MAX]; - int fd, r; - - /* create temporary file to map stat to */ - tmpdir = getenv("TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; - snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir); - fd = mkstemp(filename); - if (fd < 0) { - return fd; - } - unlink(filename); - - if ((r = fake_open->fill(cpu_env, fd))) { - int e = errno; - close(fd); - errno = e; - return r; - } - lseek(fd, 0, SEEK_SET); - - return fd; - } - - return safe_openat(dirfd, path(pathname), flags, mode); -} - #define TIMER_MAGIC 0x0caf0000 #define TIMER_MAGIC_MASK 0xffff0000 @@ -8048,57 +7787,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, preexit_cleanup(cpu_env, arg1); _exit(arg1); return 0; /* avoid warning */ - case TARGET_NR_read: - if (arg3 == 0) { - return 0; - } else { - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - return -TARGET_EFAULT; - ret = get_errno(safe_read(arg1, p, arg3)); - if (ret >= 0 && - fd_trans_host_to_target_data(arg1)) { - ret = fd_trans_host_to_target_data(arg1)(p, ret); - } - unlock_user(p, arg2, ret); - } - return ret; - case TARGET_NR_write: - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - return -TARGET_EFAULT; - if (fd_trans_target_to_host_data(arg1)) { - void *copy = g_malloc(arg3); - memcpy(copy, p, arg3); - ret = fd_trans_target_to_host_data(arg1)(copy, arg3); - if (ret >= 0) { - ret = get_errno(safe_write(arg1, copy, ret)); - } - g_free(copy); - } else { - ret = get_errno(safe_write(arg1, p, arg3)); - } - unlock_user(p, arg2, 0); - return ret; - -#ifdef TARGET_NR_open - case TARGET_NR_open: - if (!(p = lock_user_string(arg1))) - return -TARGET_EFAULT; - ret = get_errno(do_openat(cpu_env, AT_FDCWD, p, - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); - fd_trans_unregister(ret); - unlock_user(p, arg1, 0); - return ret; -#endif - case TARGET_NR_openat: - if (!(p = lock_user_string(arg2))) - return -TARGET_EFAULT; - ret = get_errno(do_openat(cpu_env, arg1, p, - target_to_host_bitmask(arg3, fcntl_flags_tbl), - arg4)); - fd_trans_unregister(ret); - unlock_user(p, arg2, 0); - return ret; #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) case TARGET_NR_name_to_handle_at: ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5); @@ -8110,10 +7798,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, fd_trans_unregister(ret); return ret; #endif - case TARGET_NR_close: - fd_trans_unregister(arg1); - return get_errno(close(arg1)); - case TARGET_NR_brk: return do_brk(arg1); #ifdef TARGET_NR_fork @@ -9375,59 +9059,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } return ret; #endif -#ifdef TARGET_NR_readlink - case TARGET_NR_readlink: - { - void *p2; - p = lock_user_string(arg1); - p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); - if (!p || !p2) { - ret = -TARGET_EFAULT; - } else if (!arg3) { - /* Short circuit this for the magic exe check. */ - ret = -TARGET_EINVAL; - } else if (is_proc_myself((const char *)p, "exe")) { - char real[PATH_MAX], *temp; - temp = realpath(exec_path, real); - /* Return value is # of bytes that we wrote to the buffer. */ - if (temp == NULL) { - ret = get_errno(-1); - } else { - /* Don't worry about sign mismatch as earlier mapping - * logic would have thrown a bad address error. */ - ret = MIN(strlen(real), arg3); - /* We cannot NUL terminate the string. */ - memcpy(p2, real, ret); - } - } else { - ret = get_errno(readlink(path(p), p2, arg3)); - } - unlock_user(p2, arg2, ret); - unlock_user(p, arg1, 0); - } - return ret; -#endif -#if defined(TARGET_NR_readlinkat) - case TARGET_NR_readlinkat: - { - void *p2; - p = lock_user_string(arg2); - p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); - 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); - } - return ret; -#endif #ifdef TARGET_NR_swapon case TARGET_NR_swapon: if (!(p = lock_user_string(arg1))) @@ -12482,11 +12113,33 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return ret; } +#include "syscall-file.inc.c" + static const SyscallDef *syscall_table(int num) { -#define S(NAME) case TARGET_NR_##NAME: return &def_##NAME; +#define S(NAME) case TARGET_NR_##NAME: return &def_##NAME switch (num) { + /* + * Unconditional syscalls. + */ + S(close); + S(openat); + S(read); + S(write); + + /* + * Conditional syscalls. + */ +#ifdef TARGET_NR_open + S(open); +#endif +#ifdef TARGET_NR_readlink + S(readlink); +#endif +#ifdef TARGET_NR_readlinkat + S(readlinkat); +#endif } return NULL; diff --git a/linux-user/strace.list b/linux-user/strace.list index ff8bb19f5f..f3a1b0fe31 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -97,9 +97,6 @@ #ifdef TARGET_NR_clone { TARGET_NR_clone, "clone" , NULL, print_clone, NULL }, #endif -#ifdef TARGET_NR_close -{ TARGET_NR_close, "close" , "%s(%d)", NULL, NULL }, -#endif #ifdef TARGET_NR_connect { TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL }, #endif @@ -677,12 +674,6 @@ #ifdef TARGET_NR_olduname { TARGET_NR_olduname, "olduname" , NULL, NULL, NULL }, #endif -#ifdef TARGET_NR_open -{ TARGET_NR_open, "open" , NULL, print_open, NULL }, -#endif -#ifdef TARGET_NR_openat -{ TARGET_NR_openat, "openat" , NULL, print_openat, NULL }, -#endif #ifdef TARGET_NR_osf_adjtime { TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL }, #endif @@ -1076,21 +1067,12 @@ #ifdef TARGET_NR_quotactl { TARGET_NR_quotactl, "quotactl" , NULL, NULL, NULL }, #endif -#ifdef TARGET_NR_read -{ TARGET_NR_read, "read" , "%s(%d,%#x,%d)", NULL, NULL }, -#endif #ifdef TARGET_NR_readahead { TARGET_NR_readahead, "readahead" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_readdir { TARGET_NR_readdir, "readdir" , NULL, NULL, NULL }, #endif -#ifdef TARGET_NR_readlink -{ TARGET_NR_readlink, "readlink" , NULL, print_readlink, NULL }, -#endif -#ifdef TARGET_NR_readlinkat -{ TARGET_NR_readlinkat, "readlinkat" , NULL, print_readlinkat, NULL }, -#endif #ifdef TARGET_NR_readv { TARGET_NR_readv, "readv" , NULL, NULL, NULL }, #endif @@ -1626,9 +1608,6 @@ #ifdef TARGET_NR_waitpid { TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL }, #endif -#ifdef TARGET_NR_write -{ TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL }, -#endif #ifdef TARGET_NR_writev { TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL }, #endif