Skip to content

Commit 4349efc

Browse files
committed
Daniel Borkmann says: ==================== pull-request: bpf 2024-01-18 We've added 10 non-merge commits during the last 5 day(s) which contain a total of 12 files changed, 806 insertions(+), 51 deletions(-). The main changes are: 1) Fix an issue in bpf_iter_udp under backward progress which prevents user space process from finishing iteration, from Martin KaFai Lau. 2) Fix BPF verifier to reject variable offset alu on registers with a type of PTR_TO_FLOW_KEYS to prevent oob access, from Hao Sun. 3) Follow up fixes for kernel- and libbpf-side logic around handling arg:ctx tagged arguments of BPF global subprogs, from Andrii Nakryiko. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: libbpf: warn on unexpected __arg_ctx type when rewriting BTF selftests/bpf: add tests confirming type logic in kernel for __arg_ctx bpf: enforce types for __arg_ctx-tagged arguments in global subprogs bpf: extract bpf_ctx_convert_map logic and make it more reusable libbpf: feature-detect arg:ctx tag support in kernel selftests/bpf: Add test for alu on PTR_TO_FLOW_KEYS bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS selftests/bpf: Test udp and tcp iter batching bpf: Avoid iter->offset making backward progress in bpf_iter_udp bpf: iter_udp: Retry with a larger batch size without going back to the previous bucket ==================== Link: https://lore.kernel.org/r/20240118153936.11769-1-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 9cfd3b5 + 35ac085 commit 4349efc

File tree

12 files changed

+806
-51
lines changed

12 files changed

+806
-51
lines changed

include/linux/btf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
512512
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
513513
struct module *owner);
514514
struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf, u32 btf_id);
515-
const struct btf_member *
515+
const struct btf_type *
516516
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
517517
const struct btf_type *t, enum bpf_prog_type prog_type,
518518
int arg);

kernel/bpf/btf.c

Lines changed: 205 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5615,21 +5615,46 @@ static u8 bpf_ctx_convert_map[] = {
56155615
#undef BPF_MAP_TYPE
56165616
#undef BPF_LINK_TYPE
56175617

5618-
const struct btf_member *
5619-
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
5620-
const struct btf_type *t, enum bpf_prog_type prog_type,
5621-
int arg)
5618+
static const struct btf_type *find_canonical_prog_ctx_type(enum bpf_prog_type prog_type)
56225619
{
56235620
const struct btf_type *conv_struct;
5624-
const struct btf_type *ctx_struct;
56255621
const struct btf_member *ctx_type;
5626-
const char *tname, *ctx_tname;
56275622

56285623
conv_struct = bpf_ctx_convert.t;
5629-
if (!conv_struct) {
5630-
bpf_log(log, "btf_vmlinux is malformed\n");
5624+
if (!conv_struct)
56315625
return NULL;
5632-
}
5626+
/* prog_type is valid bpf program type. No need for bounds check. */
5627+
ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2;
5628+
/* ctx_type is a pointer to prog_ctx_type in vmlinux.
5629+
* Like 'struct __sk_buff'
5630+
*/
5631+
return btf_type_by_id(btf_vmlinux, ctx_type->type);
5632+
}
5633+
5634+
static int find_kern_ctx_type_id(enum bpf_prog_type prog_type)
5635+
{
5636+
const struct btf_type *conv_struct;
5637+
const struct btf_member *ctx_type;
5638+
5639+
conv_struct = bpf_ctx_convert.t;
5640+
if (!conv_struct)
5641+
return -EFAULT;
5642+
/* prog_type is valid bpf program type. No need for bounds check. */
5643+
ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2 + 1;
5644+
/* ctx_type is a pointer to prog_ctx_type in vmlinux.
5645+
* Like 'struct sk_buff'
5646+
*/
5647+
return ctx_type->type;
5648+
}
5649+
5650+
const struct btf_type *
5651+
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
5652+
const struct btf_type *t, enum bpf_prog_type prog_type,
5653+
int arg)
5654+
{
5655+
const struct btf_type *ctx_type;
5656+
const char *tname, *ctx_tname;
5657+
56335658
t = btf_type_by_id(btf, t->type);
56345659
while (btf_type_is_modifier(t))
56355660
t = btf_type_by_id(btf, t->type);
@@ -5646,17 +5671,15 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
56465671
bpf_log(log, "arg#%d struct doesn't have a name\n", arg);
56475672
return NULL;
56485673
}
5649-
/* prog_type is valid bpf program type. No need for bounds check. */
5650-
ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2;
5651-
/* ctx_struct is a pointer to prog_ctx_type in vmlinux.
5652-
* Like 'struct __sk_buff'
5653-
*/
5654-
ctx_struct = btf_type_by_id(btf_vmlinux, ctx_type->type);
5655-
if (!ctx_struct)
5674+
5675+
ctx_type = find_canonical_prog_ctx_type(prog_type);
5676+
if (!ctx_type) {
5677+
bpf_log(log, "btf_vmlinux is malformed\n");
56565678
/* should not happen */
56575679
return NULL;
5680+
}
56585681
again:
5659-
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_struct->name_off);
5682+
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off);
56605683
if (!ctx_tname) {
56615684
/* should not happen */
56625685
bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n");
@@ -5677,28 +5700,167 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
56775700
/* bpf_user_pt_regs_t is a typedef, so resolve it to
56785701
* underlying struct and check name again
56795702
*/
5680-
if (!btf_type_is_modifier(ctx_struct))
5703+
if (!btf_type_is_modifier(ctx_type))
56815704
return NULL;
5682-
while (btf_type_is_modifier(ctx_struct))
5683-
ctx_struct = btf_type_by_id(btf_vmlinux, ctx_struct->type);
5705+
while (btf_type_is_modifier(ctx_type))
5706+
ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type);
56845707
goto again;
56855708
}
56865709
return ctx_type;
56875710
}
56885711

5712+
/* forward declarations for arch-specific underlying types of
5713+
* bpf_user_pt_regs_t; this avoids the need for arch-specific #ifdef
5714+
* compilation guards below for BPF_PROG_TYPE_PERF_EVENT checks, but still
5715+
* works correctly with __builtin_types_compatible_p() on respective
5716+
* architectures
5717+
*/
5718+
struct user_regs_struct;
5719+
struct user_pt_regs;
5720+
5721+
static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
5722+
const struct btf_type *t, int arg,
5723+
enum bpf_prog_type prog_type,
5724+
enum bpf_attach_type attach_type)
5725+
{
5726+
const struct btf_type *ctx_type;
5727+
const char *tname, *ctx_tname;
5728+
5729+
if (!btf_is_ptr(t)) {
5730+
bpf_log(log, "arg#%d type isn't a pointer\n", arg);
5731+
return -EINVAL;
5732+
}
5733+
t = btf_type_by_id(btf, t->type);
5734+
5735+
/* KPROBE and PERF_EVENT programs allow bpf_user_pt_regs_t typedef */
5736+
if (prog_type == BPF_PROG_TYPE_KPROBE || prog_type == BPF_PROG_TYPE_PERF_EVENT) {
5737+
while (btf_type_is_modifier(t) && !btf_type_is_typedef(t))
5738+
t = btf_type_by_id(btf, t->type);
5739+
5740+
if (btf_type_is_typedef(t)) {
5741+
tname = btf_name_by_offset(btf, t->name_off);
5742+
if (tname && strcmp(tname, "bpf_user_pt_regs_t") == 0)
5743+
return 0;
5744+
}
5745+
}
5746+
5747+
/* all other program types don't use typedefs for context type */
5748+
while (btf_type_is_modifier(t))
5749+
t = btf_type_by_id(btf, t->type);
5750+
5751+
/* `void *ctx __arg_ctx` is always valid */
5752+
if (btf_type_is_void(t))
5753+
return 0;
5754+
5755+
tname = btf_name_by_offset(btf, t->name_off);
5756+
if (str_is_empty(tname)) {
5757+
bpf_log(log, "arg#%d type doesn't have a name\n", arg);
5758+
return -EINVAL;
5759+
}
5760+
5761+
/* special cases */
5762+
switch (prog_type) {
5763+
case BPF_PROG_TYPE_KPROBE:
5764+
if (__btf_type_is_struct(t) && strcmp(tname, "pt_regs") == 0)
5765+
return 0;
5766+
break;
5767+
case BPF_PROG_TYPE_PERF_EVENT:
5768+
if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct pt_regs) &&
5769+
__btf_type_is_struct(t) && strcmp(tname, "pt_regs") == 0)
5770+
return 0;
5771+
if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_pt_regs) &&
5772+
__btf_type_is_struct(t) && strcmp(tname, "user_pt_regs") == 0)
5773+
return 0;
5774+
if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_regs_struct) &&
5775+
__btf_type_is_struct(t) && strcmp(tname, "user_regs_struct") == 0)
5776+
return 0;
5777+
break;
5778+
case BPF_PROG_TYPE_RAW_TRACEPOINT:
5779+
case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
5780+
/* allow u64* as ctx */
5781+
if (btf_is_int(t) && t->size == 8)
5782+
return 0;
5783+
break;
5784+
case BPF_PROG_TYPE_TRACING:
5785+
switch (attach_type) {
5786+
case BPF_TRACE_RAW_TP:
5787+
/* tp_btf program is TRACING, so need special case here */
5788+
if (__btf_type_is_struct(t) &&
5789+
strcmp(tname, "bpf_raw_tracepoint_args") == 0)
5790+
return 0;
5791+
/* allow u64* as ctx */
5792+
if (btf_is_int(t) && t->size == 8)
5793+
return 0;
5794+
break;
5795+
case BPF_TRACE_ITER:
5796+
/* allow struct bpf_iter__xxx types only */
5797+
if (__btf_type_is_struct(t) &&
5798+
strncmp(tname, "bpf_iter__", sizeof("bpf_iter__") - 1) == 0)
5799+
return 0;
5800+
break;
5801+
case BPF_TRACE_FENTRY:
5802+
case BPF_TRACE_FEXIT:
5803+
case BPF_MODIFY_RETURN:
5804+
/* allow u64* as ctx */
5805+
if (btf_is_int(t) && t->size == 8)
5806+
return 0;
5807+
break;
5808+
default:
5809+
break;
5810+
}
5811+
break;
5812+
case BPF_PROG_TYPE_LSM:
5813+
case BPF_PROG_TYPE_STRUCT_OPS:
5814+
/* allow u64* as ctx */
5815+
if (btf_is_int(t) && t->size == 8)
5816+
return 0;
5817+
break;
5818+
case BPF_PROG_TYPE_TRACEPOINT:
5819+
case BPF_PROG_TYPE_SYSCALL:
5820+
case BPF_PROG_TYPE_EXT:
5821+
return 0; /* anything goes */
5822+
default:
5823+
break;
5824+
}
5825+
5826+
ctx_type = find_canonical_prog_ctx_type(prog_type);
5827+
if (!ctx_type) {
5828+
/* should not happen */
5829+
bpf_log(log, "btf_vmlinux is malformed\n");
5830+
return -EINVAL;
5831+
}
5832+
5833+
/* resolve typedefs and check that underlying structs are matching as well */
5834+
while (btf_type_is_modifier(ctx_type))
5835+
ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type);
5836+
5837+
/* if program type doesn't have distinctly named struct type for
5838+
* context, then __arg_ctx argument can only be `void *`, which we
5839+
* already checked above
5840+
*/
5841+
if (!__btf_type_is_struct(ctx_type)) {
5842+
bpf_log(log, "arg#%d should be void pointer\n", arg);
5843+
return -EINVAL;
5844+
}
5845+
5846+
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off);
5847+
if (!__btf_type_is_struct(t) || strcmp(ctx_tname, tname) != 0) {
5848+
bpf_log(log, "arg#%d should be `struct %s *`\n", arg, ctx_tname);
5849+
return -EINVAL;
5850+
}
5851+
5852+
return 0;
5853+
}
5854+
56895855
static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
56905856
struct btf *btf,
56915857
const struct btf_type *t,
56925858
enum bpf_prog_type prog_type,
56935859
int arg)
56945860
{
5695-
const struct btf_member *prog_ctx_type, *kern_ctx_type;
5696-
5697-
prog_ctx_type = btf_get_prog_ctx_type(log, btf, t, prog_type, arg);
5698-
if (!prog_ctx_type)
5861+
if (!btf_get_prog_ctx_type(log, btf, t, prog_type, arg))
56995862
return -ENOENT;
5700-
kern_ctx_type = prog_ctx_type + 1;
5701-
return kern_ctx_type->type;
5863+
return find_kern_ctx_type_id(prog_type);
57025864
}
57035865

57045866
int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type)
@@ -6934,6 +7096,23 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
69347096
return -EINVAL;
69357097
}
69367098

7099+
for (i = 0; i < nargs; i++) {
7100+
const char *tag;
7101+
7102+
if (sub->args[i].arg_type != ARG_PTR_TO_CTX)
7103+
continue;
7104+
7105+
/* check if arg has "arg:ctx" tag */
7106+
t = btf_type_by_id(btf, args[i].type);
7107+
tag = btf_find_decl_tag_value(btf, fn_t, i, "arg:");
7108+
if (IS_ERR_OR_NULL(tag) || strcmp(tag, "ctx") != 0)
7109+
continue;
7110+
7111+
if (btf_validate_prog_ctx_type(log, btf, t, i, prog_type,
7112+
prog->expected_attach_type))
7113+
return -EINVAL;
7114+
}
7115+
69377116
sub->arg_cnt = nargs;
69387117
sub->args_cached = true;
69397118

kernel/bpf/verifier.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12826,6 +12826,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
1282612826
}
1282712827

1282812828
switch (base_type(ptr_reg->type)) {
12829+
case PTR_TO_FLOW_KEYS:
12830+
if (known)
12831+
break;
12832+
fallthrough;
1282912833
case CONST_PTR_TO_MAP:
1283012834
/* smin_val represents the known value */
1283112835
if (known && smin_val == 0 && opcode == BPF_ADD)

net/ipv4/udp.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,16 +3137,18 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
31373137
struct bpf_udp_iter_state *iter = seq->private;
31383138
struct udp_iter_state *state = &iter->state;
31393139
struct net *net = seq_file_net(seq);
3140+
int resume_bucket, resume_offset;
31403141
struct udp_table *udptable;
31413142
unsigned int batch_sks = 0;
31423143
bool resized = false;
31433144
struct sock *sk;
31443145

3146+
resume_bucket = state->bucket;
3147+
resume_offset = iter->offset;
3148+
31453149
/* The current batch is done, so advance the bucket. */
3146-
if (iter->st_bucket_done) {
3150+
if (iter->st_bucket_done)
31473151
state->bucket++;
3148-
iter->offset = 0;
3149-
}
31503152

31513153
udptable = udp_get_table_seq(seq, net);
31523154

@@ -3166,19 +3168,19 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
31663168
for (; state->bucket <= udptable->mask; state->bucket++) {
31673169
struct udp_hslot *hslot2 = &udptable->hash2[state->bucket];
31683170

3169-
if (hlist_empty(&hslot2->head)) {
3170-
iter->offset = 0;
3171+
if (hlist_empty(&hslot2->head))
31713172
continue;
3172-
}
31733173

3174+
iter->offset = 0;
31743175
spin_lock_bh(&hslot2->lock);
31753176
udp_portaddr_for_each_entry(sk, &hslot2->head) {
31763177
if (seq_sk_match(seq, sk)) {
31773178
/* Resume from the last iterated socket at the
31783179
* offset in the bucket before iterator was stopped.
31793180
*/
3180-
if (iter->offset) {
3181-
--iter->offset;
3181+
if (state->bucket == resume_bucket &&
3182+
iter->offset < resume_offset) {
3183+
++iter->offset;
31823184
continue;
31833185
}
31843186
if (iter->end_sk < iter->max_sk) {
@@ -3192,9 +3194,6 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
31923194

31933195
if (iter->end_sk)
31943196
break;
3195-
3196-
/* Reset the current bucket's offset before moving to the next bucket. */
3197-
iter->offset = 0;
31983197
}
31993198

32003199
/* All done: no batch made. */
@@ -3213,7 +3212,6 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
32133212
/* After allocating a larger batch, retry one more time to grab
32143213
* the whole bucket.
32153214
*/
3216-
state->bucket--;
32173215
goto again;
32183216
}
32193217
done:

0 commit comments

Comments
 (0)