From patchwork Tue Jun 28 19:12:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Riku Voipio X-Patchwork-Id: 641706 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 3rfFzq1nmkz9s9n for ; Wed, 29 Jun 2016 05:21:59 +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=SeOTKbmb; dkim-atps=neutral Received: from localhost ([::1]:39030 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHya5-00035M-66 for incoming@patchwork.ozlabs.org; Tue, 28 Jun 2016 15:21:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38319) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHyRa-0001ip-FR for qemu-devel@nongnu.org; Tue, 28 Jun 2016 15:13:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bHyRY-0006pn-5n for qemu-devel@nongnu.org; Tue, 28 Jun 2016 15:13:09 -0400 Received: from mail-lf0-x236.google.com ([2a00:1450:4010:c07::236]:33235) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHyRX-0006pZ-OW for qemu-devel@nongnu.org; Tue, 28 Jun 2016 15:13:08 -0400 Received: by mail-lf0-x236.google.com with SMTP id f6so18199532lfg.0 for ; Tue, 28 Jun 2016 12:13:07 -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=fmGLr+/iuj6bDLpfOsnWTVFxxS4GryNzTNSxbs2grB0=; b=SeOTKbmbcCtVAEV+0hDbsgvsIUjAQrROprEfHG/eCU3JrIxwGDDt+GBdUmlgJFksMo 43sCzTtEpReeS4PSR5/Fq3QYX1ERvUBIDHu9q8QEOTFVxiDOZBo0zLqiCS3Ro1qS9HBN tKzoRlRfPGURAdLpi7OMcoU2OwGdX11BmfypQ= 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=fmGLr+/iuj6bDLpfOsnWTVFxxS4GryNzTNSxbs2grB0=; b=WAEFnKe2xcUCGlAJYAHU5GQdDyALd6MiSoI7i56vEnysfNGYC6mPMr4btedrGHyv70 jarD31kBCyDaL38At4kEBOFH45/AsRV5d7eGjNADOv012CteU4NvcEaQCMjOvAm03I6Z Fcpa9QLgfeiAvi/6FupPwhPsYOT1c3EpqixyYyNDrdOUoOod/Na61latVaCYc7ep7BIy KKqD1WauRrJmtt6mJ8rQPglJdV6BNsjcugi/f2koLrzw2/CGtzV75XtFlMLXkak0Jboo 0hu/1X7/U0vOyEk9etCsQvN4RUBQqiAkzeW1s8bpVp0irQIprOoREsVNQ2ufoCjB5K4K qRkw== X-Gm-Message-State: ALyK8tLOPZCPb4iXDEV/wa+bRuLPx1M5t7HUf1ZsVg6NuhVwOOuId1fYR9Au2y9Fafnod5oj X-Received: by 10.25.4.4 with SMTP id 4mr1549630lfe.208.1467141186761; Tue, 28 Jun 2016 12:13:06 -0700 (PDT) Received: from beaming.home (91-157-170-157.elisa-laajakaista.fi. [91.157.170.157]) by smtp.gmail.com with ESMTPSA id h10sm4262823ljh.38.2016.06.28.12.13.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 28 Jun 2016 12:13:05 -0700 (PDT) From: riku.voipio@linaro.org To: qemu-devel@nongnu.org Date: Tue, 28 Jun 2016 22:12:38 +0300 Message-Id: <1d48fdd9d84aab1bd32c1f70947932f5d90f92aa.1467138806.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::236 Subject: [Qemu-devel] [PULL v2 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 3dfaea9..5166ff9 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