Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kallsyms: Refactor kallsyms_show_value() to take cred

In order to perform future tests against the cred saved during open(),
switch kallsyms_show_value() to operate on a cred, and have all current
callers pass current_cred(). This makes it very obvious where callers
are checking the wrong credential in their "read" contexts. These will
be fixed in the coming patches.

Additionally switch return value to bool, since it is always used as a
direct permission check, not a 0-on-success, negative-on-error style
function return.

Cc: stable@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>

+18 -12
+1 -1
include/linux/filter.h
··· 889 889 /* Reconstruction of call-sites is dependent on kallsyms, 890 890 * thus make dump the same restriction. 891 891 */ 892 - return kallsyms_show_value() == 1; 892 + return kallsyms_show_value(current_cred()); 893 893 } 894 894 895 895 struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
+3 -2
include/linux/kallsyms.h
··· 18 18 #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ 19 19 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1) 20 20 21 + struct cred; 21 22 struct module; 22 23 23 24 static inline int is_kernel_inittext(unsigned long addr) ··· 99 98 int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); 100 99 101 100 /* How and when do we show kallsyms values? */ 102 - extern int kallsyms_show_value(void); 101 + extern bool kallsyms_show_value(const struct cred *cred); 103 102 104 103 #else /* !CONFIG_KALLSYMS */ 105 104 ··· 159 158 return -ERANGE; 160 159 } 161 160 162 - static inline int kallsyms_show_value(void) 161 + static inline bool kallsyms_show_value(const struct cred *cred) 163 162 { 164 163 return false; 165 164 }
+11 -6
kernel/kallsyms.c
··· 644 644 * Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to 645 645 * block even that). 646 646 */ 647 - int kallsyms_show_value(void) 647 + bool kallsyms_show_value(const struct cred *cred) 648 648 { 649 649 switch (kptr_restrict) { 650 650 case 0: 651 651 if (kallsyms_for_perf()) 652 - return 1; 652 + return true; 653 653 /* fallthrough */ 654 654 case 1: 655 - if (has_capability_noaudit(current, CAP_SYSLOG)) 656 - return 1; 655 + if (security_capable(cred, &init_user_ns, CAP_SYSLOG, 656 + CAP_OPT_NOAUDIT) == 0) 657 + return true; 657 658 /* fallthrough */ 658 659 default: 659 - return 0; 660 + return false; 660 661 } 661 662 } 662 663 ··· 674 673 return -ENOMEM; 675 674 reset_iter(iter, 0); 676 675 677 - iter->show_value = kallsyms_show_value(); 676 + /* 677 + * Instead of checking this on every s_show() call, cache 678 + * the result here at open time. 679 + */ 680 + iter->show_value = kallsyms_show_value(file->f_cred); 678 681 return 0; 679 682 } 680 683
+2 -2
kernel/kprobes.c
··· 2448 2448 else 2449 2449 kprobe_type = "k"; 2450 2450 2451 - if (!kallsyms_show_value()) 2451 + if (!kallsyms_show_value(current_cred())) 2452 2452 addr = NULL; 2453 2453 2454 2454 if (sym) ··· 2540 2540 * If /proc/kallsyms is not showing kernel address, we won't 2541 2541 * show them here either. 2542 2542 */ 2543 - if (!kallsyms_show_value()) 2543 + if (!kallsyms_show_value(current_cred())) 2544 2544 seq_printf(m, "0x%px-0x%px\t%ps\n", NULL, NULL, 2545 2545 (void *)ent->start_addr); 2546 2546 else
+1 -1
kernel/module.c
··· 4377 4377 4378 4378 if (!err) { 4379 4379 struct seq_file *m = file->private_data; 4380 - m->private = kallsyms_show_value() ? NULL : (void *)8ul; 4380 + m->private = kallsyms_show_value(current_cred()) ? NULL : (void *)8ul; 4381 4381 } 4382 4382 4383 4383 return err;