From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-20.4 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A07D3C388F7 for ; Wed, 4 Nov 2020 21:18:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 40D1520825 for ; Wed, 4 Nov 2020 21:18:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="AbC8/yKS" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730864AbgKDVSe (ORCPT ); Wed, 4 Nov 2020 16:18:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53494 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726152AbgKDVSe (ORCPT ); Wed, 4 Nov 2020 16:18:34 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0DBCCC0613D3 for ; Wed, 4 Nov 2020 13:18:33 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id j2so104861ybb.12 for ; Wed, 04 Nov 2020 13:18:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=wLKH34A8RJSu6n0zXlFAJjjAxtGr+rwms4LzWjAiJ8A=; b=AbC8/yKS7Exu2XftLXv44RO1/h8baCloytw7BNg4acM65ljDUKvxxG2ut9J9xvaUFl DPeXHZVkOXkjFLT+bIqiOW7nlkxaPuYoZ9/ZZRGaG5DjPiBjrrJFE28BhMIzGCTz6y4c +RTHg13PX9ADlowTkx8i03yHdxyzfKrTZw+Fe8ir0Yf6OwSzVJP1OBWQeIyGpZeT8xTb 7Qiyye+8NHfHYLLS1Ltylw2io8rILgmdUJiQvsGTo/NM1IN7zmUBaaHB+a88yAJ6YCgt AFaWeLHniHCMzG5QQ3rP70nZy1sUSW3/70EEQG9ZUH+wc6KD1Pna7QGkjI/m/B9gqZ0X 4Hsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=wLKH34A8RJSu6n0zXlFAJjjAxtGr+rwms4LzWjAiJ8A=; b=GJAkf78kZiLzQUSldE50Flvcua16bPCEKVk46x3aQxicBlW4H1+WvD/QS99ALlN1hr keA2d8MYaW7TuujFibTnxEXuargsu77da6DG7Sqkpy6QtfUCxC4Fdis68ld3FfMDCfqD LFNZnY+eXUI2eRh0iFgKNqdGpV0D3ETZG8a4nYnQf8mEHfYl/vdEBK4rC6zIqWeZibRv mNzb/lBzCQWce7/F1+p0L0OyiRN0W6d8f/7/ndIeuiTdij5+v9UwPT/c8ynbl14WZiob 57lLGowl+p9NOnkHp2+iEy2pr8UoqpHxQYtqE9MPPrInABsN3DomHPIMrRkUZTlwHJWO inTA== X-Gm-Message-State: AOAM531bw4G7QRTRyn8nF5DcM7XKU8QdngCFA/cFJwewC69m4h/Jz21Y hQKKhFz2+B9ex3bWzNaGP+92VM8= X-Google-Smtp-Source: ABdhPJzvZt9bG2vKTkiCwRiHO+5g52EKhUdkbrWU16pvBaE7bf3U8L3vVVJYqo+Frr8QDDOOzvSx4qE= Sender: "pcc via sendgmr" X-Received: from pcc-desktop.svl.corp.google.com ([2620:15c:2ce:0:7220:84ff:fe09:385a]) (user=pcc job=sendgmr) by 2002:a25:d64e:: with SMTP id n75mr38310347ybg.322.1604524712270; Wed, 04 Nov 2020 13:18:32 -0800 (PST) Date: Wed, 4 Nov 2020 13:18:10 -0800 In-Reply-To: Message-Id: <0eb601a5d1906fadd7099149eb605181911cfc04.1604523707.git.pcc@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.29.1.341.ge80a0c044ae-goog Subject: [PATCH v14 7/8] signal: define the field siginfo.si_faultflags From: Peter Collingbourne To: Catalin Marinas , Evgenii Stepanov , Kostya Serebryany , Vincenzo Frascino , Dave Martin , Will Deacon , Oleg Nesterov , "Eric W. Biederman" , "James E.J. Bottomley" Cc: Peter Collingbourne , Linux ARM , Kevin Brodsky , Andrey Konovalov , Richard Henderson , linux-api@vger.kernel.org, Helge Deller , David Spickett Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-api@vger.kernel.org This field will contain flags that may be used by signal handlers to determine whether other fields in the _sigfault portion of siginfo are valid. An example use case is the following patch, which introduces the si_addr_tag_bits{,_mask} fields. A new sigcontext flag, SA_FAULTFLAGS, is introduced in order to allow a signal handler to require the kernel to set the field (but note that the field will be set anyway if the kernel supports the flag, regardless of its value). In combination with the previous patches, this allows a userspace program to determine whether the kernel will set the field. It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-aware program to be called with a provided siginfo data structure by using one of the following syscalls: - ptrace(PTRACE_SETSIGINFO) - pidfd_send_signal - rt_sigqueueinfo - rt_tgsigqueueinfo So we need to prevent the si_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls. The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0. There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior. It is also possible for the kernel to inject a signal specified to use _sigfault by calling force_sig (e.g. there are numerous calls to force_sig(SIGSEGV)). In this case si_code is set to SI_KERNEL and the _kill union member is used, so document that si_code must be < SI_KERNEL. Ideally this field could have just been named si_flags, but that name was already taken by ia64, so a different name was chosen. I considered making ia64's si_flags a generic field and having it appear at the end of _sigfault (in the same place as this patch has si_faultflags) on non-ia64, keeping it in the same place on ia64. ia64's si_flags is a 32-bit field with only one flag bit allocated, so we would have 31 bits to use if we do this. However, it seems simplest to avoid entangling these fields. Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/Ide155ce29366c3eab2a944ae4c51205982e5b8b2 --- v14: - make the padding explicit so we can easily use it later v13: - renamed si_xflags to si_faultflags - use fallthrough macros in kernel/ptrace.c - fixed a style warning pointed out by checkpatch.pl v12: - Change type of si_xflags to u32 to avoid increasing alignment - Add si_xflags to signal_compat.c test cases v11: - update comment to say that si_code must > 0 - change ptrace(PTRACE_SETSIGINFO2) to take a flags argument v10: - make the new field compatible with the various ways that a siginfo can be injected from another process - eliminate some duplication by adding a refactoring patch before this one arch/powerpc/platforms/powernv/vas-fault.c | 1 + arch/x86/kernel/signal_compat.c | 7 +++-- include/linux/compat.h | 2 ++ include/linux/signal_types.h | 2 +- include/uapi/asm-generic/siginfo.h | 7 +++++ include/uapi/asm-generic/signal-defs.h | 4 +++ include/uapi/linux/ptrace.h | 12 ++++++++ kernel/ptrace.c | 33 ++++++++++++++++++---- kernel/signal.c | 3 ++ 9 files changed, 62 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/powernv/vas-fault.c b/arch/powerpc/platforms/powernv/vas-fault.c index 3d21fce254b7..877e7d5fb4a2 100644 --- a/arch/powerpc/platforms/powernv/vas-fault.c +++ b/arch/powerpc/platforms/powernv/vas-fault.c @@ -154,6 +154,7 @@ static void update_csb(struct vas_window *window, info.si_errno = EFAULT; info.si_code = SEGV_MAPERR; info.si_addr = csb_addr; + info.si_faultflags = 0; /* * process will be polling on csb.flags after request is sent to diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index ddfd919be46c..222ff6178571 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -121,8 +121,8 @@ static inline void signal_compat_build_tests(void) #endif CHECK_CSI_OFFSET(_sigfault); - CHECK_CSI_SIZE (_sigfault, 4*sizeof(int)); - CHECK_SI_SIZE (_sigfault, 8*sizeof(int)); + CHECK_CSI_SIZE (_sigfault, 8*sizeof(int)); + CHECK_SI_SIZE (_sigfault, 16*sizeof(int)); BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10); BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C); @@ -138,6 +138,9 @@ static inline void signal_compat_build_tests(void) BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x20); BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pkey) != 0x14); + BUILD_BUG_ON(offsetof(siginfo_t, si_faultflags) != 0x48); + BUILD_BUG_ON(offsetof(compat_siginfo_t, si_faultflags) != 0x28); + CHECK_CSI_OFFSET(_sigpoll); CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int)); CHECK_SI_SIZE (_sigpoll, 4*sizeof(int)); diff --git a/include/linux/compat.h b/include/linux/compat.h index 14d514233e1d..84d3b72be701 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -236,7 +236,9 @@ typedef struct compat_siginfo { char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD]; u32 _pkey; } _addr_pkey; + compat_uptr_t _pad[6]; }; + u32 _faultflags; } _sigfault; /* SIGPOLL */ diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h index a7887ad84d36..7501209eae33 100644 --- a/include/linux/signal_types.h +++ b/include/linux/signal_types.h @@ -78,6 +78,6 @@ struct ksignal { #define UAPI_SA_FLAGS \ (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) + SA_NODEFER | SA_RESETHAND | SA_FAULTFLAGS | __ARCH_UAPI_SA_FLAGS) #endif /* _LINUX_SIGNAL_TYPES_H */ diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index 7aacf9389010..10a55aed9ede 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -91,7 +91,12 @@ union __sifields { char _dummy_pkey[__ADDR_BND_PKEY_PAD]; __u32 _pkey; } _addr_pkey; + void *_pad[6]; }; + __u32 _faultflags; +#ifdef __LP64__ + __u32 _pad2; /* to be used if we add another 32-bit field */ +#endif } _sigfault; /* SIGPOLL */ @@ -152,6 +157,8 @@ typedef struct siginfo { #define si_trapno _sifields._sigfault._trapno #endif #define si_addr_lsb _sifields._sigfault._addr_lsb +/* si_faultflags is only valid if 0 < si_code < SI_KERNEL */ +#define si_faultflags _sifields._sigfault._faultflags #define si_lower _sifields._sigfault._addr_bnd._lower #define si_upper _sifields._sigfault._addr_bnd._upper #define si_pkey _sifields._sigfault._addr_pkey._pkey diff --git a/include/uapi/asm-generic/signal-defs.h b/include/uapi/asm-generic/signal-defs.h index 0126ebda4d31..e27bf959d4c4 100644 --- a/include/uapi/asm-generic/signal-defs.h +++ b/include/uapi/asm-generic/signal-defs.h @@ -20,6 +20,9 @@ * so this bit allows flag bit support to be detected from userspace while * allowing an old kernel to be distinguished from a kernel that supports every * flag bit. + * SA_FAULTFLAGS indicates that the signal handler requires the siginfo.si_faultflags + * field to be valid. Note that if the kernel supports SA_FAULTFLAGS, the field will + * be valid regardless of the value of this flag. * * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively. @@ -49,6 +52,7 @@ #define SA_RESETHAND 0x80000000 #endif #define SA_UNSUPPORTED 0x00000400 +#define SA_FAULTFLAGS 0x00000800 #define SA_NOMASK SA_NODEFER #define SA_ONESHOT SA_RESETHAND diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h index a71b6e3b03eb..722a2c8a4d3d 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h @@ -101,6 +101,18 @@ struct ptrace_syscall_info { }; }; +#define PTRACE_SETSIGINFO2 0x420f +/* + * These flags are passed as the addr argument to ptrace. + */ + +/* + * Asserts that the caller is aware of the field siginfo.si_faultflags. Prevents + * the kernel from automatically setting the field to 0 when the signal uses + * a sigfault layout. + */ +#define PTRACE_SIGINFO_FAULTFLAGS 0x1 + /* * These values are stored in task->ptrace_message * by tracehook_report_syscall_* to describe the current syscall-stop. diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 43d6179508d6..ab0618b4602c 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -687,18 +687,31 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info) return error; } -static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info) +static int ptrace_setsiginfo(struct task_struct *child, unsigned long flags, + kernel_siginfo_t *info) { - unsigned long flags; + unsigned long lock_flags; int error = -ESRCH; - if (lock_task_sighand(child, &flags)) { + if (flags & ~PTRACE_SIGINFO_FAULTFLAGS) + return -EINVAL; + + /* + * If the caller is unaware of si_faultflags and we're using a layout that + * requires it, set it to 0 which means "no fields are available". + */ + if (!(flags & PTRACE_SIGINFO_FAULTFLAGS) && + siginfo_layout_is_fault( + siginfo_layout(info->si_signo, info->si_code))) + info->si_faultflags = 0; + + if (lock_task_sighand(child, &lock_flags)) { error = -EINVAL; if (likely(child->last_siginfo != NULL)) { copy_siginfo(child->last_siginfo, info); error = 0; } - unlock_task_sighand(child, &flags); + unlock_task_sighand(child, &lock_flags); } return error; } @@ -1038,9 +1051,13 @@ int ptrace_request(struct task_struct *child, long request, break; case PTRACE_SETSIGINFO: + addr = 0; + fallthrough; + + case PTRACE_SETSIGINFO2: ret = copy_siginfo_from_user(&siginfo, datavp); if (!ret) - ret = ptrace_setsiginfo(child, &siginfo); + ret = ptrace_setsiginfo(child, addr, &siginfo); break; case PTRACE_GETSIGMASK: { @@ -1347,10 +1364,14 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, break; case PTRACE_SETSIGINFO: + addr = 0; + fallthrough; + + case PTRACE_SETSIGINFO2: ret = copy_siginfo_from_user32( &siginfo, (struct compat_siginfo __user *) datap); if (!ret) - ret = ptrace_setsiginfo(child, &siginfo); + ret = ptrace_setsiginfo(child, addr, &siginfo); break; #ifdef CONFIG_HAVE_ARCH_TRACEHOOK case PTRACE_GETREGSET: diff --git a/kernel/signal.c b/kernel/signal.c index d18930aafbf4..1fd1f0d12174 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1657,6 +1657,7 @@ static void set_sigfault_common_fields(struct kernel_siginfo *info, int sig, info->si_errno = 0; info->si_code = code; info->si_addr = addr; + info->si_faultflags = 0; } int force_sig_fault_to_task(int sig, int code, void __user *addr @@ -3270,6 +3271,7 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, #ifdef __ARCH_SI_TRAPNO to->si_trapno = from->si_trapno; #endif + to->si_faultflags = from->si_faultflags; } switch (layout) { @@ -3345,6 +3347,7 @@ static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, #ifdef __ARCH_SI_TRAPNO to->si_trapno = from->si_trapno; #endif + to->si_faultflags = from->si_faultflags; } switch (layout) { -- 2.29.1.341.ge80a0c044ae-goog From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 105C3C00A89 for ; Thu, 5 Nov 2020 04:40:41 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 71F132083B for ; Thu, 5 Nov 2020 04:40:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="qQV3TyYn"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="sU+ESFOB"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="AbC8/yKS" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 71F132083B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:To:From:Subject:References:Mime-Version:Message-Id: In-Reply-To:Date:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=hn/a61OJPgosaizFCdj/BAmd4524drlFII8wqCr8TWs=; b=qQV3TyYn+nmp2SMpw11r0gD4V ZtTUWRdwX9FQBUFDKs5INrUKmZ+L0INOPq6nCF5SoB3/DdOHiZ3VroRZm+nxr0B0n0dPMyQzaLUx2 IOiu5tNVQ5PrqrrTMSwu2CXjBHUyuQagVQ0PfNlGoeOFvmwbo8/2P19ch80YGWuLRr/Nb4xtUIscV WIUt024YkSAquiTbLt0QmmFmzZ2vjoxAWeg9KhG7maeufV+WgfleS1wLEoUySmQQLkBeuEFyUpL09 ZJ+taWdyqvdVpmgSy4LNVDqWfahTJD7EmWtwRg6enokgo7Mh8iOQYReGlwPbfUvfZEY2ZkquKUYSB AYvS7wOiQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kaX33-0004XS-9I; Thu, 05 Nov 2020 04:38:57 +0000 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kaW7t-00016k-Ar for linux-arm-kernel@merlin.infradead.org; Thu, 05 Nov 2020 03:39:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:Cc:To:From:Subject: References:Mime-Version:Message-Id:In-Reply-To:Date:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=wLKH34A8RJSu6n0zXlFAJjjAxtGr+rwms4LzWjAiJ8A=; b=sU+ESFOBYEigO+cZP6YpWFiMWm dmfS+au3YZky1zn05KuWDgtm8ULr5vQ3C3zwKdVeY3u6NVJflTAKFX6A2S7O1Odjs99rTpG5pspni /AGe9oNKq/Dj2jRkyPlviypb/XfPhRgdp3Y8m6QTPdOszoHUJY42tuwBE+EAV9pONrwf+YIQ5rdHf jXY0cj6LVI8ALq8ltieTG4VCoNOYxtVWu0/vqVUPq5jZiZXDI6YlE/jZbl0r8yT8SN58TuBOwDpW4 F/wWmPWXV8nHEZ8V0Zl2RbWPR9X1Bo00pylVs13ZL4mD0LkeboH4A4TJARuCBV+XeInzqmsKBlKXc 86sRxJRQ==; Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]) by casper.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kaQBq-0000pu-0l for linux-arm-kernel@lists.infradead.org; Wed, 04 Nov 2020 21:19:41 +0000 Received: by mail-yb1-xb49.google.com with SMTP id w4so86130ybq.21 for ; Wed, 04 Nov 2020 13:19:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=wLKH34A8RJSu6n0zXlFAJjjAxtGr+rwms4LzWjAiJ8A=; b=AbC8/yKS7Exu2XftLXv44RO1/h8baCloytw7BNg4acM65ljDUKvxxG2ut9J9xvaUFl DPeXHZVkOXkjFLT+bIqiOW7nlkxaPuYoZ9/ZZRGaG5DjPiBjrrJFE28BhMIzGCTz6y4c +RTHg13PX9ADlowTkx8i03yHdxyzfKrTZw+Fe8ir0Yf6OwSzVJP1OBWQeIyGpZeT8xTb 7Qiyye+8NHfHYLLS1Ltylw2io8rILgmdUJiQvsGTo/NM1IN7zmUBaaHB+a88yAJ6YCgt AFaWeLHniHCMzG5QQ3rP70nZy1sUSW3/70EEQG9ZUH+wc6KD1Pna7QGkjI/m/B9gqZ0X 4Hsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=wLKH34A8RJSu6n0zXlFAJjjAxtGr+rwms4LzWjAiJ8A=; b=KraonbArOopPYnrhGXYjWdTr/Pz19P9D355eGXVvNpDveWU6FJXw2I7Mpe8PshXEcw NzmouQ+WQKa02mQKZB0VT0xoOstl2LJey1Eu8oi1ZKd9u5av1YcYZOQ16DRWwQZ1BNJN TSIiu2hTs11X87O5a/+XJnOmxrFi/B7rdMRPOaBiEHteYIjhqP2Hyal7t15sABNlJFsL 4LGzVjbWmVH7FyNQ8p3MRdtsp4aDGPYAdOZ4dmKYwx6u43BP7RJ0DZXIEl9OvlLj+Mhb fIGHmtKmm+T06GEkPbxkYS0VJljZvMzBV3k5MzogBEZ0PLkVHltjCEu4PZEo/Y9RVoH7 Izfw== X-Gm-Message-State: AOAM531C8zqXRTGKVJXriUyKaPQhU1mkpqwd9jMoWwHgK6LkYmllgA4T 97R9j3p3pZuNTl002u84f/gtlIc= X-Google-Smtp-Source: ABdhPJzvZt9bG2vKTkiCwRiHO+5g52EKhUdkbrWU16pvBaE7bf3U8L3vVVJYqo+Frr8QDDOOzvSx4qE= X-Received: from pcc-desktop.svl.corp.google.com ([2620:15c:2ce:0:7220:84ff:fe09:385a]) (user=pcc job=sendgmr) by 2002:a25:d64e:: with SMTP id n75mr38310347ybg.322.1604524712270; Wed, 04 Nov 2020 13:18:32 -0800 (PST) Date: Wed, 4 Nov 2020 13:18:10 -0800 In-Reply-To: Message-Id: <0eb601a5d1906fadd7099149eb605181911cfc04.1604523707.git.pcc@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.29.1.341.ge80a0c044ae-goog Subject: [PATCH v14 7/8] signal: define the field siginfo.si_faultflags From: Peter Collingbourne To: Catalin Marinas , Evgenii Stepanov , Kostya Serebryany , Vincenzo Frascino , Dave Martin , Will Deacon , Oleg Nesterov , "Eric W. Biederman" , "James E.J. Bottomley" X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201104_211934_447421_C51A1D68 X-CRM114-Status: GOOD ( 43.73 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andrey Konovalov , Helge Deller , Kevin Brodsky , linux-api@vger.kernel.org, David Spickett , Peter Collingbourne , Linux ARM , Richard Henderson Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This field will contain flags that may be used by signal handlers to determine whether other fields in the _sigfault portion of siginfo are valid. An example use case is the following patch, which introduces the si_addr_tag_bits{,_mask} fields. A new sigcontext flag, SA_FAULTFLAGS, is introduced in order to allow a signal handler to require the kernel to set the field (but note that the field will be set anyway if the kernel supports the flag, regardless of its value). In combination with the previous patches, this allows a userspace program to determine whether the kernel will set the field. It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-aware program to be called with a provided siginfo data structure by using one of the following syscalls: - ptrace(PTRACE_SETSIGINFO) - pidfd_send_signal - rt_sigqueueinfo - rt_tgsigqueueinfo So we need to prevent the si_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls. The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0. There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior. It is also possible for the kernel to inject a signal specified to use _sigfault by calling force_sig (e.g. there are numerous calls to force_sig(SIGSEGV)). In this case si_code is set to SI_KERNEL and the _kill union member is used, so document that si_code must be < SI_KERNEL. Ideally this field could have just been named si_flags, but that name was already taken by ia64, so a different name was chosen. I considered making ia64's si_flags a generic field and having it appear at the end of _sigfault (in the same place as this patch has si_faultflags) on non-ia64, keeping it in the same place on ia64. ia64's si_flags is a 32-bit field with only one flag bit allocated, so we would have 31 bits to use if we do this. However, it seems simplest to avoid entangling these fields. Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/Ide155ce29366c3eab2a944ae4c51205982e5b8b2 --- v14: - make the padding explicit so we can easily use it later v13: - renamed si_xflags to si_faultflags - use fallthrough macros in kernel/ptrace.c - fixed a style warning pointed out by checkpatch.pl v12: - Change type of si_xflags to u32 to avoid increasing alignment - Add si_xflags to signal_compat.c test cases v11: - update comment to say that si_code must > 0 - change ptrace(PTRACE_SETSIGINFO2) to take a flags argument v10: - make the new field compatible with the various ways that a siginfo can be injected from another process - eliminate some duplication by adding a refactoring patch before this one arch/powerpc/platforms/powernv/vas-fault.c | 1 + arch/x86/kernel/signal_compat.c | 7 +++-- include/linux/compat.h | 2 ++ include/linux/signal_types.h | 2 +- include/uapi/asm-generic/siginfo.h | 7 +++++ include/uapi/asm-generic/signal-defs.h | 4 +++ include/uapi/linux/ptrace.h | 12 ++++++++ kernel/ptrace.c | 33 ++++++++++++++++++---- kernel/signal.c | 3 ++ 9 files changed, 62 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/powernv/vas-fault.c b/arch/powerpc/platforms/powernv/vas-fault.c index 3d21fce254b7..877e7d5fb4a2 100644 --- a/arch/powerpc/platforms/powernv/vas-fault.c +++ b/arch/powerpc/platforms/powernv/vas-fault.c @@ -154,6 +154,7 @@ static void update_csb(struct vas_window *window, info.si_errno = EFAULT; info.si_code = SEGV_MAPERR; info.si_addr = csb_addr; + info.si_faultflags = 0; /* * process will be polling on csb.flags after request is sent to diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index ddfd919be46c..222ff6178571 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -121,8 +121,8 @@ static inline void signal_compat_build_tests(void) #endif CHECK_CSI_OFFSET(_sigfault); - CHECK_CSI_SIZE (_sigfault, 4*sizeof(int)); - CHECK_SI_SIZE (_sigfault, 8*sizeof(int)); + CHECK_CSI_SIZE (_sigfault, 8*sizeof(int)); + CHECK_SI_SIZE (_sigfault, 16*sizeof(int)); BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10); BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C); @@ -138,6 +138,9 @@ static inline void signal_compat_build_tests(void) BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x20); BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pkey) != 0x14); + BUILD_BUG_ON(offsetof(siginfo_t, si_faultflags) != 0x48); + BUILD_BUG_ON(offsetof(compat_siginfo_t, si_faultflags) != 0x28); + CHECK_CSI_OFFSET(_sigpoll); CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int)); CHECK_SI_SIZE (_sigpoll, 4*sizeof(int)); diff --git a/include/linux/compat.h b/include/linux/compat.h index 14d514233e1d..84d3b72be701 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -236,7 +236,9 @@ typedef struct compat_siginfo { char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD]; u32 _pkey; } _addr_pkey; + compat_uptr_t _pad[6]; }; + u32 _faultflags; } _sigfault; /* SIGPOLL */ diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h index a7887ad84d36..7501209eae33 100644 --- a/include/linux/signal_types.h +++ b/include/linux/signal_types.h @@ -78,6 +78,6 @@ struct ksignal { #define UAPI_SA_FLAGS \ (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) + SA_NODEFER | SA_RESETHAND | SA_FAULTFLAGS | __ARCH_UAPI_SA_FLAGS) #endif /* _LINUX_SIGNAL_TYPES_H */ diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index 7aacf9389010..10a55aed9ede 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -91,7 +91,12 @@ union __sifields { char _dummy_pkey[__ADDR_BND_PKEY_PAD]; __u32 _pkey; } _addr_pkey; + void *_pad[6]; }; + __u32 _faultflags; +#ifdef __LP64__ + __u32 _pad2; /* to be used if we add another 32-bit field */ +#endif } _sigfault; /* SIGPOLL */ @@ -152,6 +157,8 @@ typedef struct siginfo { #define si_trapno _sifields._sigfault._trapno #endif #define si_addr_lsb _sifields._sigfault._addr_lsb +/* si_faultflags is only valid if 0 < si_code < SI_KERNEL */ +#define si_faultflags _sifields._sigfault._faultflags #define si_lower _sifields._sigfault._addr_bnd._lower #define si_upper _sifields._sigfault._addr_bnd._upper #define si_pkey _sifields._sigfault._addr_pkey._pkey diff --git a/include/uapi/asm-generic/signal-defs.h b/include/uapi/asm-generic/signal-defs.h index 0126ebda4d31..e27bf959d4c4 100644 --- a/include/uapi/asm-generic/signal-defs.h +++ b/include/uapi/asm-generic/signal-defs.h @@ -20,6 +20,9 @@ * so this bit allows flag bit support to be detected from userspace while * allowing an old kernel to be distinguished from a kernel that supports every * flag bit. + * SA_FAULTFLAGS indicates that the signal handler requires the siginfo.si_faultflags + * field to be valid. Note that if the kernel supports SA_FAULTFLAGS, the field will + * be valid regardless of the value of this flag. * * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively. @@ -49,6 +52,7 @@ #define SA_RESETHAND 0x80000000 #endif #define SA_UNSUPPORTED 0x00000400 +#define SA_FAULTFLAGS 0x00000800 #define SA_NOMASK SA_NODEFER #define SA_ONESHOT SA_RESETHAND diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h index a71b6e3b03eb..722a2c8a4d3d 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h @@ -101,6 +101,18 @@ struct ptrace_syscall_info { }; }; +#define PTRACE_SETSIGINFO2 0x420f +/* + * These flags are passed as the addr argument to ptrace. + */ + +/* + * Asserts that the caller is aware of the field siginfo.si_faultflags. Prevents + * the kernel from automatically setting the field to 0 when the signal uses + * a sigfault layout. + */ +#define PTRACE_SIGINFO_FAULTFLAGS 0x1 + /* * These values are stored in task->ptrace_message * by tracehook_report_syscall_* to describe the current syscall-stop. diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 43d6179508d6..ab0618b4602c 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -687,18 +687,31 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info) return error; } -static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info) +static int ptrace_setsiginfo(struct task_struct *child, unsigned long flags, + kernel_siginfo_t *info) { - unsigned long flags; + unsigned long lock_flags; int error = -ESRCH; - if (lock_task_sighand(child, &flags)) { + if (flags & ~PTRACE_SIGINFO_FAULTFLAGS) + return -EINVAL; + + /* + * If the caller is unaware of si_faultflags and we're using a layout that + * requires it, set it to 0 which means "no fields are available". + */ + if (!(flags & PTRACE_SIGINFO_FAULTFLAGS) && + siginfo_layout_is_fault( + siginfo_layout(info->si_signo, info->si_code))) + info->si_faultflags = 0; + + if (lock_task_sighand(child, &lock_flags)) { error = -EINVAL; if (likely(child->last_siginfo != NULL)) { copy_siginfo(child->last_siginfo, info); error = 0; } - unlock_task_sighand(child, &flags); + unlock_task_sighand(child, &lock_flags); } return error; } @@ -1038,9 +1051,13 @@ int ptrace_request(struct task_struct *child, long request, break; case PTRACE_SETSIGINFO: + addr = 0; + fallthrough; + + case PTRACE_SETSIGINFO2: ret = copy_siginfo_from_user(&siginfo, datavp); if (!ret) - ret = ptrace_setsiginfo(child, &siginfo); + ret = ptrace_setsiginfo(child, addr, &siginfo); break; case PTRACE_GETSIGMASK: { @@ -1347,10 +1364,14 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, break; case PTRACE_SETSIGINFO: + addr = 0; + fallthrough; + + case PTRACE_SETSIGINFO2: ret = copy_siginfo_from_user32( &siginfo, (struct compat_siginfo __user *) datap); if (!ret) - ret = ptrace_setsiginfo(child, &siginfo); + ret = ptrace_setsiginfo(child, addr, &siginfo); break; #ifdef CONFIG_HAVE_ARCH_TRACEHOOK case PTRACE_GETREGSET: diff --git a/kernel/signal.c b/kernel/signal.c index d18930aafbf4..1fd1f0d12174 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1657,6 +1657,7 @@ static void set_sigfault_common_fields(struct kernel_siginfo *info, int sig, info->si_errno = 0; info->si_code = code; info->si_addr = addr; + info->si_faultflags = 0; } int force_sig_fault_to_task(int sig, int code, void __user *addr @@ -3270,6 +3271,7 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, #ifdef __ARCH_SI_TRAPNO to->si_trapno = from->si_trapno; #endif + to->si_faultflags = from->si_faultflags; } switch (layout) { @@ -3345,6 +3347,7 @@ static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, #ifdef __ARCH_SI_TRAPNO to->si_trapno = from->si_trapno; #endif + to->si_faultflags = from->si_faultflags; } switch (layout) { -- 2.29.1.341.ge80a0c044ae-goog _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel