aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2017-12-20 07:42:57 -0500
committerAlexei Starovoitov <ast@kernel.org>2017-12-20 21:09:40 -0500
commit7105e828c087de970fcb5a9509db51bfe6bd7894 (patch)
tree47cca432779b910dab12ee5cc81b792f6e432a76 /kernel/bpf/syscall.c
parent4f74d80971bce93d9e608c40324d662c70eb4664 (diff)
bpf: allow for correlation of maps and helpers in dump
Currently a dump of an xlated prog (post verifier stage) doesn't correlate used helpers as well as maps. The prog info lists involved map ids, however there's no correlation of where in the program they are used as of today. Likewise, bpftool does not correlate helper calls with the target functions. The latter can be done w/o any kernel changes through kallsyms, and also has the advantage that this works with inlined helpers and BPF calls. Example, via interpreter: # tc filter show dev foo ingress filter protocol all pref 49152 bpf chain 0 filter protocol all pref 49152 bpf chain 0 handle 0x1 foo.o:[ingress] \ direct-action not_in_hw id 1 tag c74773051b364165 <-- prog id:1 * Output before patch (calls/maps remain unclear): # bpftool prog dump xlated id 1 <-- dump prog id:1 0: (b7) r1 = 2 1: (63) *(u32 *)(r10 -4) = r1 2: (bf) r2 = r10 3: (07) r2 += -4 4: (18) r1 = 0xffff95c47a8d4800 6: (85) call unknown#73040 7: (15) if r0 == 0x0 goto pc+18 8: (bf) r2 = r10 9: (07) r2 += -4 10: (bf) r1 = r0 11: (85) call unknown#73040 12: (15) if r0 == 0x0 goto pc+23 [...] * Output after patch: # bpftool prog dump xlated id 1 0: (b7) r1 = 2 1: (63) *(u32 *)(r10 -4) = r1 2: (bf) r2 = r10 3: (07) r2 += -4 4: (18) r1 = map[id:2] <-- map id:2 6: (85) call bpf_map_lookup_elem#73424 <-- helper call 7: (15) if r0 == 0x0 goto pc+18 8: (bf) r2 = r10 9: (07) r2 += -4 10: (bf) r1 = r0 11: (85) call bpf_map_lookup_elem#73424 12: (15) if r0 == 0x0 goto pc+23 [...] # bpftool map show id 2 <-- show/dump/etc map id:2 2: hash_of_maps flags 0x0 key 4B value 4B max_entries 3 memlock 4096B Example, JITed, same prog: # tc filter show dev foo ingress filter protocol all pref 49152 bpf chain 0 filter protocol all pref 49152 bpf chain 0 handle 0x1 foo.o:[ingress] \ direct-action not_in_hw id 3 tag c74773051b364165 jited # bpftool prog show id 3 3: sched_cls tag c74773051b364165 loaded_at Dec 19/13:48 uid 0 xlated 384B jited 257B memlock 4096B map_ids 2 # bpftool prog dump xlated id 3 0: (b7) r1 = 2 1: (63) *(u32 *)(r10 -4) = r1 2: (bf) r2 = r10 3: (07) r2 += -4 4: (18) r1 = map[id:2] <-- map id:2 6: (85) call __htab_map_lookup_elem#77408 <-+ inlined rewrite 7: (15) if r0 == 0x0 goto pc+2 | 8: (07) r0 += 56 | 9: (79) r0 = *(u64 *)(r0 +0) <-+ 10: (15) if r0 == 0x0 goto pc+24 11: (bf) r2 = r10 12: (07) r2 += -4 [...] Example, same prog, but kallsyms disabled (in that case we are also not allowed to pass any relative offsets, etc, so prog becomes pointer sanitized on dump): # sysctl kernel.kptr_restrict=2 kernel.kptr_restrict = 2 # bpftool prog dump xlated id 3 0: (b7) r1 = 2 1: (63) *(u32 *)(r10 -4) = r1 2: (bf) r2 = r10 3: (07) r2 += -4 4: (18) r1 = map[id:2] 6: (85) call bpf_unspec#0 7: (15) if r0 == 0x0 goto pc+2 [...] Example, BPF calls via interpreter: # bpftool prog dump xlated id 1 0: (85) call pc+2#__bpf_prog_run_args32 1: (b7) r0 = 1 2: (95) exit 3: (b7) r0 = 2 4: (95) exit Example, BPF calls via JIT: # sysctl net.core.bpf_jit_enable=1 net.core.bpf_jit_enable = 1 # sysctl net.core.bpf_jit_kallsyms=1 net.core.bpf_jit_kallsyms = 1 # bpftool prog dump xlated id 1 0: (85) call pc+2#bpf_prog_3b185187f1855c4c_F 1: (b7) r0 = 1 2: (95) exit 3: (b7) r0 = 2 4: (95) exit And finally, an example for tail calls that is now working as well wrt correlation: # bpftool prog dump xlated id 2 [...] 10: (b7) r2 = 8 11: (85) call bpf_trace_printk#-41312 12: (bf) r1 = r6 13: (18) r2 = map[id:1] 15: (b7) r3 = 0 16: (85) call bpf_tail_call#12 17: (b7) r1 = 42 18: (6b) *(u16 *)(r6 +46) = r1 19: (b7) r0 = 0 20: (95) exit # bpftool map show id 1 1: prog_array flags 0x0 key 4B value 4B max_entries 1 memlock 4096B Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r--kernel/bpf/syscall.c87
1 files changed, 82 insertions, 5 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 30e728dcd35d..007802c5ca7d 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1558,6 +1558,67 @@ static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
1558 return fd; 1558 return fd;
1559} 1559}
1560 1560
1561static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
1562 unsigned long addr)
1563{
1564 int i;
1565
1566 for (i = 0; i < prog->aux->used_map_cnt; i++)
1567 if (prog->aux->used_maps[i] == (void *)addr)
1568 return prog->aux->used_maps[i];
1569 return NULL;
1570}
1571
1572static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
1573{
1574 const struct bpf_map *map;
1575 struct bpf_insn *insns;
1576 u64 imm;
1577 int i;
1578
1579 insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
1580 GFP_USER);
1581 if (!insns)
1582 return insns;
1583
1584 for (i = 0; i < prog->len; i++) {
1585 if (insns[i].code == (BPF_JMP | BPF_TAIL_CALL)) {
1586 insns[i].code = BPF_JMP | BPF_CALL;
1587 insns[i].imm = BPF_FUNC_tail_call;
1588 /* fall-through */
1589 }
1590 if (insns[i].code == (BPF_JMP | BPF_CALL) ||
1591 insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) {
1592 if (insns[i].code == (BPF_JMP | BPF_CALL_ARGS))
1593 insns[i].code = BPF_JMP | BPF_CALL;
1594 if (!bpf_dump_raw_ok())
1595 insns[i].imm = 0;
1596 continue;
1597 }
1598
1599 if (insns[i].code != (BPF_LD | BPF_IMM | BPF_DW))
1600 continue;
1601
1602 imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
1603 map = bpf_map_from_imm(prog, imm);
1604 if (map) {
1605 insns[i].src_reg = BPF_PSEUDO_MAP_FD;
1606 insns[i].imm = map->id;
1607 insns[i + 1].imm = 0;
1608 continue;
1609 }
1610
1611 if (!bpf_dump_raw_ok() &&
1612 imm == (unsigned long)prog->aux) {
1613 insns[i].imm = 0;
1614 insns[i + 1].imm = 0;
1615 continue;
1616 }
1617 }
1618
1619 return insns;
1620}
1621
1561static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 1622static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
1562 const union bpf_attr *attr, 1623 const union bpf_attr *attr,
1563 union bpf_attr __user *uattr) 1624 union bpf_attr __user *uattr)
@@ -1608,18 +1669,34 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
1608 ulen = info.jited_prog_len; 1669 ulen = info.jited_prog_len;
1609 info.jited_prog_len = prog->jited_len; 1670 info.jited_prog_len = prog->jited_len;
1610 if (info.jited_prog_len && ulen) { 1671 if (info.jited_prog_len && ulen) {
1611 uinsns = u64_to_user_ptr(info.jited_prog_insns); 1672 if (bpf_dump_raw_ok()) {
1612 ulen = min_t(u32, info.jited_prog_len, ulen); 1673 uinsns = u64_to_user_ptr(info.jited_prog_insns);
1613 if (copy_to_user(uinsns, prog->bpf_func, ulen)) 1674 ulen = min_t(u32, info.jited_prog_len, ulen);
1614 return -EFAULT; 1675 if (copy_to_user(uinsns, prog->bpf_func, ulen))
1676 return -EFAULT;
1677 } else {
1678 info.jited_prog_insns = 0;
1679 }
1615 } 1680 }
1616 1681
1617 ulen = info.xlated_prog_len; 1682 ulen = info.xlated_prog_len;
1618 info.xlated_prog_len = bpf_prog_insn_size(prog); 1683 info.xlated_prog_len = bpf_prog_insn_size(prog);
1619 if (info.xlated_prog_len && ulen) { 1684 if (info.xlated_prog_len && ulen) {
1685 struct bpf_insn *insns_sanitized;
1686 bool fault;
1687
1688 if (prog->blinded && !bpf_dump_raw_ok()) {
1689 info.xlated_prog_insns = 0;
1690 goto done;
1691 }
1692 insns_sanitized = bpf_insn_prepare_dump(prog);
1693 if (!insns_sanitized)
1694 return -ENOMEM;
1620 uinsns = u64_to_user_ptr(info.xlated_prog_insns); 1695 uinsns = u64_to_user_ptr(info.xlated_prog_insns);
1621 ulen = min_t(u32, info.xlated_prog_len, ulen); 1696 ulen = min_t(u32, info.xlated_prog_len, ulen);
1622 if (copy_to_user(uinsns, prog->insnsi, ulen)) 1697 fault = copy_to_user(uinsns, insns_sanitized, ulen);
1698 kfree(insns_sanitized);
1699 if (fault)
1623 return -EFAULT; 1700 return -EFAULT;
1624 } 1701 }
1625 1702