aboutsummaryrefslogtreecommitdiffstats
path: root/samples/bpf
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2015-10-08 01:23:23 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-12 22:13:37 -0400
commitbf5088773faffc4a052b95aa978a1660bf5f3f8d (patch)
treece888633783880b3970d2270fc1428fbbb84259e /samples/bpf
parentaaac3ba95e4c8b496d22f68bd1bc01cfbf525eca (diff)
bpf: add unprivileged bpf tests
Add new tests samples/bpf/test_verifier: unpriv: return pointer checks that pointer cannot be returned from the eBPF program unpriv: add const to pointer unpriv: add pointer to pointer unpriv: neg pointer checks that pointer arithmetic is disallowed unpriv: cmp pointer with const unpriv: cmp pointer with pointer checks that comparison of pointers is disallowed Only one case allowed 'void *value = bpf_map_lookup_elem(..); if (value == 0) ...' unpriv: check that printk is disallowed since bpf_trace_printk is not available to unprivileged unpriv: pass pointer to helper function checks that pointers cannot be passed to functions that expect integers If function expects a pointer the verifier allows only that type of pointer. Like 1st argument of bpf_map_lookup_elem() must be pointer to map. (applies to non-root as well) unpriv: indirectly pass pointer on stack to helper function checks that pointer stored into stack cannot be used as part of key passed into bpf_map_lookup_elem() unpriv: mangle pointer on stack 1 unpriv: mangle pointer on stack 2 checks that writing into stack slot that already contains a pointer is disallowed unpriv: read pointer from stack in small chunks checks that < 8 byte read from stack slot that contains a pointer is disallowed unpriv: write pointer into ctx checks that storing pointers into skb->fields is disallowed unpriv: write pointer into map elem value checks that storing pointers into element values is disallowed For example: int bpf_prog(struct __sk_buff *skb) { u32 key = 0; u64 *value = bpf_map_lookup_elem(&map, &key); if (value) *value = (u64) skb; } will be rejected. unpriv: partial copy of pointer checks that doing 32-bit register mov from register containing a pointer is disallowed unpriv: pass pointer to tail_call checks that passing pointer as an index into bpf_tail_call is disallowed unpriv: cmp map pointer with zero checks that comparing map pointer with constant is disallowed unpriv: write into frame pointer checks that frame pointer is read-only (applies to root too) unpriv: cmp of frame pointer checks that R10 cannot be using in comparison unpriv: cmp of stack pointer checks that Rx = R10 - imm is ok, but comparing Rx is not unpriv: obfuscate stack pointer checks that Rx = R10 - imm is ok, but Rx -= imm is not Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples/bpf')
-rw-r--r--samples/bpf/libbpf.h8
-rw-r--r--samples/bpf/test_verifier.c357
2 files changed, 355 insertions, 10 deletions
diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h
index 7235e292a03b..b7f63c70b4a2 100644
--- a/samples/bpf/libbpf.h
+++ b/samples/bpf/libbpf.h
@@ -64,6 +64,14 @@ extern char bpf_log_buf[LOG_BUF_SIZE];
64 .off = 0, \ 64 .off = 0, \
65 .imm = 0 }) 65 .imm = 0 })
66 66
67#define BPF_MOV32_REG(DST, SRC) \
68 ((struct bpf_insn) { \
69 .code = BPF_ALU | BPF_MOV | BPF_X, \
70 .dst_reg = DST, \
71 .src_reg = SRC, \
72 .off = 0, \
73 .imm = 0 })
74
67/* Short form of mov, dst_reg = imm32 */ 75/* Short form of mov, dst_reg = imm32 */
68 76
69#define BPF_MOV64_IMM(DST, IMM) \ 77#define BPF_MOV64_IMM(DST, IMM) \
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c
index ee0f110c9c54..563c507c0a09 100644
--- a/samples/bpf/test_verifier.c
+++ b/samples/bpf/test_verifier.c
@@ -15,20 +15,27 @@
15#include <string.h> 15#include <string.h>
16#include <linux/filter.h> 16#include <linux/filter.h>
17#include <stddef.h> 17#include <stddef.h>
18#include <stdbool.h>
19#include <sys/resource.h>
18#include "libbpf.h" 20#include "libbpf.h"
19 21
20#define MAX_INSNS 512 22#define MAX_INSNS 512
21#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 23#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
22 24
25#define MAX_FIXUPS 8
26
23struct bpf_test { 27struct bpf_test {
24 const char *descr; 28 const char *descr;
25 struct bpf_insn insns[MAX_INSNS]; 29 struct bpf_insn insns[MAX_INSNS];
26 int fixup[32]; 30 int fixup[MAX_FIXUPS];
31 int prog_array_fixup[MAX_FIXUPS];
27 const char *errstr; 32 const char *errstr;
33 const char *errstr_unpriv;
28 enum { 34 enum {
35 UNDEF,
29 ACCEPT, 36 ACCEPT,
30 REJECT 37 REJECT
31 } result; 38 } result, result_unpriv;
32 enum bpf_prog_type prog_type; 39 enum bpf_prog_type prog_type;
33}; 40};
34 41
@@ -96,6 +103,7 @@ static struct bpf_test tests[] = {
96 BPF_EXIT_INSN(), 103 BPF_EXIT_INSN(),
97 }, 104 },
98 .errstr = "invalid BPF_LD_IMM insn", 105 .errstr = "invalid BPF_LD_IMM insn",
106 .errstr_unpriv = "R1 pointer comparison",
99 .result = REJECT, 107 .result = REJECT,
100 }, 108 },
101 { 109 {
@@ -109,6 +117,7 @@ static struct bpf_test tests[] = {
109 BPF_EXIT_INSN(), 117 BPF_EXIT_INSN(),
110 }, 118 },
111 .errstr = "invalid BPF_LD_IMM insn", 119 .errstr = "invalid BPF_LD_IMM insn",
120 .errstr_unpriv = "R1 pointer comparison",
112 .result = REJECT, 121 .result = REJECT,
113 }, 122 },
114 { 123 {
@@ -219,6 +228,7 @@ static struct bpf_test tests[] = {
219 BPF_EXIT_INSN(), 228 BPF_EXIT_INSN(),
220 }, 229 },
221 .errstr = "R0 !read_ok", 230 .errstr = "R0 !read_ok",
231 .errstr_unpriv = "R1 pointer comparison",
222 .result = REJECT, 232 .result = REJECT,
223 }, 233 },
224 { 234 {
@@ -294,7 +304,9 @@ static struct bpf_test tests[] = {
294 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), 304 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
295 BPF_EXIT_INSN(), 305 BPF_EXIT_INSN(),
296 }, 306 },
307 .errstr_unpriv = "R0 leaks addr",
297 .result = ACCEPT, 308 .result = ACCEPT,
309 .result_unpriv = REJECT,
298 }, 310 },
299 { 311 {
300 "check corrupted spill/fill", 312 "check corrupted spill/fill",
@@ -310,6 +322,7 @@ static struct bpf_test tests[] = {
310 322
311 BPF_EXIT_INSN(), 323 BPF_EXIT_INSN(),
312 }, 324 },
325 .errstr_unpriv = "attempt to corrupt spilled",
313 .errstr = "corrupted spill", 326 .errstr = "corrupted spill",
314 .result = REJECT, 327 .result = REJECT,
315 }, 328 },
@@ -473,6 +486,7 @@ static struct bpf_test tests[] = {
473 }, 486 },
474 .fixup = {3}, 487 .fixup = {3},
475 .errstr = "R0 invalid mem access", 488 .errstr = "R0 invalid mem access",
489 .errstr_unpriv = "R0 leaks addr",
476 .result = REJECT, 490 .result = REJECT,
477 }, 491 },
478 { 492 {
@@ -495,6 +509,8 @@ static struct bpf_test tests[] = {
495 BPF_MOV64_IMM(BPF_REG_0, 0), 509 BPF_MOV64_IMM(BPF_REG_0, 0),
496 BPF_EXIT_INSN(), 510 BPF_EXIT_INSN(),
497 }, 511 },
512 .errstr_unpriv = "R1 pointer comparison",
513 .result_unpriv = REJECT,
498 .result = ACCEPT, 514 .result = ACCEPT,
499 }, 515 },
500 { 516 {
@@ -521,6 +537,8 @@ static struct bpf_test tests[] = {
521 BPF_MOV64_IMM(BPF_REG_0, 0), 537 BPF_MOV64_IMM(BPF_REG_0, 0),
522 BPF_EXIT_INSN(), 538 BPF_EXIT_INSN(),
523 }, 539 },
540 .errstr_unpriv = "R1 pointer comparison",
541 .result_unpriv = REJECT,
524 .result = ACCEPT, 542 .result = ACCEPT,
525 }, 543 },
526 { 544 {
@@ -555,6 +573,8 @@ static struct bpf_test tests[] = {
555 BPF_EXIT_INSN(), 573 BPF_EXIT_INSN(),
556 }, 574 },
557 .fixup = {24}, 575 .fixup = {24},
576 .errstr_unpriv = "R1 pointer comparison",
577 .result_unpriv = REJECT,
558 .result = ACCEPT, 578 .result = ACCEPT,
559 }, 579 },
560 { 580 {
@@ -603,6 +623,8 @@ static struct bpf_test tests[] = {
603 BPF_MOV64_IMM(BPF_REG_0, 0), 623 BPF_MOV64_IMM(BPF_REG_0, 0),
604 BPF_EXIT_INSN(), 624 BPF_EXIT_INSN(),
605 }, 625 },
626 .errstr_unpriv = "R1 pointer comparison",
627 .result_unpriv = REJECT,
606 .result = ACCEPT, 628 .result = ACCEPT,
607 }, 629 },
608 { 630 {
@@ -642,6 +664,8 @@ static struct bpf_test tests[] = {
642 BPF_MOV64_IMM(BPF_REG_0, 0), 664 BPF_MOV64_IMM(BPF_REG_0, 0),
643 BPF_EXIT_INSN(), 665 BPF_EXIT_INSN(),
644 }, 666 },
667 .errstr_unpriv = "R1 pointer comparison",
668 .result_unpriv = REJECT,
645 .result = ACCEPT, 669 .result = ACCEPT,
646 }, 670 },
647 { 671 {
@@ -699,6 +723,7 @@ static struct bpf_test tests[] = {
699 }, 723 },
700 .fixup = {4}, 724 .fixup = {4},
701 .errstr = "different pointers", 725 .errstr = "different pointers",
726 .errstr_unpriv = "R1 pointer comparison",
702 .result = REJECT, 727 .result = REJECT,
703 }, 728 },
704 { 729 {
@@ -720,6 +745,7 @@ static struct bpf_test tests[] = {
720 }, 745 },
721 .fixup = {6}, 746 .fixup = {6},
722 .errstr = "different pointers", 747 .errstr = "different pointers",
748 .errstr_unpriv = "R1 pointer comparison",
723 .result = REJECT, 749 .result = REJECT,
724 }, 750 },
725 { 751 {
@@ -742,6 +768,7 @@ static struct bpf_test tests[] = {
742 }, 768 },
743 .fixup = {7}, 769 .fixup = {7},
744 .errstr = "different pointers", 770 .errstr = "different pointers",
771 .errstr_unpriv = "R1 pointer comparison",
745 .result = REJECT, 772 .result = REJECT,
746 }, 773 },
747 { 774 {
@@ -752,6 +779,7 @@ static struct bpf_test tests[] = {
752 BPF_EXIT_INSN(), 779 BPF_EXIT_INSN(),
753 }, 780 },
754 .errstr = "invalid bpf_context access", 781 .errstr = "invalid bpf_context access",
782 .errstr_unpriv = "R1 leaks addr",
755 .result = REJECT, 783 .result = REJECT,
756 }, 784 },
757 { 785 {
@@ -762,6 +790,7 @@ static struct bpf_test tests[] = {
762 BPF_EXIT_INSN(), 790 BPF_EXIT_INSN(),
763 }, 791 },
764 .errstr = "invalid bpf_context access", 792 .errstr = "invalid bpf_context access",
793 .errstr_unpriv = "R1 leaks addr",
765 .result = REJECT, 794 .result = REJECT,
766 }, 795 },
767 { 796 {
@@ -772,16 +801,18 @@ static struct bpf_test tests[] = {
772 BPF_EXIT_INSN(), 801 BPF_EXIT_INSN(),
773 }, 802 },
774 .errstr = "invalid bpf_context access", 803 .errstr = "invalid bpf_context access",
804 .errstr_unpriv = "R1 leaks addr",
775 .result = REJECT, 805 .result = REJECT,
776 }, 806 },
777 { 807 {
778 "check out of range skb->cb access", 808 "check out of range skb->cb access",
779 .insns = { 809 .insns = {
780 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 810 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
781 offsetof(struct __sk_buff, cb[60])), 811 offsetof(struct __sk_buff, cb[0]) + 256),
782 BPF_EXIT_INSN(), 812 BPF_EXIT_INSN(),
783 }, 813 },
784 .errstr = "invalid bpf_context access", 814 .errstr = "invalid bpf_context access",
815 .errstr_unpriv = "",
785 .result = REJECT, 816 .result = REJECT,
786 .prog_type = BPF_PROG_TYPE_SCHED_ACT, 817 .prog_type = BPF_PROG_TYPE_SCHED_ACT,
787 }, 818 },
@@ -803,6 +834,8 @@ static struct bpf_test tests[] = {
803 BPF_EXIT_INSN(), 834 BPF_EXIT_INSN(),
804 }, 835 },
805 .result = ACCEPT, 836 .result = ACCEPT,
837 .errstr_unpriv = "R1 leaks addr",
838 .result_unpriv = REJECT,
806 }, 839 },
807 { 840 {
808 "write skb fields from tc_cls_act prog", 841 "write skb fields from tc_cls_act prog",
@@ -819,6 +852,8 @@ static struct bpf_test tests[] = {
819 offsetof(struct __sk_buff, cb[3])), 852 offsetof(struct __sk_buff, cb[3])),
820 BPF_EXIT_INSN(), 853 BPF_EXIT_INSN(),
821 }, 854 },
855 .errstr_unpriv = "",
856 .result_unpriv = REJECT,
822 .result = ACCEPT, 857 .result = ACCEPT,
823 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 858 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
824 }, 859 },
@@ -881,6 +916,270 @@ static struct bpf_test tests[] = {
881 .result = REJECT, 916 .result = REJECT,
882 .errstr = "invalid stack off=0 size=8", 917 .errstr = "invalid stack off=0 size=8",
883 }, 918 },
919 {
920 "unpriv: return pointer",
921 .insns = {
922 BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
923 BPF_EXIT_INSN(),
924 },
925 .result = ACCEPT,
926 .result_unpriv = REJECT,
927 .errstr_unpriv = "R0 leaks addr",
928 },
929 {
930 "unpriv: add const to pointer",
931 .insns = {
932 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
933 BPF_MOV64_IMM(BPF_REG_0, 0),
934 BPF_EXIT_INSN(),
935 },
936 .result = ACCEPT,
937 .result_unpriv = REJECT,
938 .errstr_unpriv = "R1 pointer arithmetic",
939 },
940 {
941 "unpriv: add pointer to pointer",
942 .insns = {
943 BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_10),
944 BPF_MOV64_IMM(BPF_REG_0, 0),
945 BPF_EXIT_INSN(),
946 },
947 .result = ACCEPT,
948 .result_unpriv = REJECT,
949 .errstr_unpriv = "R1 pointer arithmetic",
950 },
951 {
952 "unpriv: neg pointer",
953 .insns = {
954 BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
955 BPF_MOV64_IMM(BPF_REG_0, 0),
956 BPF_EXIT_INSN(),
957 },
958 .result = ACCEPT,
959 .result_unpriv = REJECT,
960 .errstr_unpriv = "R1 pointer arithmetic",
961 },
962 {
963 "unpriv: cmp pointer with const",
964 .insns = {
965 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
966 BPF_MOV64_IMM(BPF_REG_0, 0),
967 BPF_EXIT_INSN(),
968 },
969 .result = ACCEPT,
970 .result_unpriv = REJECT,
971 .errstr_unpriv = "R1 pointer comparison",
972 },
973 {
974 "unpriv: cmp pointer with pointer",
975 .insns = {
976 BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0),
977 BPF_MOV64_IMM(BPF_REG_0, 0),
978 BPF_EXIT_INSN(),
979 },
980 .result = ACCEPT,
981 .result_unpriv = REJECT,
982 .errstr_unpriv = "R10 pointer comparison",
983 },
984 {
985 "unpriv: check that printk is disallowed",
986 .insns = {
987 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
988 BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
989 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
990 BPF_MOV64_IMM(BPF_REG_2, 8),
991 BPF_MOV64_REG(BPF_REG_3, BPF_REG_1),
992 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_trace_printk),
993 BPF_MOV64_IMM(BPF_REG_0, 0),
994 BPF_EXIT_INSN(),
995 },
996 .errstr_unpriv = "unknown func 6",
997 .result_unpriv = REJECT,
998 .result = ACCEPT,
999 },
1000 {
1001 "unpriv: pass pointer to helper function",
1002 .insns = {
1003 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
1004 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1005 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1006 BPF_LD_MAP_FD(BPF_REG_1, 0),
1007 BPF_MOV64_REG(BPF_REG_3, BPF_REG_2),
1008 BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
1009 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem),
1010 BPF_MOV64_IMM(BPF_REG_0, 0),
1011 BPF_EXIT_INSN(),
1012 },
1013 .fixup = {3},
1014 .errstr_unpriv = "R4 leaks addr",
1015 .result_unpriv = REJECT,
1016 .result = ACCEPT,
1017 },
1018 {
1019 "unpriv: indirectly pass pointer on stack to helper function",
1020 .insns = {
1021 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1022 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1023 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1024 BPF_LD_MAP_FD(BPF_REG_1, 0),
1025 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1026 BPF_MOV64_IMM(BPF_REG_0, 0),
1027 BPF_EXIT_INSN(),
1028 },
1029 .fixup = {3},
1030 .errstr = "invalid indirect read from stack off -8+0 size 8",
1031 .result = REJECT,
1032 },
1033 {
1034 "unpriv: mangle pointer on stack 1",
1035 .insns = {
1036 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1037 BPF_ST_MEM(BPF_W, BPF_REG_10, -8, 0),
1038 BPF_MOV64_IMM(BPF_REG_0, 0),
1039 BPF_EXIT_INSN(),
1040 },
1041 .errstr_unpriv = "attempt to corrupt spilled",
1042 .result_unpriv = REJECT,
1043 .result = ACCEPT,
1044 },
1045 {
1046 "unpriv: mangle pointer on stack 2",
1047 .insns = {
1048 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1049 BPF_ST_MEM(BPF_B, BPF_REG_10, -1, 0),
1050 BPF_MOV64_IMM(BPF_REG_0, 0),
1051 BPF_EXIT_INSN(),
1052 },
1053 .errstr_unpriv = "attempt to corrupt spilled",
1054 .result_unpriv = REJECT,
1055 .result = ACCEPT,
1056 },
1057 {
1058 "unpriv: read pointer from stack in small chunks",
1059 .insns = {
1060 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1061 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_10, -8),
1062 BPF_MOV64_IMM(BPF_REG_0, 0),
1063 BPF_EXIT_INSN(),
1064 },
1065 .errstr = "invalid size",
1066 .result = REJECT,
1067 },
1068 {
1069 "unpriv: write pointer into ctx",
1070 .insns = {
1071 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0),
1072 BPF_MOV64_IMM(BPF_REG_0, 0),
1073 BPF_EXIT_INSN(),
1074 },
1075 .errstr_unpriv = "R1 leaks addr",
1076 .result_unpriv = REJECT,
1077 .errstr = "invalid bpf_context access",
1078 .result = REJECT,
1079 },
1080 {
1081 "unpriv: write pointer into map elem value",
1082 .insns = {
1083 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
1084 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1085 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1086 BPF_LD_MAP_FD(BPF_REG_1, 0),
1087 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1088 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
1089 BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
1090 BPF_EXIT_INSN(),
1091 },
1092 .fixup = {3},
1093 .errstr_unpriv = "R0 leaks addr",
1094 .result_unpriv = REJECT,
1095 .result = ACCEPT,
1096 },
1097 {
1098 "unpriv: partial copy of pointer",
1099 .insns = {
1100 BPF_MOV32_REG(BPF_REG_1, BPF_REG_10),
1101 BPF_MOV64_IMM(BPF_REG_0, 0),
1102 BPF_EXIT_INSN(),
1103 },
1104 .errstr_unpriv = "R10 partial copy",
1105 .result_unpriv = REJECT,
1106 .result = ACCEPT,
1107 },
1108 {
1109 "unpriv: pass pointer to tail_call",
1110 .insns = {
1111 BPF_MOV64_REG(BPF_REG_3, BPF_REG_1),
1112 BPF_LD_MAP_FD(BPF_REG_2, 0),
1113 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call),
1114 BPF_MOV64_IMM(BPF_REG_0, 0),
1115 BPF_EXIT_INSN(),
1116 },
1117 .prog_array_fixup = {1},
1118 .errstr_unpriv = "R3 leaks addr into helper",
1119 .result_unpriv = REJECT,
1120 .result = ACCEPT,
1121 },
1122 {
1123 "unpriv: cmp map pointer with zero",
1124 .insns = {
1125 BPF_MOV64_IMM(BPF_REG_1, 0),
1126 BPF_LD_MAP_FD(BPF_REG_1, 0),
1127 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
1128 BPF_MOV64_IMM(BPF_REG_0, 0),
1129 BPF_EXIT_INSN(),
1130 },
1131 .fixup = {1},
1132 .errstr_unpriv = "R1 pointer comparison",
1133 .result_unpriv = REJECT,
1134 .result = ACCEPT,
1135 },
1136 {
1137 "unpriv: write into frame pointer",
1138 .insns = {
1139 BPF_MOV64_REG(BPF_REG_10, BPF_REG_1),
1140 BPF_MOV64_IMM(BPF_REG_0, 0),
1141 BPF_EXIT_INSN(),
1142 },
1143 .errstr = "frame pointer is read only",
1144 .result = REJECT,
1145 },
1146 {
1147 "unpriv: cmp of frame pointer",
1148 .insns = {
1149 BPF_JMP_IMM(BPF_JEQ, BPF_REG_10, 0, 0),
1150 BPF_MOV64_IMM(BPF_REG_0, 0),
1151 BPF_EXIT_INSN(),
1152 },
1153 .errstr_unpriv = "R10 pointer comparison",
1154 .result_unpriv = REJECT,
1155 .result = ACCEPT,
1156 },
1157 {
1158 "unpriv: cmp of stack pointer",
1159 .insns = {
1160 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1161 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1162 BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 0),
1163 BPF_MOV64_IMM(BPF_REG_0, 0),
1164 BPF_EXIT_INSN(),
1165 },
1166 .errstr_unpriv = "R2 pointer comparison",
1167 .result_unpriv = REJECT,
1168 .result = ACCEPT,
1169 },
1170 {
1171 "unpriv: obfuscate stack pointer",
1172 .insns = {
1173 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1174 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1175 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1176 BPF_MOV64_IMM(BPF_REG_0, 0),
1177 BPF_EXIT_INSN(),
1178 },
1179 .errstr_unpriv = "R2 pointer arithmetic",
1180 .result_unpriv = REJECT,
1181 .result = ACCEPT,
1182 },
884}; 1183};
885 1184
886static int probe_filter_length(struct bpf_insn *fp) 1185static int probe_filter_length(struct bpf_insn *fp)
@@ -896,13 +1195,24 @@ static int probe_filter_length(struct bpf_insn *fp)
896 1195
897static int create_map(void) 1196static int create_map(void)
898{ 1197{
899 long long key, value = 0;
900 int map_fd; 1198 int map_fd;
901 1199
902 map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024); 1200 map_fd = bpf_create_map(BPF_MAP_TYPE_HASH,
903 if (map_fd < 0) { 1201 sizeof(long long), sizeof(long long), 1024);
1202 if (map_fd < 0)
904 printf("failed to create map '%s'\n", strerror(errno)); 1203 printf("failed to create map '%s'\n", strerror(errno));
905 } 1204
1205 return map_fd;
1206}
1207
1208static int create_prog_array(void)
1209{
1210 int map_fd;
1211
1212 map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY,
1213 sizeof(int), sizeof(int), 4);
1214 if (map_fd < 0)
1215 printf("failed to create prog_array '%s'\n", strerror(errno));
906 1216
907 return map_fd; 1217 return map_fd;
908} 1218}
@@ -910,13 +1220,17 @@ static int create_map(void)
910static int test(void) 1220static int test(void)
911{ 1221{
912 int prog_fd, i, pass_cnt = 0, err_cnt = 0; 1222 int prog_fd, i, pass_cnt = 0, err_cnt = 0;
1223 bool unpriv = geteuid() != 0;
913 1224
914 for (i = 0; i < ARRAY_SIZE(tests); i++) { 1225 for (i = 0; i < ARRAY_SIZE(tests); i++) {
915 struct bpf_insn *prog = tests[i].insns; 1226 struct bpf_insn *prog = tests[i].insns;
916 int prog_type = tests[i].prog_type; 1227 int prog_type = tests[i].prog_type;
917 int prog_len = probe_filter_length(prog); 1228 int prog_len = probe_filter_length(prog);
918 int *fixup = tests[i].fixup; 1229 int *fixup = tests[i].fixup;
919 int map_fd = -1; 1230 int *prog_array_fixup = tests[i].prog_array_fixup;
1231 int expected_result;
1232 const char *expected_errstr;
1233 int map_fd = -1, prog_array_fd = -1;
920 1234
921 if (*fixup) { 1235 if (*fixup) {
922 map_fd = create_map(); 1236 map_fd = create_map();
@@ -926,13 +1240,31 @@ static int test(void)
926 fixup++; 1240 fixup++;
927 } while (*fixup); 1241 } while (*fixup);
928 } 1242 }
1243 if (*prog_array_fixup) {
1244 prog_array_fd = create_prog_array();
1245
1246 do {
1247 prog[*prog_array_fixup].imm = prog_array_fd;
1248 prog_array_fixup++;
1249 } while (*prog_array_fixup);
1250 }
929 printf("#%d %s ", i, tests[i].descr); 1251 printf("#%d %s ", i, tests[i].descr);
930 1252
931 prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER, 1253 prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER,
932 prog, prog_len * sizeof(struct bpf_insn), 1254 prog, prog_len * sizeof(struct bpf_insn),
933 "GPL", 0); 1255 "GPL", 0);
934 1256
935 if (tests[i].result == ACCEPT) { 1257 if (unpriv && tests[i].result_unpriv != UNDEF)
1258 expected_result = tests[i].result_unpriv;
1259 else
1260 expected_result = tests[i].result;
1261
1262 if (unpriv && tests[i].errstr_unpriv)
1263 expected_errstr = tests[i].errstr_unpriv;
1264 else
1265 expected_errstr = tests[i].errstr;
1266
1267 if (expected_result == ACCEPT) {
936 if (prog_fd < 0) { 1268 if (prog_fd < 0) {
937 printf("FAIL\nfailed to load prog '%s'\n", 1269 printf("FAIL\nfailed to load prog '%s'\n",
938 strerror(errno)); 1270 strerror(errno));
@@ -947,7 +1279,7 @@ static int test(void)
947 err_cnt++; 1279 err_cnt++;
948 goto fail; 1280 goto fail;
949 } 1281 }
950 if (strstr(bpf_log_buf, tests[i].errstr) == 0) { 1282 if (strstr(bpf_log_buf, expected_errstr) == 0) {
951 printf("FAIL\nunexpected error message: %s", 1283 printf("FAIL\nunexpected error message: %s",
952 bpf_log_buf); 1284 bpf_log_buf);
953 err_cnt++; 1285 err_cnt++;
@@ -960,6 +1292,8 @@ static int test(void)
960fail: 1292fail:
961 if (map_fd >= 0) 1293 if (map_fd >= 0)
962 close(map_fd); 1294 close(map_fd);
1295 if (prog_array_fd >= 0)
1296 close(prog_array_fd);
963 close(prog_fd); 1297 close(prog_fd);
964 1298
965 } 1299 }
@@ -970,5 +1304,8 @@ fail:
970 1304
971int main(void) 1305int main(void)
972{ 1306{
1307 struct rlimit r = {1 << 20, 1 << 20};
1308
1309 setrlimit(RLIMIT_MEMLOCK, &r);
973 return test(); 1310 return test();
974} 1311}