Skip to content

Commit 91af2fc

Browse files
kkdwvdAlexei Starovoitov
authored andcommitted
bpf: Make btf_find_field more generic
Next commit introduces field type 'kptr' whose kind will not be struct, but pointer, and it will not be limited to one offset, but multiple ones. Make existing btf_find_struct_field and btf_find_datasec_var functions amenable to use for finding kptrs in map value, by moving spin_lock and timer specific checks into their own function. The alignment, and name are checked before the function is called, so it is the last point where we can skip field or return an error before the next loop iteration happens. Size of the field and type is meant to be checked inside the function. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20220415160354.1050687-2-memxor@gmail.com
1 parent e1a34e1 commit 91af2fc

File tree

1 file changed

+89
-31
lines changed

1 file changed

+89
-31
lines changed

kernel/bpf/btf.c

Lines changed: 89 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3163,71 +3163,121 @@ static void btf_struct_log(struct btf_verifier_env *env,
31633163
btf_verifier_log(env, "size=%u vlen=%u", t->size, btf_type_vlen(t));
31643164
}
31653165

3166+
enum btf_field_type {
3167+
BTF_FIELD_SPIN_LOCK,
3168+
BTF_FIELD_TIMER,
3169+
};
3170+
3171+
struct btf_field_info {
3172+
u32 off;
3173+
};
3174+
3175+
static int btf_find_struct(const struct btf *btf, const struct btf_type *t,
3176+
u32 off, int sz, struct btf_field_info *info)
3177+
{
3178+
if (!__btf_type_is_struct(t))
3179+
return 0;
3180+
if (t->size != sz)
3181+
return 0;
3182+
if (info->off != -ENOENT)
3183+
/* only one such field is allowed */
3184+
return -E2BIG;
3185+
info->off = off;
3186+
return 0;
3187+
}
3188+
31663189
static int btf_find_struct_field(const struct btf *btf, const struct btf_type *t,
3167-
const char *name, int sz, int align)
3190+
const char *name, int sz, int align,
3191+
enum btf_field_type field_type,
3192+
struct btf_field_info *info)
31683193
{
31693194
const struct btf_member *member;
3170-
u32 i, off = -ENOENT;
3195+
u32 i, off;
31713196

31723197
for_each_member(i, t, member) {
31733198
const struct btf_type *member_type = btf_type_by_id(btf,
31743199
member->type);
3175-
if (!__btf_type_is_struct(member_type))
3176-
continue;
3177-
if (member_type->size != sz)
3178-
continue;
3200+
31793201
if (strcmp(__btf_name_by_offset(btf, member_type->name_off), name))
31803202
continue;
3181-
if (off != -ENOENT)
3182-
/* only one such field is allowed */
3183-
return -E2BIG;
3203+
31843204
off = __btf_member_bit_offset(t, member);
31853205
if (off % 8)
31863206
/* valid C code cannot generate such BTF */
31873207
return -EINVAL;
31883208
off /= 8;
31893209
if (off % align)
31903210
return -EINVAL;
3211+
3212+
switch (field_type) {
3213+
case BTF_FIELD_SPIN_LOCK:
3214+
case BTF_FIELD_TIMER:
3215+
return btf_find_struct(btf, member_type, off, sz, info);
3216+
default:
3217+
return -EFAULT;
3218+
}
31913219
}
3192-
return off;
3220+
return 0;
31933221
}
31943222

31953223
static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t,
3196-
const char *name, int sz, int align)
3224+
const char *name, int sz, int align,
3225+
enum btf_field_type field_type,
3226+
struct btf_field_info *info)
31973227
{
31983228
const struct btf_var_secinfo *vsi;
3199-
u32 i, off = -ENOENT;
3229+
u32 i, off;
32003230

32013231
for_each_vsi(i, t, vsi) {
32023232
const struct btf_type *var = btf_type_by_id(btf, vsi->type);
32033233
const struct btf_type *var_type = btf_type_by_id(btf, var->type);
32043234

3205-
if (!__btf_type_is_struct(var_type))
3206-
continue;
3207-
if (var_type->size != sz)
3235+
off = vsi->offset;
3236+
3237+
if (strcmp(__btf_name_by_offset(btf, var_type->name_off), name))
32083238
continue;
32093239
if (vsi->size != sz)
32103240
continue;
3211-
if (strcmp(__btf_name_by_offset(btf, var_type->name_off), name))
3212-
continue;
3213-
if (off != -ENOENT)
3214-
/* only one such field is allowed */
3215-
return -E2BIG;
3216-
off = vsi->offset;
32173241
if (off % align)
32183242
return -EINVAL;
3243+
3244+
switch (field_type) {
3245+
case BTF_FIELD_SPIN_LOCK:
3246+
case BTF_FIELD_TIMER:
3247+
return btf_find_struct(btf, var_type, off, sz, info);
3248+
default:
3249+
return -EFAULT;
3250+
}
32193251
}
3220-
return off;
3252+
return 0;
32213253
}
32223254

32233255
static int btf_find_field(const struct btf *btf, const struct btf_type *t,
3224-
const char *name, int sz, int align)
3256+
enum btf_field_type field_type,
3257+
struct btf_field_info *info)
32253258
{
3259+
const char *name;
3260+
int sz, align;
3261+
3262+
switch (field_type) {
3263+
case BTF_FIELD_SPIN_LOCK:
3264+
name = "bpf_spin_lock";
3265+
sz = sizeof(struct bpf_spin_lock);
3266+
align = __alignof__(struct bpf_spin_lock);
3267+
break;
3268+
case BTF_FIELD_TIMER:
3269+
name = "bpf_timer";
3270+
sz = sizeof(struct bpf_timer);
3271+
align = __alignof__(struct bpf_timer);
3272+
break;
3273+
default:
3274+
return -EFAULT;
3275+
}
32263276

32273277
if (__btf_type_is_struct(t))
3228-
return btf_find_struct_field(btf, t, name, sz, align);
3278+
return btf_find_struct_field(btf, t, name, sz, align, field_type, info);
32293279
else if (btf_type_is_datasec(t))
3230-
return btf_find_datasec_var(btf, t, name, sz, align);
3280+
return btf_find_datasec_var(btf, t, name, sz, align, field_type, info);
32313281
return -EINVAL;
32323282
}
32333283

@@ -3237,16 +3287,24 @@ static int btf_find_field(const struct btf *btf, const struct btf_type *t,
32373287
*/
32383288
int btf_find_spin_lock(const struct btf *btf, const struct btf_type *t)
32393289
{
3240-
return btf_find_field(btf, t, "bpf_spin_lock",
3241-
sizeof(struct bpf_spin_lock),
3242-
__alignof__(struct bpf_spin_lock));
3290+
struct btf_field_info info = { .off = -ENOENT };
3291+
int ret;
3292+
3293+
ret = btf_find_field(btf, t, BTF_FIELD_SPIN_LOCK, &info);
3294+
if (ret < 0)
3295+
return ret;
3296+
return info.off;
32433297
}
32443298

32453299
int btf_find_timer(const struct btf *btf, const struct btf_type *t)
32463300
{
3247-
return btf_find_field(btf, t, "bpf_timer",
3248-
sizeof(struct bpf_timer),
3249-
__alignof__(struct bpf_timer));
3301+
struct btf_field_info info = { .off = -ENOENT };
3302+
int ret;
3303+
3304+
ret = btf_find_field(btf, t, BTF_FIELD_TIMER, &info);
3305+
if (ret < 0)
3306+
return ret;
3307+
return info.off;
32503308
}
32513309

32523310
static void __btf_struct_show(const struct btf *btf, const struct btf_type *t,

0 commit comments

Comments
 (0)