BPF verifier supports direct memory access for BPF_PROG_TYPE_TRACING type of bpf programs, e.g., a->b. If "a" is a pointer pointing to kernel memory, bpf verifier will allow user to write code in C like a->b and the verifier will translate it to a kernel load properly. If "a" is a pointer to user memory, it is expected that bpf developer should be bpf_probe_read_user() helper to get the value a->b. Without utilizing BTF __user tagging information, current verifier will assume that a->b is a kernel memory access and this may generate incorrect result. Now BTF contains __user information, it can check whether the pointer points to a user memory or not. If it is, the verifier can reject the program and force users to use bpf_probe_read_user() helper explicitly. In the future, we can easily extend btf_add_space for other address space tagging, for example, rcu/percpu etc.
Unified · Split
| @@ -332,7 +332,10 @@ enum bpf_type_flag { · 331 unmodified lines | |||
| 332 | */ | 332 | */ |
| 333 | MEM_ALLOC = BIT(2 + BPF_BASE_TYPE_BITS), | 333 | MEM_ALLOC = BIT(2 + BPF_BASE_TYPE_BITS), |
| 334 | 334 | ||
| 335 | __BPF_TYPE_LAST_FLAG = MEM_ALLOC, | 335 | /* MEM is in user address space. */ |
| 336 | MEM_USER = BIT(3 + BPF_BASE_TYPE_BITS), | ||
| 337 | |||
| 338 | __BPF_TYPE_LAST_FLAG = MEM_USER, | ||
| 336 | }; | 339 | }; |
| 337 | 340 | ||
| 338 | /* Max number of base types. */ | 341 | /* Max number of base types. */ |
| @@ -588,7 +591,7 @@ struct bpf_verifier_ops { · 249 unmodified lines | |||
| 588 | const struct btf *btf, | 591 | const struct btf *btf, |
| 589 | const struct btf_type *t, int off, int size, | 592 | const struct btf_type *t, int off, int size, |
| 590 | enum bpf_access_type atype, | 593 | enum bpf_access_type atype, |
| 591 | u32 *next_btf_id); | 594 | u32 *next_btf_id, enum bpf_type_flag *flag); |
| 592 | }; | 595 | }; |
| 593 | 596 | ||
| 594 | struct bpf_prog_offload_ops { | 597 | struct bpf_prog_offload_ops { |
| @@ -1780,7 +1783,7 @@ static inline bool bpf_tracing_btf_ctx_access(int off, int size, · 1185 unmodified lines | |||
| 1780 | int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, | 1783 | int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, |
| 1781 | const struct btf_type *t, int off, int size, | 1784 | const struct btf_type *t, int off, int size, |
| 1782 | enum bpf_access_type atype, | 1785 | enum bpf_access_type atype, |
| 1783 | u32 *next_btf_id); | 1786 | u32 *next_btf_id, enum bpf_type_flag *flag); |
| 1784 | bool btf_struct_ids_match(struct bpf_verifier_log *log, | 1787 | bool btf_struct_ids_match(struct bpf_verifier_log *log, |
| 1785 | const struct btf *btf, u32 id, int off, | 1788 | const struct btf *btf, u32 id, int off, |
| 1786 | const struct btf *need_btf, u32 need_type_id); | 1789 | const struct btf *need_btf, u32 need_type_id); |
| @@ -238,6 +238,11 @@ static inline bool btf_type_is_var(const struct btf_type *t) · 237 unmodified lines | |||
| 238 | return BTF_INFO_KIND(t->info) == BTF_KIND_VAR; | 238 | return BTF_INFO_KIND(t->info) == BTF_KIND_VAR; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | static inline bool btf_type_is_type_tag(const struct btf_type *t) | ||
| 242 | { | ||
| 243 | return BTF_INFO_KIND(t->info) == BTF_KIND_TYPE_TAG; | ||
| 244 | } | ||
| 245 | |||
| 241 | /* union is only a special case of struct: | 246 | /* union is only a special case of struct: |
| 242 | * all its offsetof(member) == 0 | 247 | * all its offsetof(member) == 0 |
| 243 | */ | 248 | */ |
| @@ -4886,6 +4886,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, · 4885 unmodified lines | |||
| 4886 | const char *tname = prog->aux->attach_func_name; | 4886 | const char *tname = prog->aux->attach_func_name; |
| 4887 | struct bpf_verifier_log *log = info->log; | 4887 | struct bpf_verifier_log *log = info->log; |
| 4888 | const struct btf_param *args; | 4888 | const struct btf_param *args; |
| 4889 | const char *tag_value; | ||
| 4889 | u32 nr_args, arg; | 4890 | u32 nr_args, arg; |
| 4890 | int i, ret; | 4891 | int i, ret; |
| 4891 | 4892 | ||
| @@ -5038,6 +5039,13 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, · 146 unmodified lines | |||
| 5038 | info->btf = btf; | 5039 | info->btf = btf; |
| 5039 | info->btf_id = t->type; | 5040 | info->btf_id = t->type; |
| 5040 | t = btf_type_by_id(btf, t->type); | 5041 | t = btf_type_by_id(btf, t->type); |
| 5042 | |||
| 5043 | if (btf_type_is_type_tag(t)) { | ||
| 5044 | tag_value = __btf_name_by_offset(btf, t->name_off); | ||
| 5045 | if (strcmp(tag_value, "user") == 0) | ||
| 5046 | info->reg_type |= MEM_USER; | ||
| 5047 | } | ||
| 5048 | |||
| 5041 | /* skip modifiers */ | 5049 | /* skip modifiers */ |
| 5042 | while (btf_type_is_modifier(t)) { | 5050 | while (btf_type_is_modifier(t)) { |
| 5043 | info->btf_id = t->type; | 5051 | info->btf_id = t->type; |
| @@ -5064,12 +5072,12 @@ enum bpf_struct_walk_result { · 20 unmodified lines | |||
| 5064 | 5072 | ||
| 5065 | static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf, | 5073 | static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf, |
| 5066 | const struct btf_type *t, int off, int size, | 5074 | const struct btf_type *t, int off, int size, |
| 5067 | u32 *next_btf_id) | 5075 | u32 *next_btf_id, enum bpf_type_flag *flag) |
| 5068 | { | 5076 | { |
| 5069 | u32 i, moff, mtrue_end, msize = 0, total_nelems = 0; | 5077 | u32 i, moff, mtrue_end, msize = 0, total_nelems = 0; |
| 5070 | const struct btf_type *mtype, *elem_type = NULL; | 5078 | const struct btf_type *mtype, *elem_type = NULL; |
| 5071 | const struct btf_member *member; | 5079 | const struct btf_member *member; |
| 5072 | const char *tname, *mname; | 5080 | const char *tname, *mname, *tag_value; |
| 5073 | u32 vlen, elem_id, mid; | 5081 | u32 vlen, elem_id, mid; |
| 5074 | 5082 | ||
| 5075 | again: | 5083 | again: |
| @@ -5253,7 +5261,8 @@ error: · 177 unmodified lines | |||
| 5253 | } | 5261 | } |
| 5254 | 5262 | ||
| 5255 | if (btf_type_is_ptr(mtype)) { | 5263 | if (btf_type_is_ptr(mtype)) { |
| 5256 | const struct btf_type *stype; | 5264 | const struct btf_type *stype, *t; |
| 5265 | enum bpf_type_flag tmp_flag = 0; | ||
| 5257 | u32 id; | 5266 | u32 id; |
| 5258 | 5267 | ||
| 5259 | if (msize != size || off != moff) { | 5268 | if (msize != size || off != moff) { |
| @@ -5262,9 +5271,19 @@ error: · 2 unmodified lines | |||
| 5262 | mname, moff, tname, off, size); | 5271 | mname, moff, tname, off, size); |
| 5263 | return -EACCES; | 5272 | return -EACCES; |
| 5264 | } | 5273 | } |
| 5274 | |||
| 5275 | /* check __user tag */ | ||
| 5276 | t = btf_type_by_id(btf, mtype->type); | ||
| 5277 | if (btf_type_is_type_tag(t)) { | ||
| 5278 | tag_value = __btf_name_by_offset(btf, t->name_off); | ||
| 5279 | if (strcmp(tag_value, "user") == 0) | ||
| 5280 | tmp_flag = MEM_USER; | ||
| 5281 | } | ||
| 5282 | |||
| 5265 | stype = btf_type_skip_modifiers(btf, mtype->type, &id); | 5283 | stype = btf_type_skip_modifiers(btf, mtype->type, &id); |
| 5266 | if (btf_type_is_struct(stype)) { | 5284 | if (btf_type_is_struct(stype)) { |
| 5267 | *next_btf_id = id; | 5285 | *next_btf_id = id; |
| 5286 | *flag = tmp_flag; | ||
| 5268 | return WALK_PTR; | 5287 | return WALK_PTR; |
| 5269 | } | 5288 | } |
| 5270 | } | 5289 | } |
| @@ -5291,13 +5310,14 @@ error: · 20 unmodified lines | |||
| 5291 | int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, | 5310 | int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, |
| 5292 | const struct btf_type *t, int off, int size, | 5311 | const struct btf_type *t, int off, int size, |
| 5293 | enum bpf_access_type atype __maybe_unused, | 5312 | enum bpf_access_type atype __maybe_unused, |
| 5294 | u32 *next_btf_id) | 5313 | u32 *next_btf_id, enum bpf_type_flag *flag) |
| 5295 | { | 5314 | { |
| 5315 | enum bpf_type_flag tmp_flag = 0; | ||
| 5296 | int err; | 5316 | int err; |
| 5297 | u32 id; | 5317 | u32 id; |
| 5298 | 5318 | ||
| 5299 | do { | 5319 | do { |
| 5300 | err = btf_struct_walk(log, btf, t, off, size, &id); | 5320 | err = btf_struct_walk(log, btf, t, off, size, &id, &tmp_flag); |
| 5301 | 5321 | ||
| 5302 | switch (err) { | 5322 | switch (err) { |
| 5303 | case WALK_PTR: | 5323 | case WALK_PTR: |
| @@ -5305,6 +5325,7 @@ int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, · 1 unmodified line | |||
| 5305 | * we're done. | 5325 | * we're done. |
| 5306 | */ | 5326 | */ |
| 5307 | *next_btf_id = id; | 5327 | *next_btf_id = id; |
| 5328 | *flag = tmp_flag; | ||
| 5308 | return PTR_TO_BTF_ID; | 5329 | return PTR_TO_BTF_ID; |
| 5309 | case WALK_SCALAR: | 5330 | case WALK_SCALAR: |
| 5310 | return SCALAR_VALUE; | 5331 | return SCALAR_VALUE; |
| @@ -5349,6 +5370,7 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log, · 38 unmodified lines | |||
| 5349 | const struct btf *need_btf, u32 need_type_id) | 5370 | const struct btf *need_btf, u32 need_type_id) |
| 5350 | { | 5371 | { |
| 5351 | const struct btf_type *type; | 5372 | const struct btf_type *type; |
| 5373 | enum bpf_type_flag flag; | ||
| 5352 | int err; | 5374 | int err; |
| 5353 | 5375 | ||
| 5354 | /* Are we already done? */ | 5376 | /* Are we already done? */ |
| @@ -5359,7 +5381,7 @@ again: · 4 unmodified lines | |||
| 5359 | type = btf_type_by_id(btf, id); | 5381 | type = btf_type_by_id(btf, id); |
| 5360 | if (!type) | 5382 | if (!type) |
| 5361 | return false; | 5383 | return false; |
| 5362 | err = btf_struct_walk(log, btf, type, off, 1, &id); | 5384 | err = btf_struct_walk(log, btf, type, off, 1, &id, &flag); |
| 5363 | if (err != WALK_STRUCT) | 5385 | if (err != WALK_STRUCT) |
| 5364 | return false; | 5386 | return false; |
| 5365 | 5387 | ||
| @@ -536,7 +536,7 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn) · 535 unmodified lines | |||
| 536 | static const char *reg_type_str(struct bpf_verifier_env *env, | 536 | static const char *reg_type_str(struct bpf_verifier_env *env, |
| 537 | enum bpf_reg_type type) | 537 | enum bpf_reg_type type) |
| 538 | { | 538 | { |
| 539 | char postfix[16] = {0}, prefix[16] = {0}; | 539 | char postfix[16] = {0}, prefix[32] = {0}; |
| 540 | static const char * const str[] = { | 540 | static const char * const str[] = { |
| 541 | [NOT_INIT] = "?", | 541 | [NOT_INIT] = "?", |
| 542 | [SCALAR_VALUE] = "inv", | 542 | [SCALAR_VALUE] = "inv", |
| @@ -570,9 +570,11 @@ static const char *reg_type_str(struct bpf_verifier_env *env, · 27 unmodified lines | |||
| 570 | } | 570 | } |
| 571 | 571 | ||
| 572 | if (type & MEM_RDONLY) | 572 | if (type & MEM_RDONLY) |
| 573 | strncpy(prefix, "rdonly_", 16); | 573 | strncpy(prefix, "rdonly_", 32); |
| 574 | if (type & MEM_ALLOC) | 574 | if (type & MEM_ALLOC) |
| 575 | strncpy(prefix, "alloc_", 16); | 575 | strncpy(prefix, "alloc_", 32); |
| 576 | if (type & MEM_USER) | ||
| 577 | strncpy(prefix, "user_", 32); | ||
| 576 | 578 | ||
| 577 | snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s", | 579 | snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s", |
| 578 | prefix, str[base_type(type)], postfix); | 580 | prefix, str[base_type(type)], postfix); |
| @@ -1547,14 +1549,15 @@ static void mark_reg_not_init(struct bpf_verifier_env *env, · 968 unmodified lines | |||
| 1547 | static void mark_btf_ld_reg(struct bpf_verifier_env *env, | 1549 | static void mark_btf_ld_reg(struct bpf_verifier_env *env, |
| 1548 | struct bpf_reg_state *regs, u32 regno, | 1550 | struct bpf_reg_state *regs, u32 regno, |
| 1549 | enum bpf_reg_type reg_type, | 1551 | enum bpf_reg_type reg_type, |
| 1550 | struct btf *btf, u32 btf_id) | 1552 | struct btf *btf, u32 btf_id, |
| 1553 | enum bpf_type_flag flag) | ||
| 1551 | { | 1554 | { |
| 1552 | if (reg_type == SCALAR_VALUE) { | 1555 | if (reg_type == SCALAR_VALUE) { |
| 1553 | mark_reg_unknown(env, regs, regno); | 1556 | mark_reg_unknown(env, regs, regno); |
| 1554 | return; | 1557 | return; |
| 1555 | } | 1558 | } |
| 1556 | mark_reg_known_zero(env, regs, regno); | 1559 | mark_reg_known_zero(env, regs, regno); |
| 1557 | regs[regno].type = PTR_TO_BTF_ID; | 1560 | regs[regno].type = PTR_TO_BTF_ID | flag; |
| 1558 | regs[regno].btf = btf; | 1561 | regs[regno].btf = btf; |
| 1559 | regs[regno].btf_id = btf_id; | 1562 | regs[regno].btf_id = btf_id; |
| 1560 | } | 1563 | } |
| @@ -4152,6 +4155,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, · 2591 unmodified lines | |||
| 4152 | struct bpf_reg_state *reg = regs + regno; | 4155 | struct bpf_reg_state *reg = regs + regno; |
| 4153 | const struct btf_type *t = btf_type_by_id(reg->btf, reg->btf_id); | 4156 | const struct btf_type *t = btf_type_by_id(reg->btf, reg->btf_id); |
| 4154 | const char *tname = btf_name_by_offset(reg->btf, t->name_off); | 4157 | const char *tname = btf_name_by_offset(reg->btf, t->name_off); |
| 4158 | enum bpf_type_flag flag = 0; | ||
| 4155 | u32 btf_id; | 4159 | u32 btf_id; |
| 4156 | int ret; | 4160 | int ret; |
| 4157 | 4161 | ||
| @@ -4171,9 +4175,16 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, · 13 unmodified lines | |||
| 4171 | return -EACCES; | 4175 | return -EACCES; |
| 4172 | } | 4176 | } |
| 4173 | 4177 | ||
| 4178 | if (reg->type & MEM_USER) { | ||
| 4179 | verbose(env, | ||
| 4180 | "R%d is ptr_%s access user memory: off=%d\n", | ||
| 4181 | regno, tname, off); | ||
| 4182 | return -EACCES; | ||
| 4183 | } | ||
| 4184 | |||
| 4174 | if (env->ops->btf_struct_access) { | 4185 | if (env->ops->btf_struct_access) { |
| 4175 | ret = env->ops->btf_struct_access(&env->log, reg->btf, t, | 4186 | ret = env->ops->btf_struct_access(&env->log, reg->btf, t, |
| 4176 | off, size, atype, &btf_id); | 4187 | off, size, atype, &btf_id, &flag); |
| 4177 | } else { | 4188 | } else { |
| 4178 | if (atype != BPF_READ) { | 4189 | if (atype != BPF_READ) { |
| 4179 | verbose(env, "only read is supported\n"); | 4190 | verbose(env, "only read is supported\n"); |
| @@ -4181,14 +4192,14 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, · 1 unmodified line | |||
| 4181 | } | 4192 | } |
| 4182 | 4193 | ||
| 4183 | ret = btf_struct_access(&env->log, reg->btf, t, off, size, | 4194 | ret = btf_struct_access(&env->log, reg->btf, t, off, size, |
| 4184 | atype, &btf_id); | 4195 | atype, &btf_id, &flag); |
| 4185 | } | 4196 | } |
| 4186 | 4197 | ||
| 4187 | if (ret < 0) | 4198 | if (ret < 0) |
| 4188 | return ret; | 4199 | return ret; |
| 4189 | 4200 | ||
| 4190 | if (atype == BPF_READ && value_regno >= 0) | 4201 | if (atype == BPF_READ && value_regno >= 0) |
| 4191 | mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id); | 4202 | mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag); |
| 4192 | 4203 | ||
| 4193 | return 0; | 4204 | return 0; |
| 4194 | } | 4205 | } |
| @@ -4201,6 +4212,7 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env, · 6 unmodified lines | |||
| 4201 | { | 4212 | { |
| 4202 | struct bpf_reg_state *reg = regs + regno; | 4213 | struct bpf_reg_state *reg = regs + regno; |
| 4203 | struct bpf_map *map = reg->map_ptr; | 4214 | struct bpf_map *map = reg->map_ptr; |
| 4215 | enum bpf_type_flag flag = 0; | ||
| 4204 | const struct btf_type *t; | 4216 | const struct btf_type *t; |
| 4205 | const char *tname; | 4217 | const char *tname; |
| 4206 | u32 btf_id; | 4218 | u32 btf_id; |
| @@ -4238,12 +4250,12 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env, · 31 unmodified lines | |||
| 4238 | return -EACCES; | 4250 | return -EACCES; |
| 4239 | } | 4251 | } |
| 4240 | 4252 | ||
| 4241 | ret = btf_struct_access(&env->log, btf_vmlinux, t, off, size, atype, &btf_id); | 4253 | ret = btf_struct_access(&env->log, btf_vmlinux, t, off, size, atype, &btf_id, &flag); |
| 4242 | if (ret < 0) | 4254 | if (ret < 0) |
| 4243 | return ret; | 4255 | return ret; |
| 4244 | 4256 | ||
| 4245 | if (value_regno >= 0) | 4257 | if (value_regno >= 0) |
| 4246 | mark_btf_ld_reg(env, regs, value_regno, ret, btf_vmlinux, btf_id); | 4258 | mark_btf_ld_reg(env, regs, value_regno, ret, btf_vmlinux, btf_id, flag); |
| 4247 | 4259 | ||
| 4248 | return 0; | 4260 | return 0; |
| 4249 | } | 4261 | } |
| @@ -4444,7 +4456,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn · 194 unmodified lines | |||
| 4444 | if (err < 0) | 4456 | if (err < 0) |
| 4445 | return err; | 4457 | return err; |
| 4446 | 4458 | ||
| 4447 | err = check_ctx_access(env, insn_idx, off, size, t, ®_type, &btf, &btf_id); | 4459 | err = check_ctx_access(env, insn_idx, off, size, t, ®_type, &btf, |
| 4460 | &btf_id); | ||
| 4448 | if (err) | 4461 | if (err) |
| 4449 | verbose_linfo(env, insn_idx, "; "); | 4462 | verbose_linfo(env, insn_idx, "; "); |
| 4450 | if (!err && t == BPF_READ && value_regno >= 0) { | 4463 | if (!err && t == BPF_READ && value_regno >= 0) { |
| @@ -145,7 +145,8 @@ static int bpf_dummy_ops_btf_struct_access(struct bpf_verifier_log *log, · 144 unmodified lines | |||
| 145 | const struct btf *btf, | 145 | const struct btf *btf, |
| 146 | const struct btf_type *t, int off, | 146 | const struct btf_type *t, int off, |
| 147 | int size, enum bpf_access_type atype, | 147 | int size, enum bpf_access_type atype, |
| 148 | u32 *next_btf_id) | 148 | u32 *next_btf_id, |
| 149 | enum bpf_type_flag *flag) | ||
| 149 | { | 150 | { |
| 150 | const struct btf_type *state; | 151 | const struct btf_type *state; |
| 151 | s32 type_id; | 152 | s32 type_id; |
| @@ -162,7 +163,8 @@ static int bpf_dummy_ops_btf_struct_access(struct bpf_verifier_log *log, · 10 unmodified lines | |||
| 162 | return -EACCES; | 163 | return -EACCES; |
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | err = btf_struct_access(log, btf, t, off, size, atype, next_btf_id); | 166 | err = btf_struct_access(log, btf, t, off, size, atype, next_btf_id, |
| 167 | flag); | ||
| 166 | if (err < 0) | 168 | if (err < 0) |
| 167 | return err; | 169 | return err; |
| 168 | 170 | ||
| @@ -96,12 +96,14 @@ static int bpf_tcp_ca_btf_struct_access(struct bpf_verifier_log *log, · 95 unmodified lines | |||
| 96 | const struct btf *btf, | 96 | const struct btf *btf, |
| 97 | const struct btf_type *t, int off, | 97 | const struct btf_type *t, int off, |
| 98 | int size, enum bpf_access_type atype, | 98 | int size, enum bpf_access_type atype, |
| 99 | u32 *next_btf_id) | 99 | u32 *next_btf_id, |
| 100 | enum bpf_type_flag *flag) | ||
| 100 | { | 101 | { |
| 101 | size_t end; | 102 | size_t end; |
| 102 | 103 | ||
| 103 | if (atype == BPF_READ) | 104 | if (atype == BPF_READ) |
| 104 | return btf_struct_access(log, btf, t, off, size, atype, next_btf_id); | 105 | return btf_struct_access(log, btf, t, off, size, atype, next_btf_id, |
| 106 | flag); | ||
| 105 | 107 | ||
| 106 | if (t != tcp_sock_type) { | 108 | if (t != tcp_sock_type) { |
| 107 | bpf_log(log, "only read is supported\n"); | 109 | bpf_log(log, "only read is supported\n"); |