From patchwork Fri Jun 24 09:52:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Riku Voipio X-Patchwork-Id: 640111 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rbYbP15r6z9t1K for ; Fri, 24 Jun 2016 19:54:57 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b=MXNdePhP; dkim-atps=neutral Received: from localhost ([::1]:42247 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGNp9-0002KZ-2L for incoming@patchwork.ozlabs.org; Fri, 24 Jun 2016 05:54:55 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58749) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGNnn-0000ek-EJ for qemu-devel@nongnu.org; Fri, 24 Jun 2016 05:53:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bGNnl-0003Fc-2d for qemu-devel@nongnu.org; Fri, 24 Jun 2016 05:53:30 -0400 Received: from mail-lf0-x229.google.com ([2a00:1450:4010:c07::229]:36656) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGNnk-0003F0-Mh for qemu-devel@nongnu.org; Fri, 24 Jun 2016 05:53:29 -0400 Received: by mail-lf0-x229.google.com with SMTP id q132so112557004lfe.3 for ; Fri, 24 Jun 2016 02:53:28 -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=8GthqKGeRrkRx1GIXdABBmCE7j3tYfuhrTAwOK7jBFc=; b=MXNdePhPo3iJocjoJRfY5I0RPqSWG7yVt/XZKHkqOCYjarC9ApF4Uap2j7A+xmvX1f JG20iAInj0eIFX8sZDyKX5oKsjdef8jHTDS8QtxjNzMQltndFM4MQQSh5s0CUAZe9M3p 55gg2ewyuk+zAimWjNlEso0LSaOuoFAihjs6E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8GthqKGeRrkRx1GIXdABBmCE7j3tYfuhrTAwOK7jBFc=; b=P1d9DR2VWY94XvOfg6ku5V0VmAJhv7uPfV+an5aAVzn1icGmdWxKd3eIO7X53jwroh 5RXjl7nUuCaSf8+kqGeiy5uFrfkFe98Zv70nNluaofqnBdLisf+kJLQHv+Ao8ejitsbz f2uN0wstIhFHQJcmPtS+DECQuVorC/2WxDGMyZnpfQFxUCSINIVDOn8d5GsciUgSqq9H 2bMNl/hncYGmKjjzIHAgP9YgnOvSK2ENmkocHJj9P+CKDcnBnQP38oGDiaVznINWmqVY BO61RJh8McGp9C54sPsQlhJATTX5k8Ea3lYpkWDDb4sYgG7AGqXn+aaznpkmCnwcnjh6 FXsQ== X-Gm-Message-State: ALyK8tIAFo0el/hBbkD0rA66ZfhKuAHJGMDZZ0mcDjekoi8Ut2borsF9ue3FYkLoXnuUjX0w X-Received: by 10.25.143.149 with SMTP id r143mr1019459lfd.165.1466762007771; Fri, 24 Jun 2016 02:53:27 -0700 (PDT) Received: from beaming.home (85-76-80-69-nat.elisa-mobile.fi. [85.76.80.69]) by smtp.gmail.com with ESMTPSA id o137sm798203lfe.2.2016.06.24.02.53.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 24 Jun 2016 02:53:27 -0700 (PDT) From: riku.voipio@linaro.org To: qemu-devel@nongnu.org Date: Fri, 24 Jun 2016 12:52:59 +0300 Message-Id: <0494c67c6caa499e759bdea3ae7ddc7ea52da643.1466760944.git.riku.voipio@linaro.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c07::229 Subject: [Qemu-devel] [PULL 04/24] linux-user: Don't use sigfillset() on uc->uc_sigmask 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: Peter Maydell Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Peter Maydell The kernel and libc have different ideas about what a sigset_t is -- for the kernel it is only _NSIG / 8 bytes in size (usually 8 bytes), but for libc it is much larger, 128 bytes. In most situations the difference doesn't matter, because if you pass a pointer to a libc sigset_t to the kernel it just acts on the first 8 bytes of it, but for the ucontext_t* argument to a signal handler it trips us up. The kernel allocates this ucontext_t on the stack according to its idea of the sigset_t type, but the type of the ucontext_t defined by the libc headers uses the libc type, and so do the manipulator functions like sigfillset(). This means that (1) sizeof(uc->uc_sigmask) is much larger than the actual space used on the stack (2) sigfillset(&uc->uc_sigmask) will write garbage 0xff bytes off the end of the structure, which can trash data that was on the stack before the signal handler was invoked, and may result in a crash after the handler returns To avoid this, we use a memset() of the correct size to fill the signal mask rather than using the libc function. This fixes a problem where we would crash at least some of the time on an i386 host when a signal was taken. Signed-off-by: Peter Maydell Reviewed-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/qemu.h | 5 +++++ linux-user/signal.c | 10 +++++++++- linux-user/syscall.c | 5 ----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 56f29c3..e8a5aed 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -20,6 +20,11 @@ #define THREAD __thread +/* This is the size of the host kernel's sigset_t, needed where we make + * direct system calls that take a sigset_t pointer and a size. + */ +#define SIGSET_T_SIZE (_NSIG / 8) + /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain * task_struct fields in the kernel diff --git a/linux-user/signal.c b/linux-user/signal.c index e2d55ff..9d98045 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -636,8 +636,16 @@ static void host_signal_handler(int host_signum, siginfo_t *info, * code in case the guest code provokes one in the window between * now and it getting out to the main loop. Signals will be * unblocked again in process_pending_signals(). + * + * WARNING: we cannot use sigfillset() here because the uc_sigmask + * field is a kernel sigset_t, which is much smaller than the + * libc sigset_t which sigfillset() operates on. Using sigfillset() + * would write 0xff bytes off the end of the structure and trash + * data on the struct. + * We can't use sizeof(uc->uc_sigmask) either, because the libc + * headers define the struct field with the wrong (too large) type. */ - sigfillset(&uc->uc_sigmask); + memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE); sigdelset(&uc->uc_sigmask, SIGSEGV); sigdelset(&uc->uc_sigmask, SIGBUS); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8dc8c7a..95eafeb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -123,11 +123,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2]) -/* This is the size of the host kernel's sigset_t, needed where we make - * direct system calls that take a sigset_t pointer and a size. - */ -#define SIGSET_T_SIZE (_NSIG / 8) - #undef _syscall0 #undef _syscall1 #undef _syscall2