Skip to content

Commit ce69fb3

Browse files
committed
Merge tag 'kallsyms_show_value-v5.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull kallsyms fix from Kees Cook: "Refactor kallsyms_show_value() users for correct cred. I'm not delighted by the timing of getting these changes to you, but it does fix a handful of kernel address exposures, and no one has screamed yet at the patches. Several users of kallsyms_show_value() were performing checks not during "open". Refactor everything needed to gain proper checks against file->f_cred for modules, kprobes, and bpf" * tag 'kallsyms_show_value-v5.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: selftests: kmod: Add module address visibility test bpf: Check correct cred for CAP_SYSLOG in bpf_dump_raw_ok() kprobes: Do not expose probe addresses to non-CAP_SYSLOG module: Do not expose section addresses to non-CAP_SYSLOG module: Refactor section attr into bin attribute kallsyms: Refactor kallsyms_show_value() to take cred
2 parents 0bddd22 + 2c79583 commit ce69fb3

File tree

8 files changed

+103
-53
lines changed

8 files changed

+103
-53
lines changed

include/linux/filter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -884,12 +884,12 @@ void bpf_jit_compile(struct bpf_prog *prog);
884884
bool bpf_jit_needs_zext(void);
885885
bool bpf_helper_changes_pkt_data(void *func);
886886

887-
static inline bool bpf_dump_raw_ok(void)
887+
static inline bool bpf_dump_raw_ok(const struct cred *cred)
888888
{
889889
/* Reconstruction of call-sites is dependent on kallsyms,
890890
* thus make dump the same restriction.
891891
*/
892-
return kallsyms_show_value() == 1;
892+
return kallsyms_show_value(cred);
893893
}
894894

895895
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,

include/linux/kallsyms.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
1919
2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1)
2020

21+
struct cred;
2122
struct module;
2223

2324
static inline int is_kernel_inittext(unsigned long addr)
@@ -98,7 +99,7 @@ int lookup_symbol_name(unsigned long addr, char *symname);
9899
int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
99100

100101
/* How and when do we show kallsyms values? */
101-
extern int kallsyms_show_value(void);
102+
extern bool kallsyms_show_value(const struct cred *cred);
102103

103104
#else /* !CONFIG_KALLSYMS */
104105

@@ -158,7 +159,7 @@ static inline int lookup_symbol_attrs(unsigned long addr, unsigned long *size, u
158159
return -ERANGE;
159160
}
160161

161-
static inline int kallsyms_show_value(void)
162+
static inline bool kallsyms_show_value(const struct cred *cred)
162163
{
163164
return false;
164165
}

kernel/bpf/syscall.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,7 +3139,8 @@ static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
31393139
return NULL;
31403140
}
31413141

3142-
static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
3142+
static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
3143+
const struct cred *f_cred)
31433144
{
31443145
const struct bpf_map *map;
31453146
struct bpf_insn *insns;
@@ -3165,7 +3166,7 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
31653166
code == (BPF_JMP | BPF_CALL_ARGS)) {
31663167
if (code == (BPF_JMP | BPF_CALL_ARGS))
31673168
insns[i].code = BPF_JMP | BPF_CALL;
3168-
if (!bpf_dump_raw_ok())
3169+
if (!bpf_dump_raw_ok(f_cred))
31693170
insns[i].imm = 0;
31703171
continue;
31713172
}
@@ -3221,7 +3222,8 @@ static int set_info_rec_size(struct bpf_prog_info *info)
32213222
return 0;
32223223
}
32233224

3224-
static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
3225+
static int bpf_prog_get_info_by_fd(struct file *file,
3226+
struct bpf_prog *prog,
32253227
const union bpf_attr *attr,
32263228
union bpf_attr __user *uattr)
32273229
{
@@ -3290,11 +3292,11 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
32903292
struct bpf_insn *insns_sanitized;
32913293
bool fault;
32923294

3293-
if (prog->blinded && !bpf_dump_raw_ok()) {
3295+
if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
32943296
info.xlated_prog_insns = 0;
32953297
goto done;
32963298
}
3297-
insns_sanitized = bpf_insn_prepare_dump(prog);
3299+
insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
32983300
if (!insns_sanitized)
32993301
return -ENOMEM;
33003302
uinsns = u64_to_user_ptr(info.xlated_prog_insns);
@@ -3328,7 +3330,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
33283330
}
33293331

33303332
if (info.jited_prog_len && ulen) {
3331-
if (bpf_dump_raw_ok()) {
3333+
if (bpf_dump_raw_ok(file->f_cred)) {
33323334
uinsns = u64_to_user_ptr(info.jited_prog_insns);
33333335
ulen = min_t(u32, info.jited_prog_len, ulen);
33343336

@@ -3363,7 +3365,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
33633365
ulen = info.nr_jited_ksyms;
33643366
info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
33653367
if (ulen) {
3366-
if (bpf_dump_raw_ok()) {
3368+
if (bpf_dump_raw_ok(file->f_cred)) {
33673369
unsigned long ksym_addr;
33683370
u64 __user *user_ksyms;
33693371
u32 i;
@@ -3394,7 +3396,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
33943396
ulen = info.nr_jited_func_lens;
33953397
info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
33963398
if (ulen) {
3397-
if (bpf_dump_raw_ok()) {
3399+
if (bpf_dump_raw_ok(file->f_cred)) {
33983400
u32 __user *user_lens;
33993401
u32 func_len, i;
34003402

@@ -3451,7 +3453,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
34513453
else
34523454
info.nr_jited_line_info = 0;
34533455
if (info.nr_jited_line_info && ulen) {
3454-
if (bpf_dump_raw_ok()) {
3456+
if (bpf_dump_raw_ok(file->f_cred)) {
34553457
__u64 __user *user_linfo;
34563458
u32 i;
34573459

@@ -3497,7 +3499,8 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
34973499
return 0;
34983500
}
34993501

3500-
static int bpf_map_get_info_by_fd(struct bpf_map *map,
3502+
static int bpf_map_get_info_by_fd(struct file *file,
3503+
struct bpf_map *map,
35013504
const union bpf_attr *attr,
35023505
union bpf_attr __user *uattr)
35033506
{
@@ -3540,7 +3543,8 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map,
35403543
return 0;
35413544
}
35423545

3543-
static int bpf_btf_get_info_by_fd(struct btf *btf,
3546+
static int bpf_btf_get_info_by_fd(struct file *file,
3547+
struct btf *btf,
35443548
const union bpf_attr *attr,
35453549
union bpf_attr __user *uattr)
35463550
{
@@ -3555,7 +3559,8 @@ static int bpf_btf_get_info_by_fd(struct btf *btf,
35553559
return btf_get_info_by_fd(btf, attr, uattr);
35563560
}
35573561

3558-
static int bpf_link_get_info_by_fd(struct bpf_link *link,
3562+
static int bpf_link_get_info_by_fd(struct file *file,
3563+
struct bpf_link *link,
35593564
const union bpf_attr *attr,
35603565
union bpf_attr __user *uattr)
35613566
{
@@ -3608,15 +3613,15 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
36083613
return -EBADFD;
36093614

36103615
if (f.file->f_op == &bpf_prog_fops)
3611-
err = bpf_prog_get_info_by_fd(f.file->private_data, attr,
3616+
err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
36123617
uattr);
36133618
else if (f.file->f_op == &bpf_map_fops)
3614-
err = bpf_map_get_info_by_fd(f.file->private_data, attr,
3619+
err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
36153620
uattr);
36163621
else if (f.file->f_op == &btf_fops)
3617-
err = bpf_btf_get_info_by_fd(f.file->private_data, attr, uattr);
3622+
err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
36183623
else if (f.file->f_op == &bpf_link_fops)
3619-
err = bpf_link_get_info_by_fd(f.file->private_data,
3624+
err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
36203625
attr, uattr);
36213626
else
36223627
err = -EINVAL;

kernel/kallsyms.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -644,19 +644,20 @@ static inline int kallsyms_for_perf(void)
644644
* Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to
645645
* block even that).
646646
*/
647-
int kallsyms_show_value(void)
647+
bool kallsyms_show_value(const struct cred *cred)
648648
{
649649
switch (kptr_restrict) {
650650
case 0:
651651
if (kallsyms_for_perf())
652-
return 1;
652+
return true;
653653
/* fallthrough */
654654
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;
657658
/* fallthrough */
658659
default:
659-
return 0;
660+
return false;
660661
}
661662
}
662663

@@ -673,7 +674,11 @@ static int kallsyms_open(struct inode *inode, struct file *file)
673674
return -ENOMEM;
674675
reset_iter(iter, 0);
675676

676-
iter->show_value = kallsyms_show_value();
677+
/*
678+
* Instead of checking this on every s_show() call, cache
679+
* the result here at open time.
680+
*/
681+
iter->show_value = kallsyms_show_value(file->f_cred);
677682
return 0;
678683
}
679684

kernel/kprobes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,7 @@ static void report_probe(struct seq_file *pi, struct kprobe *p,
24482448
else
24492449
kprobe_type = "k";
24502450

2451-
if (!kallsyms_show_value())
2451+
if (!kallsyms_show_value(pi->file->f_cred))
24522452
addr = NULL;
24532453

24542454
if (sym)
@@ -2540,7 +2540,7 @@ static int kprobe_blacklist_seq_show(struct seq_file *m, void *v)
25402540
* If /proc/kallsyms is not showing kernel address, we won't
25412541
* show them here either.
25422542
*/
2543-
if (!kallsyms_show_value())
2543+
if (!kallsyms_show_value(m->file->f_cred))
25442544
seq_printf(m, "0x%px-0x%px\t%ps\n", NULL, NULL,
25452545
(void *)ent->start_addr);
25462546
else

kernel/module.c

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,8 +1510,7 @@ static inline bool sect_empty(const Elf_Shdr *sect)
15101510
}
15111511

15121512
struct module_sect_attr {
1513-
struct module_attribute mattr;
1514-
char *name;
1513+
struct bin_attribute battr;
15151514
unsigned long address;
15161515
};
15171516

@@ -1521,21 +1520,26 @@ struct module_sect_attrs {
15211520
struct module_sect_attr attrs[];
15221521
};
15231522

1524-
static ssize_t module_sect_show(struct module_attribute *mattr,
1525-
struct module_kobject *mk, char *buf)
1523+
static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
1524+
struct bin_attribute *battr,
1525+
char *buf, loff_t pos, size_t count)
15261526
{
15271527
struct module_sect_attr *sattr =
1528-
container_of(mattr, struct module_sect_attr, mattr);
1529-
return sprintf(buf, "0x%px\n", kptr_restrict < 2 ?
1530-
(void *)sattr->address : NULL);
1528+
container_of(battr, struct module_sect_attr, battr);
1529+
1530+
if (pos != 0)
1531+
return -EINVAL;
1532+
1533+
return sprintf(buf, "0x%px\n",
1534+
kallsyms_show_value(file->f_cred) ? (void *)sattr->address : NULL);
15311535
}
15321536

15331537
static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
15341538
{
15351539
unsigned int section;
15361540

15371541
for (section = 0; section < sect_attrs->nsections; section++)
1538-
kfree(sect_attrs->attrs[section].name);
1542+
kfree(sect_attrs->attrs[section].battr.attr.name);
15391543
kfree(sect_attrs);
15401544
}
15411545

@@ -1544,42 +1548,41 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
15441548
unsigned int nloaded = 0, i, size[2];
15451549
struct module_sect_attrs *sect_attrs;
15461550
struct module_sect_attr *sattr;
1547-
struct attribute **gattr;
1551+
struct bin_attribute **gattr;
15481552

15491553
/* Count loaded sections and allocate structures */
15501554
for (i = 0; i < info->hdr->e_shnum; i++)
15511555
if (!sect_empty(&info->sechdrs[i]))
15521556
nloaded++;
15531557
size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
1554-
sizeof(sect_attrs->grp.attrs[0]));
1555-
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
1558+
sizeof(sect_attrs->grp.bin_attrs[0]));
1559+
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
15561560
sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
15571561
if (sect_attrs == NULL)
15581562
return;
15591563

15601564
/* Setup section attributes. */
15611565
sect_attrs->grp.name = "sections";
1562-
sect_attrs->grp.attrs = (void *)sect_attrs + size[0];
1566+
sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
15631567

15641568
sect_attrs->nsections = 0;
15651569
sattr = &sect_attrs->attrs[0];
1566-
gattr = &sect_attrs->grp.attrs[0];
1570+
gattr = &sect_attrs->grp.bin_attrs[0];
15671571
for (i = 0; i < info->hdr->e_shnum; i++) {
15681572
Elf_Shdr *sec = &info->sechdrs[i];
15691573
if (sect_empty(sec))
15701574
continue;
1575+
sysfs_bin_attr_init(&sattr->battr);
15711576
sattr->address = sec->sh_addr;
1572-
sattr->name = kstrdup(info->secstrings + sec->sh_name,
1573-
GFP_KERNEL);
1574-
if (sattr->name == NULL)
1577+
sattr->battr.attr.name =
1578+
kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
1579+
if (sattr->battr.attr.name == NULL)
15751580
goto out;
15761581
sect_attrs->nsections++;
1577-
sysfs_attr_init(&sattr->mattr.attr);
1578-
sattr->mattr.show = module_sect_show;
1579-
sattr->mattr.store = NULL;
1580-
sattr->mattr.attr.name = sattr->name;
1581-
sattr->mattr.attr.mode = S_IRUSR;
1582-
*(gattr++) = &(sattr++)->mattr.attr;
1582+
sattr->battr.read = module_sect_read;
1583+
sattr->battr.size = 3 /* "0x", "\n" */ + (BITS_PER_LONG / 4);
1584+
sattr->battr.attr.mode = 0400;
1585+
*(gattr++) = &(sattr++)->battr;
15831586
}
15841587
*gattr = NULL;
15851588

@@ -1669,7 +1672,7 @@ static void add_notes_attrs(struct module *mod, const struct load_info *info)
16691672
continue;
16701673
if (info->sechdrs[i].sh_type == SHT_NOTE) {
16711674
sysfs_bin_attr_init(nattr);
1672-
nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
1675+
nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
16731676
nattr->attr.mode = S_IRUGO;
16741677
nattr->size = info->sechdrs[i].sh_size;
16751678
nattr->private = (void *) info->sechdrs[i].sh_addr;
@@ -4379,7 +4382,7 @@ static int modules_open(struct inode *inode, struct file *file)
43794382

43804383
if (!err) {
43814384
struct seq_file *m = file->private_data;
4382-
m->private = kallsyms_show_value() ? NULL : (void *)8ul;
4385+
m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
43834386
}
43844387

43854388
return err;

net/core/sysctl_net_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ static int proc_dointvec_minmax_bpf_enable(struct ctl_table *table, int write,
274274
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
275275
if (write && !ret) {
276276
if (jit_enable < 2 ||
277-
(jit_enable == 2 && bpf_dump_raw_ok())) {
277+
(jit_enable == 2 && bpf_dump_raw_ok(current_cred()))) {
278278
*(int *)table->data = jit_enable;
279279
if (jit_enable == 2)
280280
pr_warn("bpf_jit_enable = 2 was set! NEVER use this in production, only for JIT debugging!\n");

0 commit comments

Comments
 (0)