| 1 | #include "bpf_experimental.h"
|
| 2 | #include "bpf_misc.h"
|
| 3 |
|
| 4 | struct val_t {
|
| 5 | long b, c, d;
|
| 6 | };
|
| 7 |
|
| 8 | struct val2_t {
|
| 9 | long b;
|
| 10 | };
|
| 11 |
|
| 12 | struct val_with_ptr_t {
|
| 13 | char *p;
|
| 14 | };
|
| 15 |
|
| 16 | struct val_with_rb_root_t {
|
| 17 | struct bpf_spin_lock lock;
|
| 18 | };
|
| 19 |
|
| 20 | struct val_600b_t {
|
| 21 | char b[600];
|
| 22 | };
|
| 23 |
|
| 24 | struct elem {
|
| 25 | long sum;
|
| 26 | struct val_t __percpu_kptr *pc;
|
| 27 | };
|
| 28 |
|
| 29 | struct {
|
| 30 | __uint(type, BPF_MAP_TYPE_ARRAY);
|
| 31 | __uint(max_entries, 1);
|
| 32 | __type(key, int);
|
| 33 | __type(value, struct elem);
|
| 34 | } array SEC(".maps");
|
| 35 |
|
| 36 | struct kernel_percpu_elem {
|
| 37 | struct task_struct __percpu_kptr *task;
|
| 38 | };
|
| 39 |
|
| 40 | struct {
|
| 41 | __uint(type, BPF_MAP_TYPE_ARRAY);
|
| 42 | __uint(max_entries, 1);
|
| 43 | __type(key, int);
|
| 44 | __type(value, struct kernel_percpu_elem);
|
| 45 | } kernel_percpu_array SEC(".maps");
|
| 46 |
|
| 47 | struct task_struct *bpf_task_from_pid(s32 pid) __ksym;
|
| 48 | void bpf_task_release(struct task_struct *p) __ksym;
|
| 49 |
|
| 50 | long ret;
|
| 51 |
|
| 52 | SEC("?fentry/bpf_fentry_test1")
|
| 53 | __failure __msg("store to referenced kptr disallowed")
|
| 54 | int BPF_PROG(test_array_map_1)
|
| 55 | {
|
| 56 | struct val_t __percpu_kptr *p;
|
| 57 | struct elem *e;
|
| 58 | int index = 0;
|
| 59 |
|
| 60 | e = bpf_map_lookup_elem(&array, &index);
|
| 61 | if (!e)
|
| 62 | return 0;
|
| 63 |
|
| 64 | p = bpf_percpu_obj_new(struct val_t);
|
| 65 | if (!p)
|
| 66 | return 0;
|
| 67 |
|
| 68 | p = bpf_kptr_xchg(&e->pc, p);
|
| 69 | if (p)
|
| 70 | bpf_percpu_obj_drop(p);
|
| 71 |
|
| 72 | e->pc = (struct val_t __percpu_kptr *)ret;
|
| 73 | return 0;
|
| 74 | }
|
| 75 |
|
| 76 | SEC("?fentry/bpf_fentry_test1")
|
| 77 | __failure __msg("invalid kptr access, R2 type=percpu_ptr_val2_t expected=ptr_val_t")
|
| 78 | int BPF_PROG(test_array_map_2)
|
| 79 | {
|
| 80 | struct val2_t __percpu_kptr *p2;
|
| 81 | struct val_t __percpu_kptr *p;
|
| 82 | struct elem *e;
|
| 83 | int index = 0;
|
| 84 |
|
| 85 | e = bpf_map_lookup_elem(&array, &index);
|
| 86 | if (!e)
|
| 87 | return 0;
|
| 88 |
|
| 89 | p2 = bpf_percpu_obj_new(struct val2_t);
|
| 90 | if (!p2)
|
| 91 | return 0;
|
| 92 |
|
| 93 | p = bpf_kptr_xchg(&e->pc, p2);
|
| 94 | if (p)
|
| 95 | bpf_percpu_obj_drop(p);
|
| 96 |
|
| 97 | return 0;
|
| 98 | }
|
| 99 |
|
| 100 | SEC("?fentry.s/bpf_fentry_test1")
|
| 101 | __failure __msg("R1 type=scalar expected=percpu_ptr_, percpu_rcu_ptr_, percpu_trusted_ptr_")
|
| 102 | int BPF_PROG(test_array_map_3)
|
| 103 | {
|
| 104 | struct val_t __percpu_kptr *p, *p1;
|
| 105 | struct val_t *v;
|
| 106 | struct elem *e;
|
| 107 | int index = 0;
|
| 108 |
|
| 109 | e = bpf_map_lookup_elem(&array, &index);
|
| 110 | if (!e)
|
| 111 | return 0;
|
| 112 |
|
| 113 | p = bpf_percpu_obj_new(struct val_t);
|
| 114 | if (!p)
|
| 115 | return 0;
|
| 116 |
|
| 117 | p1 = bpf_kptr_xchg(&e->pc, p);
|
| 118 | if (p1)
|
| 119 | bpf_percpu_obj_drop(p1);
|
| 120 |
|
| 121 | v = bpf_this_cpu_ptr(p);
|
| 122 | ret = v->b;
|
| 123 | return 0;
|
| 124 | }
|
| 125 |
|
| 126 | SEC("?fentry.s/bpf_fentry_test1")
|
| 127 | __failure __msg("R1 expected for bpf_percpu_obj_drop()")
|
| 128 | int BPF_PROG(test_array_map_4)
|
| 129 | {
|
| 130 | struct val_t __percpu_kptr *p;
|
| 131 |
|
| 132 | p = bpf_percpu_obj_new(struct val_t);
|
| 133 | if (!p)
|
| 134 | return 0;
|
| 135 |
|
| 136 | bpf_obj_drop(p);
|
| 137 | return 0;
|
| 138 | }
|
| 139 |
|
| 140 | SEC("?fentry.s/bpf_fentry_test1")
|
| 141 | __failure __msg("R1 expected for bpf_obj_drop()")
|
| 142 | int BPF_PROG(test_array_map_5)
|
| 143 | {
|
| 144 | struct val_t *p;
|
| 145 |
|
| 146 | p = bpf_obj_new(struct val_t);
|
| 147 | if (!p)
|
| 148 | return 0;
|
| 149 |
|
| 150 | bpf_percpu_obj_drop(p);
|
| 151 | return 0;
|
| 152 | }
|
| 153 |
|
| 154 | SEC("?syscall")
|
| 155 | __failure __msg("invalid kptr access, R2 type=trusted_ptr_ expected=ptr_task_struct")
|
| 156 | int reject_kernel_ptr_into_percpu_kptr(void *ctx)
|
| 157 | {
|
| 158 | struct kernel_percpu_elem *e;
|
| 159 | struct task_struct *p, *old;
|
| 160 | int index = 0;
|
| 161 |
|
| 162 | e = bpf_map_lookup_elem(&kernel_percpu_array, &index);
|
| 163 | if (!e)
|
| 164 | return 0;
|
| 165 |
|
| 166 | p = bpf_task_from_pid(1);
|
| 167 | if (!p)
|
| 168 | return 0;
|
| 169 |
|
| 170 | old = bpf_kptr_xchg(&e->task, p);
|
| 171 | if (old)
|
| 172 | bpf_task_release(old);
|
| 173 | return 0;
|
| 174 | }
|
| 175 |
|
| 176 | SEC("?fentry.s/bpf_fentry_test1")
|
| 177 | __failure __msg("invalid kptr access, R2 type=ptr_ expected=ptr_val_t")
|
| 178 | int BPF_PROG(reject_plain_alloc_into_percpu_kptr)
|
| 179 | {
|
| 180 | struct val_t __percpu_kptr *old;
|
| 181 | struct val_t *p;
|
| 182 | struct elem *e;
|
| 183 | int index = 0;
|
| 184 |
|
| 185 | e = bpf_map_lookup_elem(&array, &index);
|
| 186 | if (!e)
|
| 187 | return 0;
|
| 188 |
|
| 189 | p = bpf_obj_new(struct val_t);
|
| 190 | if (!p)
|
| 191 | return 0;
|
| 192 |
|
| 193 | old = bpf_kptr_xchg(&e->pc, p);
|
| 194 | if (old)
|
| 195 | bpf_percpu_obj_drop(old);
|
| 196 | return 0;
|
| 197 | }
|
| 198 |
|
| 199 | SEC("?fentry.s/bpf_fentry_test1")
|
| 200 | __failure __msg("bpf_percpu_obj_new type ID argument must be of a struct of scalars")
|
| 201 | int BPF_PROG(test_array_map_6)
|
| 202 | {
|
| 203 | struct val_with_ptr_t __percpu_kptr *p;
|
| 204 |
|
| 205 | p = bpf_percpu_obj_new(struct val_with_ptr_t);
|
| 206 | if (!p)
|
| 207 | return 0;
|
| 208 |
|
| 209 | bpf_percpu_obj_drop(p);
|
| 210 | return 0;
|
| 211 | }
|
| 212 |
|
| 213 | SEC("?fentry.s/bpf_fentry_test1")
|
| 214 | __failure __msg("bpf_percpu_obj_new type ID argument must not contain special fields")
|
| 215 | int BPF_PROG(test_array_map_7)
|
| 216 | {
|
| 217 | struct val_with_rb_root_t __percpu_kptr *p;
|
| 218 |
|
| 219 | p = bpf_percpu_obj_new(struct val_with_rb_root_t);
|
| 220 | if (!p)
|
| 221 | return 0;
|
| 222 |
|
| 223 | bpf_percpu_obj_drop(p);
|
| 224 | return 0;
|
| 225 | }
|
| 226 |
|
| 227 | SEC("?fentry.s/bpf_fentry_test1")
|
| 228 | __failure __msg("bpf_percpu_obj_new type size (600) is greater than 512")
|
| 229 | int BPF_PROG(test_array_map_8)
|
| 230 | {
|
| 231 | struct val_600b_t __percpu_kptr *p;
|
| 232 |
|
| 233 | p = bpf_percpu_obj_new(struct val_600b_t);
|
| 234 | if (!p)
|
| 235 | return 0;
|
| 236 |
|
| 237 | bpf_percpu_obj_drop(p);
|
| 238 | return 0;
|
| 239 | }
|
| 240 |
|
| 241 | char _license[] SEC("license") = "GPL";
|