From patchwork Mon Jun 20 14:50:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 9187731 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 035736075E for ; Mon, 20 Jun 2016 15:04:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E4A2420747 for ; Mon, 20 Jun 2016 15:04:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D783E2793B; Mon, 20 Jun 2016 15:04:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3786E20747 for ; Mon, 20 Jun 2016 15:04:44 +0000 (UTC) Received: from localhost ([::1]:44197 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bF0kj-0005PP-Q4 for patchwork-qemu-devel@patchwork.kernel.org; Mon, 20 Jun 2016 11:04:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60047) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bF0XD-0007Fc-Pa for qemu-devel@nongnu.org; Mon, 20 Jun 2016 10:50:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bF0XB-0007vi-Ln for qemu-devel@nongnu.org; Mon, 20 Jun 2016 10:50:43 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:57919) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bF0XB-0007vQ-Be for qemu-devel@nongnu.org; Mon, 20 Jun 2016 10:50:41 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1bF0X8-0001SU-Mh; Mon, 20 Jun 2016 15:50:38 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Mon, 20 Jun 2016 15:50:35 +0100 Message-Id: <1466434237-19334-2-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1466434237-19334-1-git-send-email-peter.maydell@linaro.org> References: <1466434237-19334-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 1/3] linux-user: Check sigsetsize argument to 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: Riku Voipio , Laurent Vivier , patches@linaro.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Many syscalls which take a sigset_t argument also take an argument giving the size of the sigset_t. The kernel insists that this matches its idea of the type size and fails EINVAL if it is not. Implement this logic in QEMU. (This mostly just means some LTP test cases which check error cases now pass.) Signed-off-by: Peter Maydell --- linux-user/syscall.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 95eafeb..7b3d129 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7592,7 +7592,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_ALPHA) struct target_sigaction act, oact, *pact = 0; struct target_rt_sigaction *rt_act; - /* ??? arg4 == sizeof(sigset_t). */ + + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } if (arg2) { if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1)) goto efault; @@ -7616,6 +7620,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction *act; struct target_sigaction *oact; + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } if (arg2) { if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) goto efault; @@ -7747,6 +7755,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int how = arg1; sigset_t set, oldset, *set_ptr; + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + goto fail; + } + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: @@ -7797,6 +7810,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigpending: { sigset_t set; + + /* Yes, this check is >, not != like most. We follow the kernel's + * logic and it does it like this because it implements + * NR_sigpending through the same code path, and in that case + * the old_sigset_t is smaller in size. + */ + if (arg2 > sizeof(target_sigset_t)) { + return -TARGET_EINVAL; + } + ret = get_errno(sigpending(&set)); if (!is_error(ret)) { if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) @@ -7830,6 +7853,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigsuspend: { TaskState *ts = cpu->opaque; + + if (arg2 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) goto efault; target_to_host_sigset(&ts->sigsuspend_mask, p); @@ -7847,6 +7875,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec uts, *puts; siginfo_t uinfo; + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) goto efault; target_to_host_sigset(&set, p); @@ -9095,6 +9128,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } if (arg4) { + if (arg5 != sizeof(target_sigset_t)) { + unlock_user(target_pfd, arg1, 0); + ret = -TARGET_EINVAL; + break; + } + target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1); if (!target_set) { unlock_user(target_pfd, arg1, 0); @@ -10914,6 +10953,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t _set, *set = &_set; if (arg5) { + if (arg6 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } + target_set = lock_user(VERIFY_READ, arg5, sizeof(target_sigset_t), 1); if (!target_set) {