aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/bpf_trace.c
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2018-03-30 18:08:00 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-03-30 20:14:44 -0400
commit5e43f899b03a3492ce5fc44e8900becb04dae9c0 (patch)
tree2811b77402c54e99a10a74f8a1b092b4bc2e24f6 /kernel/trace/bpf_trace.c
parent807ae7daf5fb9ba9ef688344ae7c0d8cbebd211c (diff)
bpf: Check attach type at prog load time
== The problem == There are use-cases when a program of some type can be attached to multiple attach points and those attach points must have different permissions to access context or to call helpers. E.g. context structure may have fields for both IPv4 and IPv6 but it doesn't make sense to read from / write to IPv6 field when attach point is somewhere in IPv4 stack. Same applies to BPF-helpers: it may make sense to call some helper from some attach point, but not from other for same prog type. == The solution == Introduce `expected_attach_type` field in in `struct bpf_attr` for `BPF_PROG_LOAD` command. If scenario described in "The problem" section is the case for some prog type, the field will be checked twice: 1) At load time prog type is checked to see if attach type for it must be known to validate program permissions correctly. Prog will be rejected with EINVAL if it's the case and `expected_attach_type` is not specified or has invalid value. 2) At attach time `attach_type` is compared with `expected_attach_type`, if prog type requires to have one, and, if they differ, attach will be rejected with EINVAL. The `expected_attach_type` is now available as part of `struct bpf_prog` in both `bpf_verifier_ops->is_valid_access()` and `bpf_verifier_ops->get_func_proto()` () and can be used to check context accesses and calls to helpers correspondingly. Initially the idea was discussed by Alexei Starovoitov <ast@fb.com> and Daniel Borkmann <daniel@iogearbox.net> here: https://marc.info/?l=linux-netdev&m=152107378717201&w=2 Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel/trace/bpf_trace.c')
-rw-r--r--kernel/trace/bpf_trace.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 463e72d18c4c..d88e96d4e12c 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -524,7 +524,8 @@ static const struct bpf_func_proto bpf_probe_read_str_proto = {
524 .arg3_type = ARG_ANYTHING, 524 .arg3_type = ARG_ANYTHING,
525}; 525};
526 526
527static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id) 527static const struct bpf_func_proto *
528tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
528{ 529{
529 switch (func_id) { 530 switch (func_id) {
530 case BPF_FUNC_map_lookup_elem: 531 case BPF_FUNC_map_lookup_elem:
@@ -568,7 +569,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
568 } 569 }
569} 570}
570 571
571static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func_id) 572static const struct bpf_func_proto *
573kprobe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
572{ 574{
573 switch (func_id) { 575 switch (func_id) {
574 case BPF_FUNC_perf_event_output: 576 case BPF_FUNC_perf_event_output:
@@ -582,12 +584,13 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func
582 return &bpf_override_return_proto; 584 return &bpf_override_return_proto;
583#endif 585#endif
584 default: 586 default:
585 return tracing_func_proto(func_id); 587 return tracing_func_proto(func_id, prog);
586 } 588 }
587} 589}
588 590
589/* bpf+kprobe programs can access fields of 'struct pt_regs' */ 591/* bpf+kprobe programs can access fields of 'struct pt_regs' */
590static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type, 592static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
593 const struct bpf_prog *prog,
591 struct bpf_insn_access_aux *info) 594 struct bpf_insn_access_aux *info)
592{ 595{
593 if (off < 0 || off >= sizeof(struct pt_regs)) 596 if (off < 0 || off >= sizeof(struct pt_regs))
@@ -661,7 +664,8 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {
661 .arg3_type = ARG_ANYTHING, 664 .arg3_type = ARG_ANYTHING,
662}; 665};
663 666
664static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id) 667static const struct bpf_func_proto *
668tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
665{ 669{
666 switch (func_id) { 670 switch (func_id) {
667 case BPF_FUNC_perf_event_output: 671 case BPF_FUNC_perf_event_output:
@@ -669,11 +673,12 @@ static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
669 case BPF_FUNC_get_stackid: 673 case BPF_FUNC_get_stackid:
670 return &bpf_get_stackid_proto_tp; 674 return &bpf_get_stackid_proto_tp;
671 default: 675 default:
672 return tracing_func_proto(func_id); 676 return tracing_func_proto(func_id, prog);
673 } 677 }
674} 678}
675 679
676static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type, 680static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type,
681 const struct bpf_prog *prog,
677 struct bpf_insn_access_aux *info) 682 struct bpf_insn_access_aux *info)
678{ 683{
679 if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE) 684 if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE)
@@ -721,7 +726,8 @@ static const struct bpf_func_proto bpf_perf_prog_read_value_proto = {
721 .arg3_type = ARG_CONST_SIZE, 726 .arg3_type = ARG_CONST_SIZE,
722}; 727};
723 728
724static const struct bpf_func_proto *pe_prog_func_proto(enum bpf_func_id func_id) 729static const struct bpf_func_proto *
730pe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
725{ 731{
726 switch (func_id) { 732 switch (func_id) {
727 case BPF_FUNC_perf_event_output: 733 case BPF_FUNC_perf_event_output:
@@ -731,7 +737,7 @@ static const struct bpf_func_proto *pe_prog_func_proto(enum bpf_func_id func_id)
731 case BPF_FUNC_perf_prog_read_value: 737 case BPF_FUNC_perf_prog_read_value:
732 return &bpf_perf_prog_read_value_proto; 738 return &bpf_perf_prog_read_value_proto;
733 default: 739 default:
734 return tracing_func_proto(func_id); 740 return tracing_func_proto(func_id, prog);
735 } 741 }
736} 742}
737 743
@@ -781,7 +787,8 @@ static const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = {
781 .arg3_type = ARG_ANYTHING, 787 .arg3_type = ARG_ANYTHING,
782}; 788};
783 789
784static const struct bpf_func_proto *raw_tp_prog_func_proto(enum bpf_func_id func_id) 790static const struct bpf_func_proto *
791raw_tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
785{ 792{
786 switch (func_id) { 793 switch (func_id) {
787 case BPF_FUNC_perf_event_output: 794 case BPF_FUNC_perf_event_output:
@@ -789,12 +796,13 @@ static const struct bpf_func_proto *raw_tp_prog_func_proto(enum bpf_func_id func
789 case BPF_FUNC_get_stackid: 796 case BPF_FUNC_get_stackid:
790 return &bpf_get_stackid_proto_raw_tp; 797 return &bpf_get_stackid_proto_raw_tp;
791 default: 798 default:
792 return tracing_func_proto(func_id); 799 return tracing_func_proto(func_id, prog);
793 } 800 }
794} 801}
795 802
796static bool raw_tp_prog_is_valid_access(int off, int size, 803static bool raw_tp_prog_is_valid_access(int off, int size,
797 enum bpf_access_type type, 804 enum bpf_access_type type,
805 const struct bpf_prog *prog,
798 struct bpf_insn_access_aux *info) 806 struct bpf_insn_access_aux *info)
799{ 807{
800 /* largest tracepoint in the kernel has 12 args */ 808 /* largest tracepoint in the kernel has 12 args */
@@ -816,6 +824,7 @@ const struct bpf_prog_ops raw_tracepoint_prog_ops = {
816}; 824};
817 825
818static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type, 826static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
827 const struct bpf_prog *prog,
819 struct bpf_insn_access_aux *info) 828 struct bpf_insn_access_aux *info)
820{ 829{
821 const int size_u64 = sizeof(u64); 830 const int size_u64 = sizeof(u64);