From patchwork Mon Feb 11 17:59:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 158022 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp2891919jaa; Mon, 11 Feb 2019 09:59:48 -0800 (PST) X-Google-Smtp-Source: AHgI3IY81q3qsK0m/B/CEf/lVAZkqOUvN9iOzL6WT6gwnBvZgIsvuVyrCf8EbMMfaXrerCMROvyV X-Received: by 2002:a17:902:820f:: with SMTP id x15mr37406074pln.224.1549907987962; Mon, 11 Feb 2019 09:59:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549907987; cv=none; d=google.com; s=arc-20160816; b=hgGcBFPXY/+ynupxUEJbpJVKDvKHzGzr5c/fdMCspzf5fgzZ1Sq0w4Ue3z86Dh+CnZ EEibLdPkNCf0bzE4OEYMSNUe69hDOlM6A9t3GCLi3ydnUhmbTzd2qNwWNkc7MpNHIGRI 1b9mlNoV6A8zaCvLz/GyU9Ma6bc2EcS4TfnGEmyfE8HfXQgvYgTvSzFsGLiCcnKOzFV1 74K6GoMfIAvUjI0p1WX1feW5qmOEKwYYApvABBT2E6n6VWWAA8fCC4TwHj4XHws12Nm/ 8ByNKxypOVUu5tgrDUEXyVby0rfZcof92GOLuBQO3lwvZSoSGBG+arzDkIkm49hP6Ycc 5l6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=hO76sjAZgEHyPjd0c0Vua+q8nWvIE3sQ1uXBd2acD+8=; b=EeOr6WUMxAdPGNZJRxgpgVeZSfYEtpDadpmMY5DNcG+D5EhBQjNB/LllcbGnkFEjr2 PV5N6bE1xkuz84kowFdbc2vI481ih+iaVW8aLqSjcRVv2Ao3gUM4oGicGIeC3tmdYxmi kGzu/E4zeiTFNQo1ERBeEHYL1IChS4F1vMHVzFAiqO02t6kAQSQHB350hp45fSv/FE7j hMjknx/e1GgGBiB+nIBICEX3KsYRXVhu3DQnaczFXakopD+3lX3vqUEdxjyC4qgEXL5n uobrgCG7Tm2W0kxzXUkSxnjxgSt3V2eDZDT5eW16UZU8D/kLsJufNpxeT2JvqkwclE+R 8/Yg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z8si9483200pgv.204.2019.02.11.09.59.47; Mon, 11 Feb 2019 09:59:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731001AbfBKR7q (ORCPT + 31 others); Mon, 11 Feb 2019 12:59:46 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:55048 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726104AbfBKR7n (ORCPT ); Mon, 11 Feb 2019 12:59:43 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 5A29715AD; Mon, 11 Feb 2019 09:59:43 -0800 (PST) Received: from fuggles.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id D4AE83F675; Mon, 11 Feb 2019 09:59:41 -0800 (PST) From: Will Deacon To: linux-kernel@vger.kernel.org Cc: Will Deacon , Kees Cook , Jann Horn , Andrew Morton , Matthew Wilcox , Michal Hocko , Peter Zijlstra Subject: [RFC PATCH 1/4] mm: Check user stack pointer is mapped with MAP_STACK Date: Mon, 11 Feb 2019 17:59:32 +0000 Message-Id: <20190211175935.4602-2-will.deacon@arm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190211175935.4602-1-will.deacon@arm.com> References: <20190211175935.4602-1-will.deacon@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org By marking stack VMAs with VM_USERSTACK, we can perform optional checks on entry to the kernel from system calls and user faults to ensure that the user stack pointer does indeed point to a stack VMA. If the stack pointer is found to point elsewhere, a SIGSEGV can be delivered to the current application. This acts as a best-effort defense against stack-pivoting attacks. Cc: Kees Cook Cc: Jann Horn Cc: Andrew Morton Cc: Matthew Wilcox Cc: Michal Hocko Cc: Peter Zijlstra Signed-off-by: Will Deacon --- include/linux/mm.h | 10 +++++++++- include/linux/mman.h | 3 ++- include/linux/sched.h | 4 ++++ mm/memory.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) -- 2.11.0 diff --git a/include/linux/mm.h b/include/linux/mm.h index 80bb6408fe73..9fa02d47a270 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -233,6 +233,7 @@ extern unsigned int kobjsize(const void *objp); #define VM_ARCH_1 0x01000000 /* Architecture-specific flag */ #define VM_WIPEONFORK 0x02000000 /* Wipe VMA contents in child. */ #define VM_DONTDUMP 0x04000000 /* Do not include in the core dump */ +#define VM_USERSTACK 0x08000000 /* User stack VM */ #ifdef CONFIG_MEM_SOFT_DIRTY # define VM_SOFTDIRTY 0x08000000 /* Not soft dirty clean area */ @@ -310,7 +311,8 @@ extern unsigned int kobjsize(const void *objp); #define VM_STACK VM_GROWSDOWN #endif -#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT) +#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT | \ + VM_USERSTACK) /* * Special vmas that are non-mergable, non-mlock()able. @@ -1480,6 +1482,12 @@ int truncate_inode_page(struct address_space *mapping, struct page *page); int generic_error_remove_page(struct address_space *mapping, struct page *page); int invalidate_inode_page(struct page *page); +#ifdef CONFIG_USER_STACK_POINTER_CHECKS +bool usp_check_syscall(void); +#else +static inline bool usp_check_syscall(void) { return true; } +#endif + #ifdef CONFIG_MMU extern vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, unsigned int flags); diff --git a/include/linux/mman.h b/include/linux/mman.h index 4b08e9c9c538..d4f2d39fca70 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -131,7 +131,8 @@ calc_vm_flag_bits(unsigned long flags) return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ) | - _calc_vm_trans(flags, MAP_SYNC, VM_SYNC ); + _calc_vm_trans(flags, MAP_SYNC, VM_SYNC ) | + _calc_vm_trans(flags, MAP_STACK, VM_USERSTACK ) ; } unsigned long vm_commit_limit(void); diff --git a/include/linux/sched.h b/include/linux/sched.h index bba3afb4e9bf..2e6766301645 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1208,6 +1208,10 @@ struct task_struct { unsigned long prev_lowest_stack; #endif +#ifdef CONFIG_USER_STACK_POINTER_CHECKS + unsigned int usp_checks; +#endif + /* * New fields for task_struct should be added above here, so that * they are included in the randomized portion of task_struct. diff --git a/mm/memory.c b/mm/memory.c index e11ca9dd823f..e0b449f520da 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -3911,6 +3913,46 @@ static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma, return handle_pte_fault(&vmf); } +#ifdef CONFIG_USER_STACK_POINTER_CHECKS +#define USP_CHECK_FAULT (1U << 0) +#define USP_CHECK_SYSCALL (1U << 1) + +static bool __usp_check(void) +{ + struct vm_area_struct *vma; + + vma = find_vma(current->mm, current_user_stack_pointer()); + return vma && (vma->vm_flags & VM_USERSTACK); +} + +static bool usp_check_fault(unsigned int flags) +{ + if (!(flags & FAULT_FLAG_USER)) + return true; + + if (!(current->usp_checks & USP_CHECK_FAULT)) + return true; + + return __usp_check(); +} + +bool usp_check_syscall(void) +{ + bool ret; + struct mm_struct *mm = current->mm; + + if (!(current->usp_checks & USP_CHECK_SYSCALL)) + return true; + + down_read(&mm->mmap_sem); + ret = __usp_check(); + up_read(&mm->mmap_sem); + return ret; +} +#else +static bool usp_check_fault(unsigned int flags) { return true; } +#endif + /* * By the time we get here, we already hold the mm semaphore * @@ -3930,6 +3972,9 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, /* do counter updates before entering really critical section. */ check_sync_rss_stat(current); + if (!usp_check_fault(flags)) + return VM_FAULT_SIGSEGV; + if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE, flags & FAULT_FLAG_INSTRUCTION, flags & FAULT_FLAG_REMOTE))