aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRyan Mallon <rmallon@gmail.com>2013-11-12 18:08:51 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-04 13:56:06 -0500
commit7135a8a100fb1bc8d15f90a31e72faccdb4d7118 (patch)
tree9756ae0c669325b8a75aeef50ecabadbab2a737c /lib
parent922b22ffb72220e659e58fec784e11dec9922ec4 (diff)
vsprintf: check real user/group id for %pK
commit 312b4e226951f707e120b95b118cbc14f3d162b2 upstream. 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. This happens for example with the setuid pppd application on Ubuntu 12.04: $ head -1 /proc/kallsyms 00000000 T startup_32 $ pppd file /proc/kallsyms pppd: In file /proc/kallsyms: unrecognized option 'c1000000' This will only leak the pointer value from the first line, but other setuid binaries may leak more information. Fix this by adding a check that in addition to the current process having CAP_SYSLOG, that effective user and group ids are equal to the real ids. If a setuid binary reads the contents of a file which uses %pK then the pointer values will be printed as NULL if the real user is unprivileged. Update the sysctl documentation to reflect the changes, and also correct the documentation to state the kptr_restrict=0 is the default. This is a only temporary solution to the issue. The correct solution is to do the permission check at open() time on files, and to replace %pK with a function which checks the open() time permission. %pK uses in printk should be removed since no sane permission check can be done, and instead protected by using dmesg_restrict. Signed-off-by: Ryan Mallon <rmallon@gmail.com> Cc: Kees Cook <keescook@chromium.org> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Joe Perches <joe@perches.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/vsprintf.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e149c6416384..620fae4c11f6 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -26,6 +26,7 @@
26#include <linux/math64.h> 26#include <linux/math64.h>
27#include <linux/uaccess.h> 27#include <linux/uaccess.h>
28#include <linux/ioport.h> 28#include <linux/ioport.h>
29#include <linux/cred.h>
29#include <net/addrconf.h> 30#include <net/addrconf.h>
30 31
31#include <asm/page.h> /* for PAGE_SIZE */ 32#include <asm/page.h> /* for PAGE_SIZE */
@@ -1118,11 +1119,37 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
1118 spec.field_width = default_width; 1119 spec.field_width = default_width;
1119 return string(buf, end, "pK-error", spec); 1120 return string(buf, end, "pK-error", spec);
1120 } 1121 }
1121 if (!((kptr_restrict == 0) || 1122
1122 (kptr_restrict == 1 && 1123 switch (kptr_restrict) {
1123 has_capability_noaudit(current, CAP_SYSLOG)))) 1124 case 0:
1125 /* Always print %pK values */
1126 break;
1127 case 1: {
1128 /*
1129 * Only print the real pointer value if the current
1130 * process has CAP_SYSLOG and is running with the
1131 * same credentials it started with. This is because
1132 * access to files is checked at open() time, but %pK
1133 * checks permission at read() time. We don't want to
1134 * leak pointer values if a binary opens a file using
1135 * %pK and then elevates privileges before reading it.
1136 */
1137 const struct cred *cred = current_cred();
1138
1139 if (!has_capability_noaudit(current, CAP_SYSLOG) ||
1140 !uid_eq(cred->euid, cred->uid) ||
1141 !gid_eq(cred->egid, cred->gid))
1142 ptr = NULL;
1143 break;
1144 }
1145 case 2:
1146 default:
1147 /* Always print 0's for %pK */
1124 ptr = NULL; 1148 ptr = NULL;
1149 break;
1150 }
1125 break; 1151 break;
1152
1126 case 'N': 1153 case 'N':
1127 switch (fmt[1]) { 1154 switch (fmt[1]) {
1128 case 'F': 1155 case 'F':