From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755451AbcAVWjw (ORCPT ); Fri, 22 Jan 2016 17:39:52 -0500 Received: from mail-pa0-f45.google.com ([209.85.220.45]:34224 "EHLO mail-pa0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754665AbcAVWjV (ORCPT ); Fri, 22 Jan 2016 17:39:21 -0500 From: Kees Cook To: Andrew Morton Cc: Kees Cook , Al Viro , Richard Weinberger , "Eric W. Biederman" , Andy Lutomirski , =?UTF-8?q?Robert=20=C5=9Awi=C4=99cki?= , Dmitry Vyukov , David Howells , Miklos Szeredi , Kostya Serebryany , Alexander Potapenko , Eric Dumazet , Sasha Levin , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Subject: [PATCH 1/2] sysctl: expand use of proc_dointvec_minmax_sysadmin Date: Fri, 22 Jan 2016 14:39:04 -0800 Message-Id: <1453502345-30416-2-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.6.3 In-Reply-To: <1453502345-30416-1-git-send-email-keescook@chromium.org> References: <1453502345-30416-1-git-send-email-keescook@chromium.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Several sysctls expect a state where the highest value (in extra2) is locked once set for that boot. Yama does this, and kptr_restrict should be doing it. This extracts Yama's logic and adds it to the existing proc_dointvec_minmax_sysadmin, taking care to avoid the simple boolean states (which do not get locked). Since Yama wants to be checking a different capability, we build wrappers for both cases (CAP_SYS_ADMIN and CAP_SYS_PTRACE). Signed-off-by: Kees Cook --- Documentation/sysctl/kernel.txt | 4 +++- include/linux/sysctl.h | 18 ++++++++++++++++++ kernel/sysctl.c | 34 +++++++++++++++++++++------------- security/yama/yama_lsm.c | 18 +----------------- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 73c6b1ef0e84..bbfc5e339a3d 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -385,7 +385,9 @@ to protect against uses of %pK in dmesg(8) if leaking kernel pointer values to unprivileged users is a concern. When kptr_restrict is set to (2), kernel pointers printed using -%pK will be replaced with 0's regardless of privileges. +%pK will be replaced with 0's regardless of privileges, and the value +will be locked at "2", so that the root user cannot remove this +restriction. ============================================================== diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index fa7bc29925c9..f8f0b991fe3e 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -55,6 +56,23 @@ extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int, void __user *, size_t *, loff_t *); extern int proc_do_large_bitmap(struct ctl_table *, int, void __user *, size_t *, loff_t *); +extern int proc_dointvec_minmax_cap(int cap, struct ctl_table *table, + int write, void __user *buffer, + size_t *lenp, loff_t *ppos); +static inline int proc_dointvec_minmax_cap_sysadmin(struct ctl_table *table, + int write, void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dointvec_minmax_cap(CAP_SYS_ADMIN, table, write, buffer, + lenp, ppos); +} +static inline int proc_dointvec_minmax_cap_ptrace(struct ctl_table *table, + int write, void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dointvec_minmax_cap(CAP_SYS_PTRACE, table, write, buffer, + lenp, ppos); +} /* * Register a set of sysctl names by calling register_sysctl_table diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c810f8afdb7f..fc8899dd636d 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -181,11 +181,6 @@ static int proc_taint(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); #endif -#ifdef CONFIG_PRINTK -static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -#endif - static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); #ifdef CONFIG_COREDUMP @@ -803,7 +798,7 @@ static struct ctl_table kern_table[] = { .data = &dmesg_restrict, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_minmax_sysadmin, + .proc_handler = proc_dointvec_minmax_cap_sysadmin, .extra1 = &zero, .extra2 = &one, }, @@ -812,7 +807,7 @@ static struct ctl_table kern_table[] = { .data = &kptr_restrict, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_minmax_sysadmin, + .proc_handler = proc_dointvec_minmax_cap_sysadmin, .extra1 = &zero, .extra2 = &two, }, @@ -2217,16 +2212,29 @@ static int proc_taint(struct ctl_table *table, int write, return err; } -#ifdef CONFIG_PRINTK -static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) +int proc_dointvec_minmax_cap(int cap, struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) { - if (write && !capable(CAP_SYS_ADMIN)) + struct ctl_table table_copy; + int value; + + /* Require init capabilities to make changes. */ + if (write && !capable(cap)) return -EPERM; - return proc_dointvec_minmax(table, write, buffer, lenp, ppos); + /* + * To deal with const sysctl tables, we make a copy to perform + * the locking. When data is >1 and ==extra2, lock extra1 to + * extra2 to stop the value from being changed any further at + * runtime. + */ + table_copy = *table; + value = *(int *)table_copy.data; + if (value > 1 && value == *(int *)table_copy.extra2) + table_copy.extra1 = table_copy.extra2; + + return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos); } -#endif struct do_proc_dointvec_minmax_conv_param { int *min; diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index d3c19c970a06..3215afd08fbd 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -354,22 +354,6 @@ static struct security_hook_list yama_hooks[] = { }; #ifdef CONFIG_SYSCTL -static int yama_dointvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table table_copy; - - if (write && !capable(CAP_SYS_PTRACE)) - return -EPERM; - - /* Lock the max value if it ever gets set. */ - table_copy = *table; - if (*(int *)table_copy.data == *(int *)table_copy.extra2) - table_copy.extra1 = table_copy.extra2; - - return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos); -} - static int zero; static int max_scope = YAMA_SCOPE_NO_ATTACH; @@ -385,7 +369,7 @@ static struct ctl_table yama_sysctl_table[] = { .data = &ptrace_scope, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = yama_dointvec_minmax, + .proc_handler = proc_dointvec_minmax_cap_ptrace, .extra1 = &zero, .extra2 = &max_scope, }, -- 2.6.3