Message ID | 20210210030317.78820-5-iii@linux.ibm.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | Add BTF_KIND_FLOAT support | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Not a local patch |
On Tue, Feb 9, 2021 at 7:04 PM Ilya Leoshkevich <iii@linux.ibm.com> wrote: > > On the kernel side, introduce a new btf_kind_operations. It is > similar to that of BTF_KIND_INT, however, it does not need to > handle encodings and bit offsets. Do not implement printing, since > the kernel does not know how to format floating-point values. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > kernel/bpf/btf.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 99 insertions(+), 2 deletions(-) > > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index 756a93f534b6..6f27b7b59d77 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -173,8 +173,9 @@ > #define BITS_ROUNDUP_BYTES(bits) \ > (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) > > -#define BTF_INFO_MASK 0x8f00ffff > +#define BTF_INFO_MASK 0x9f00ffff > #define BTF_INT_MASK 0x0fffffff > +#define BTF_FLOAT_MASK 0x000000ff > #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE) > #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET) > > @@ -280,6 +281,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { > [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", > [BTF_KIND_VAR] = "VAR", > [BTF_KIND_DATASEC] = "DATASEC", > + [BTF_KIND_FLOAT] = "FLOAT", > }; > > static const char *btf_type_str(const struct btf_type *t) > @@ -574,6 +576,7 @@ static bool btf_type_has_size(const struct btf_type *t) > case BTF_KIND_UNION: > case BTF_KIND_ENUM: > case BTF_KIND_DATASEC: > + case BTF_KIND_FLOAT: > return true; > } > > @@ -614,6 +617,11 @@ static const struct btf_var *btf_type_var(const struct btf_type *t) > return (const struct btf_var *)(t + 1); > } > > +static u32 btf_type_float(const struct btf_type *t) > +{ > + return *(u32 *)(t + 1); > +} > + > static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) > { > return kind_ops[BTF_INFO_KIND(t->info)]; > @@ -1704,6 +1712,7 @@ __btf_resolve_size(const struct btf *btf, const struct btf_type *type, > case BTF_KIND_STRUCT: > case BTF_KIND_UNION: > case BTF_KIND_ENUM: > + case BTF_KIND_FLOAT: > size = type->size; > goto resolved; > > @@ -1849,7 +1858,7 @@ static int btf_df_check_kflag_member(struct btf_verifier_env *env, > return -EINVAL; > } > > -/* Used for ptr, array and struct/union type members. > +/* Used for ptr, array struct/union and float type members. > * int, enum and modifier types have their specific callback functions. > */ > static int btf_generic_check_kflag_member(struct btf_verifier_env *env, > @@ -3675,6 +3684,93 @@ static const struct btf_kind_operations datasec_ops = { > .show = btf_datasec_show, > }; > > +static s32 btf_float_check_meta(struct btf_verifier_env *env, > + const struct btf_type *t, > + u32 meta_left) > +{ > + u32 float_data, nr_bits, meta_needed = sizeof(float_data); > + > + if (meta_left < meta_needed) { > + btf_verifier_log_basic(env, t, > + "meta_left:%u meta_needed:%u", > + meta_left, meta_needed); > + return -EINVAL; > + } > + > + if (btf_type_vlen(t)) { > + btf_verifier_log_type(env, t, "vlen != 0"); > + return -EINVAL; > + } > + > + if (btf_type_kflag(t)) { > + btf_verifier_log_type(env, t, "Invalid btf_info kind_flag"); > + return -EINVAL; > + } > + > + float_data = btf_type_float(t); > + if (float_data & ~BTF_FLOAT_MASK) { > + btf_verifier_log_basic(env, t, "Invalid float_data:%x", > + float_data); > + return -EINVAL; > + } > + > + nr_bits = BTF_FLOAT_BITS(float_data); > + > + if (BITS_ROUNDUP_BYTES(nr_bits) > t->size) { what's the case where nr_bits != t->size * 8 ? Is that even possible in C? > + btf_verifier_log_type(env, t, "nr_bits exceeds type_size"); > + return -EINVAL; > + } > + > + btf_verifier_log_type(env, t, NULL); > + > + return meta_needed; > +} > + > +static int btf_float_check_member(struct btf_verifier_env *env, > + const struct btf_type *struct_type, > + const struct btf_member *member, > + const struct btf_type *member_type) > +{ > + u64 end_offset_bytes; > + u64 end_offset_bits; > + u64 offset_bits; > + u32 float_data; > + u64 size_bits; > + > + float_data = btf_type_float(member_type); > + size_bits = BTF_FLOAT_BITS(float_data); > + offset_bits = member->offset; > + end_offset_bits = offset_bits + size_bits; > + end_offset_bytes = BITS_ROUNDUP_BYTES(end_offset_bits); > + > + if (end_offset_bytes > struct_type->size) { > + btf_verifier_log_member(env, struct_type, member, > + "Member exceeds struct_size"); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static void btf_float_log(struct btf_verifier_env *env, > + const struct btf_type *t) > +{ > + int float_data = btf_type_float(t); > + > + btf_verifier_log(env, > + "size=%u nr_bits=%u", > + t->size, BTF_FLOAT_BITS(float_data)); > +} > + > +static const struct btf_kind_operations float_ops = { > + .check_meta = btf_float_check_meta, > + .resolve = btf_df_resolve, > + .check_member = btf_float_check_member, > + .check_kflag_member = btf_generic_check_kflag_member, > + .log_details = btf_float_log, > + .show = btf_df_show, > +}; > + > static int btf_func_proto_check(struct btf_verifier_env *env, > const struct btf_type *t) > { > @@ -3808,6 +3904,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { > [BTF_KIND_FUNC_PROTO] = &func_proto_ops, > [BTF_KIND_VAR] = &var_ops, > [BTF_KIND_DATASEC] = &datasec_ops, > + [BTF_KIND_FLOAT] = &float_ops, > }; > > static s32 btf_check_meta(struct btf_verifier_env *env, > -- > 2.29.2 >
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 756a93f534b6..6f27b7b59d77 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -173,8 +173,9 @@ #define BITS_ROUNDUP_BYTES(bits) \ (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) -#define BTF_INFO_MASK 0x8f00ffff +#define BTF_INFO_MASK 0x9f00ffff #define BTF_INT_MASK 0x0fffffff +#define BTF_FLOAT_MASK 0x000000ff #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE) #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET) @@ -280,6 +281,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", [BTF_KIND_VAR] = "VAR", [BTF_KIND_DATASEC] = "DATASEC", + [BTF_KIND_FLOAT] = "FLOAT", }; static const char *btf_type_str(const struct btf_type *t) @@ -574,6 +576,7 @@ static bool btf_type_has_size(const struct btf_type *t) case BTF_KIND_UNION: case BTF_KIND_ENUM: case BTF_KIND_DATASEC: + case BTF_KIND_FLOAT: return true; } @@ -614,6 +617,11 @@ static const struct btf_var *btf_type_var(const struct btf_type *t) return (const struct btf_var *)(t + 1); } +static u32 btf_type_float(const struct btf_type *t) +{ + return *(u32 *)(t + 1); +} + static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) { return kind_ops[BTF_INFO_KIND(t->info)]; @@ -1704,6 +1712,7 @@ __btf_resolve_size(const struct btf *btf, const struct btf_type *type, case BTF_KIND_STRUCT: case BTF_KIND_UNION: case BTF_KIND_ENUM: + case BTF_KIND_FLOAT: size = type->size; goto resolved; @@ -1849,7 +1858,7 @@ static int btf_df_check_kflag_member(struct btf_verifier_env *env, return -EINVAL; } -/* Used for ptr, array and struct/union type members. +/* Used for ptr, array struct/union and float type members. * int, enum and modifier types have their specific callback functions. */ static int btf_generic_check_kflag_member(struct btf_verifier_env *env, @@ -3675,6 +3684,93 @@ static const struct btf_kind_operations datasec_ops = { .show = btf_datasec_show, }; +static s32 btf_float_check_meta(struct btf_verifier_env *env, + const struct btf_type *t, + u32 meta_left) +{ + u32 float_data, nr_bits, meta_needed = sizeof(float_data); + + if (meta_left < meta_needed) { + btf_verifier_log_basic(env, t, + "meta_left:%u meta_needed:%u", + meta_left, meta_needed); + return -EINVAL; + } + + if (btf_type_vlen(t)) { + btf_verifier_log_type(env, t, "vlen != 0"); + return -EINVAL; + } + + if (btf_type_kflag(t)) { + btf_verifier_log_type(env, t, "Invalid btf_info kind_flag"); + return -EINVAL; + } + + float_data = btf_type_float(t); + if (float_data & ~BTF_FLOAT_MASK) { + btf_verifier_log_basic(env, t, "Invalid float_data:%x", + float_data); + return -EINVAL; + } + + nr_bits = BTF_FLOAT_BITS(float_data); + + if (BITS_ROUNDUP_BYTES(nr_bits) > t->size) { + btf_verifier_log_type(env, t, "nr_bits exceeds type_size"); + return -EINVAL; + } + + btf_verifier_log_type(env, t, NULL); + + return meta_needed; +} + +static int btf_float_check_member(struct btf_verifier_env *env, + const struct btf_type *struct_type, + const struct btf_member *member, + const struct btf_type *member_type) +{ + u64 end_offset_bytes; + u64 end_offset_bits; + u64 offset_bits; + u32 float_data; + u64 size_bits; + + float_data = btf_type_float(member_type); + size_bits = BTF_FLOAT_BITS(float_data); + offset_bits = member->offset; + end_offset_bits = offset_bits + size_bits; + end_offset_bytes = BITS_ROUNDUP_BYTES(end_offset_bits); + + if (end_offset_bytes > struct_type->size) { + btf_verifier_log_member(env, struct_type, member, + "Member exceeds struct_size"); + return -EINVAL; + } + + return 0; +} + +static void btf_float_log(struct btf_verifier_env *env, + const struct btf_type *t) +{ + int float_data = btf_type_float(t); + + btf_verifier_log(env, + "size=%u nr_bits=%u", + t->size, BTF_FLOAT_BITS(float_data)); +} + +static const struct btf_kind_operations float_ops = { + .check_meta = btf_float_check_meta, + .resolve = btf_df_resolve, + .check_member = btf_float_check_member, + .check_kflag_member = btf_generic_check_kflag_member, + .log_details = btf_float_log, + .show = btf_df_show, +}; + static int btf_func_proto_check(struct btf_verifier_env *env, const struct btf_type *t) { @@ -3808,6 +3904,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { [BTF_KIND_FUNC_PROTO] = &func_proto_ops, [BTF_KIND_VAR] = &var_ops, [BTF_KIND_DATASEC] = &datasec_ops, + [BTF_KIND_FLOAT] = &float_ops, }; static s32 btf_check_meta(struct btf_verifier_env *env,
On the kernel side, introduce a new btf_kind_operations. It is similar to that of BTF_KIND_INT, however, it does not need to handle encodings and bit offsets. Do not implement printing, since the kernel does not know how to format floating-point values. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- kernel/bpf/btf.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-)