@@ -1483,8 +1483,13 @@ 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
+long prctl_sp_check(struct task_struct *tsk, unsigned long flags);
bool usp_check_syscall(void);
#else
+static inline long prctl_sp_check(struct task_struct *tsk, unsigned long flags)
+{
+ return -EINVAL;
+}
static inline bool usp_check_syscall(void) { return true; }
#endif
@@ -228,4 +228,9 @@ struct prctl_mm_map {
# define PR_PAC_APDBKEY (1UL << 3)
# define PR_PAC_APGAKEY (1UL << 4)
+/* User stack pointer sanity checking */
+#define PR_SP_CHECK 55
+# define PR_SP_CHECK_PAGE_FAULT (1UL << 0)
+# define PR_SP_CHECK_SYSCALL (1UL << 1)
+
#endif /* _LINUX_PRCTL_H */
@@ -2485,6 +2485,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
return -EINVAL;
error = PAC_RESET_KEYS(me, arg2);
break;
+ case PR_SP_CHECK:
+ if (arg3 || arg4 || arg5)
+ return -EINVAL;
+ error = prctl_sp_check(me, arg2);
+ break;
default:
error = -EINVAL;
break;
@@ -71,6 +71,7 @@
#include <linux/userfaultfd_k.h>
#include <linux/dax.h>
#include <linux/oom.h>
+#include <linux/prctl.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
@@ -3949,6 +3950,27 @@ bool usp_check_syscall(void)
up_read(&mm->mmap_sem);
return ret;
}
+
+long prctl_sp_check(struct task_struct *tsk, unsigned long flags)
+{
+ if (flags & ~(PR_SP_CHECK_PAGE_FAULT | PR_SP_CHECK_SYSCALL))
+ return -EINVAL;
+
+ if (flags & PR_SP_CHECK_PAGE_FAULT)
+ tsk->usp_checks |= USP_CHECK_FAULT;
+ else
+ tsk->usp_checks &= ~USP_CHECK_FAULT;
+
+ if (flags & PR_SP_CHECK_SYSCALL) {
+ if (!IS_ENABLED(CONFIG_ARCH_HAS_USP_CHECK_SYSCALL))
+ return -EINVAL;
+ tsk->usp_checks |= USP_CHECK_SYSCALL;
+ } else {
+ tsk->usp_checks &= ~USP_CHECK_SYSCALL;
+ }
+
+ return 0;
+}
#else
static bool usp_check_fault(unsigned int flags) { return true; }
#endif
Hook up a prctl() option to control the level of user stack pointer checking for the current task. By default, no checking is performed, but checks can be independently controlled for system calls and page faults. The option is inherited across fork() and preserved across exec(). Cc: Kees Cook <keescook@chromium.org> Cc: Jann Horn <jannh@google.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Matthew Wilcox <willy@infradead.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Will Deacon <will.deacon@arm.com> --- include/linux/mm.h | 5 +++++ include/uapi/linux/prctl.h | 5 +++++ kernel/sys.c | 5 +++++ mm/memory.c | 22 ++++++++++++++++++++++ 4 files changed, 37 insertions(+) -- 2.11.0