|
Message-ID: <5254BDD0.7040001@gmail.com> Date: Wed, 09 Oct 2013 13:22:08 +1100 From: Ryan Mallon <rmallon@...il.com> To: Joe Perches <joe@...ches.com> CC: Andrew Morton <akpm@...ux-foundation.org>, eldad@...refinery.com, Jiri Kosina <jkosina@...e.cz>, jgunthorpe@...idianresearch.com, Dan Rosenberg <dan.j.rosenberg@...il.com>, Kees Cook <keescook@...omium.org>, Alexander Viro <viro@...iv.linux.org.uk>, "Eric W. Biederman" <ebiederm@...ssion.com>, George Spelvin <linux@...izon.com>, "kernel-hardening@...ts.openwall.com" <kernel-hardening@...ts.openwall.com>, "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org> Subject: Re: [PATCH v2] vsprintf: Check real user/group id for %pK On 09/10/13 13:00, Joe Perches wrote: > On Wed, 2013-10-09 at 12:55 +1100, Ryan Mallon wrote: >> On 09/10/13 12:30, Joe Perches wrote: >>> On Tue, 2013-10-08 at 17:49 -0700, Joe Perches wrote: >>>> On Wed, 2013-10-09 at 11:15 +1100, Ryan Mallon wrote: >>>>> Some setuid binaries will allow reading of files which have read >>>>> permission by the real user id. This is problematic with files which >>>>> use %pK because the file access permission is checked at open() time, >>>>> but the kptr_restrict setting is checked at read() time. If a setuid >>>>> binary opens a %pK file as an unprivileged user, and then elevates >>>>> permissions before reading the file, then kernel pointer values may be >>>>> leaked. >>>> I think it should explicitly test 0. >>> Also, Documentation/sysctl/kernel.txt should be updated too. >>> >>> Here's a suggested patch: >>> >>> --- >>> Documentation/sysctl/kernel.txt | 14 ++++++++------ >>> lib/vsprintf.c | 38 ++++++++++++++++++++++++++------------ >>> 2 files changed, 34 insertions(+), 18 deletions(-) >>> >>> diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt >>> index 9d4c1d1..eac53d5 100644 >>> --- a/Documentation/sysctl/kernel.txt >>> +++ b/Documentation/sysctl/kernel.txt >>> @@ -290,13 +290,15 @@ Default value is "/sbin/hotplug". >>> kptr_restrict: >>> >>> This toggle indicates whether restrictions are placed on >>> -exposing kernel addresses via /proc and other interfaces. When >>> -kptr_restrict is set to (0), there are no restrictions. When >>> -kptr_restrict is set to (1), the default, kernel pointers >>> +exposing kernel addresses via /proc and other interfaces. >>> + >>> +When kptr_restrict is set to (0), there are no restrictions. >>> +When kptr_restrict is set to (1), the default, kernel pointers >>> printed using the %pK format specifier will be replaced with 0's >>> -unless the user has CAP_SYSLOG. When kptr_restrict is set to >>> -(2), kernel pointers printed using %pK will be replaced with 0's >>> -regardless of privileges. >>> +unless the user has CAP_SYSLOG and effective user and group ids >>> +are equal to the real ids. >>> +When kptr_restrict is set to (2), kernel pointers printed using >>> +%pK will be replaced with 0's regardless of privileges. >> I'll add this, thanks. >> >> I'm less fussed about the suggestions for the logic. The current test is >> small and concise. > The logic ends up the same to the compiler, but it's > human readers that want simple and clear. > >> The original also does the in_irq tests regardless of >> the kptr_restrict setting since they are mostly intended to catch >> internal kernel bugs. > Not so. > > http://marc.info/?l=linux-security-module&m=129303800912245&w=4 > https://lkml.org/lkml/2012/7/13/428 > Ah, I misread it. It does however check when kptr_restrict != 0, not just when kptr_restrict is 1. I've left the in_irq test as-is, but used a switch as suggested. I don't really care either way, I think the original check is quite readable. Anyway, updated patch below: ~Ryan --- diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 9d4c1d1..eac53d5 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -290,13 +290,15 @@ Default value is "/sbin/hotplug". kptr_restrict: This toggle indicates whether restrictions are placed on -exposing kernel addresses via /proc and other interfaces. When -kptr_restrict is set to (0), there are no restrictions. When -kptr_restrict is set to (1), the default, kernel pointers +exposing kernel addresses via /proc and other interfaces. + +When kptr_restrict is set to (0), there are no restrictions. +When kptr_restrict is set to (1), the default, kernel pointers printed using the %pK format specifier will be replaced with 0's -unless the user has CAP_SYSLOG. When kptr_restrict is set to -(2), kernel pointers printed using %pK will be replaced with 0's -regardless of privileges. +unless the user has CAP_SYSLOG and effective user and group ids +are equal to the real ids. +When kptr_restrict is set to (2), kernel pointers printed using +%pK will be replaced with 0's regardless of privileges. ============================================================== diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 26559bd..6dd8c5d 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -27,6 +27,7 @@ #include <linux/uaccess.h> #include <linux/ioport.h> #include <linux/dcache.h> +#include <linux/cred.h> #include <net/addrconf.h> #include <asm/page.h> /* for PAGE_SIZE */ @@ -1312,11 +1313,36 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, spec.field_width = default_width; return string(buf, end, "pK-error", spec); } - if (!((kptr_restrict == 0) || - (kptr_restrict == 1 && - has_capability_noaudit(current, CAP_SYSLOG)))) + + switch (kptr_restrict) { + case 0: + /* Always print %pK values */ + break; + case 1: { + /* + * Only print the real pointer value if the current + * proccess has CAP_SYSLOG and is running with the + * same credentials it started with. This is because + * access to files is checked at open() time, but %pK + * checks permission at read() time. We don't want to + * leak pointer values if a binary opens a file using + * %pK and then elevates privileges before reading it. + */ + const struct cred *cred = current_cred(); + + if (!has_capability_noaudit(current, CAP_SYSLOG) || + !uid_eq(cred->euid, cred->uid) || + !gid_eq(cred->egid, cred->gid)) + ptr = NULL; + break; + } + default: + /* Always print 0's for %pK */ ptr = NULL; + break; + } break; + case 'N': switch (fmt[1]) { case 'F':
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.