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.
Unified · Split
| @@ -173,7 +173,7 @@ · 172 unmodified lines | |||
| 173 | #define BITS_ROUNDUP_BYTES(bits) \ | 173 | #define BITS_ROUNDUP_BYTES(bits) \ |
| 174 | (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) | 174 | (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) |
| 175 | 175 | ||
| 176 | #define BTF_INFO_MASK 0x8f00ffff | 176 | #define BTF_INFO_MASK 0x9f00ffff |
| 177 | #define BTF_INT_MASK 0x0fffffff | 177 | #define BTF_INT_MASK 0x0fffffff |
| 178 | #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE) | 178 | #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE) |
| 179 | #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET) | 179 | #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET) |
| @@ -280,6 +280,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { · 100 unmodified lines | |||
| 280 | [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", | 280 | [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", |
| 281 | [BTF_KIND_VAR] = "VAR", | 281 | [BTF_KIND_VAR] = "VAR", |
| 282 | [BTF_KIND_DATASEC] = "DATASEC", | 282 | [BTF_KIND_DATASEC] = "DATASEC", |
| 283 | [BTF_KIND_FLOAT] = "FLOAT", | ||
| 283 | }; | 284 | }; |
| 284 | 285 | ||
| 285 | static const char *btf_type_str(const struct btf_type *t) | 286 | static const char *btf_type_str(const struct btf_type *t) |
| @@ -574,6 +575,7 @@ static bool btf_type_has_size(const struct btf_type *t) · 288 unmodified lines | |||
| 574 | case BTF_KIND_UNION: | 575 | case BTF_KIND_UNION: |
| 575 | case BTF_KIND_ENUM: | 576 | case BTF_KIND_ENUM: |
| 576 | case BTF_KIND_DATASEC: | 577 | case BTF_KIND_DATASEC: |
| 578 | case BTF_KIND_FLOAT: | ||
| 577 | return true; | 579 | return true; |
| 578 | } | 580 | } |
| 579 | 581 | ||
| @@ -1704,6 +1706,7 @@ __btf_resolve_size(const struct btf *btf, const struct btf_type *type, · 1124 unmodified lines | |||
| 1704 | case BTF_KIND_STRUCT: | 1706 | case BTF_KIND_STRUCT: |
| 1705 | case BTF_KIND_UNION: | 1707 | case BTF_KIND_UNION: |
| 1706 | case BTF_KIND_ENUM: | 1708 | case BTF_KIND_ENUM: |
| 1709 | case BTF_KIND_FLOAT: | ||
| 1707 | size = type->size; | 1710 | size = type->size; |
| 1708 | goto resolved; | 1711 | goto resolved; |
| 1709 | 1712 | ||
| @@ -1849,7 +1852,7 @@ static int btf_df_check_kflag_member(struct btf_verifier_env *env, · 139 unmodified lines | |||
| 1849 | return -EINVAL; | 1852 | return -EINVAL; |
| 1850 | } | 1853 | } |
| 1851 | 1854 | ||
| 1852 | /* Used for ptr, array and struct/union type members. | 1855 | /* Used for ptr, array struct/union and float type members. |
| 1853 | * int, enum and modifier types have their specific callback functions. | 1856 | * int, enum and modifier types have their specific callback functions. |
| 1854 | */ | 1857 | */ |
| 1855 | static int btf_generic_check_kflag_member(struct btf_verifier_env *env, | 1858 | static int btf_generic_check_kflag_member(struct btf_verifier_env *env, |
| @@ -3675,6 +3678,81 @@ static const struct btf_kind_operations datasec_ops = { · 1819 unmodified lines | |||
| 3675 | .show = btf_datasec_show, | 3678 | .show = btf_datasec_show, |
| 3676 | }; | 3679 | }; |
| 3677 | 3680 | ||
| 3681 | static s32 btf_float_check_meta(struct btf_verifier_env *env, | ||
| 3682 | const struct btf_type *t, | ||
| 3683 | u32 meta_left) | ||
| 3684 | { | ||
| 3685 | if (btf_type_vlen(t)) { | ||
| 3686 | btf_verifier_log_type(env, t, "vlen != 0"); | ||
| 3687 | return -EINVAL; | ||
| 3688 | } | ||
| 3689 | |||
| 3690 | if (btf_type_kflag(t)) { | ||
| 3691 | btf_verifier_log_type(env, t, "Invalid btf_info kind_flag"); | ||
| 3692 | return -EINVAL; | ||
| 3693 | } | ||
| 3694 | |||
| 3695 | if (t->size != 2 && t->size != 4 && t->size != 8 && t->size != 12 && | ||
| 3696 | t->size != 16) { | ||
| 3697 | btf_verifier_log_type(env, t, "Invalid type_size"); | ||
| 3698 | return -EINVAL; | ||
| 3699 | } | ||
| 3700 | |||
| 3701 | btf_verifier_log_type(env, t, NULL); | ||
| 3702 | |||
| 3703 | return 0; | ||
| 3704 | } | ||
| 3705 | |||
| 3706 | static int btf_float_check_member(struct btf_verifier_env *env, | ||
| 3707 | const struct btf_type *struct_type, | ||
| 3708 | const struct btf_member *member, | ||
| 3709 | const struct btf_type *member_type) | ||
| 3710 | { | ||
| 3711 | u64 start_offset_bytes; | ||
| 3712 | u64 end_offset_bytes; | ||
| 3713 | u64 misalign_bits; | ||
| 3714 | u64 align_bytes; | ||
| 3715 | u64 align_bits; | ||
| 3716 | |||
| 3717 | /* Different architectures have different alignment requirements, so | ||
| 3718 | * here we check only for the reasonable minimum. This way we ensure | ||
| 3719 | * that types after CO-RE can pass the kernel BTF verifier. | ||
| 3720 | */ | ||
| 3721 | align_bytes = min_t(u64, sizeof(void *), member_type->size); | ||
| 3722 | align_bits = align_bytes * BITS_PER_BYTE; | ||
| 3723 | div64_u64_rem(member->offset, align_bits, &misalign_bits); | ||
| 3724 | if (misalign_bits) { | ||
| 3725 | btf_verifier_log_member(env, struct_type, member, | ||
| 3726 | "Member is not properly aligned"); | ||
| 3727 | return -EINVAL; | ||
| 3728 | } | ||
| 3729 | |||
| 3730 | start_offset_bytes = member->offset / BITS_PER_BYTE; | ||
| 3731 | end_offset_bytes = start_offset_bytes + member_type->size; | ||
| 3732 | if (end_offset_bytes > struct_type->size) { | ||
| 3733 | btf_verifier_log_member(env, struct_type, member, | ||
| 3734 | "Member exceeds struct_size"); | ||
| 3735 | return -EINVAL; | ||
| 3736 | } | ||
| 3737 | |||
| 3738 | return 0; | ||
| 3739 | } | ||
| 3740 | |||
| 3741 | static void btf_float_log(struct btf_verifier_env *env, | ||
| 3742 | const struct btf_type *t) | ||
| 3743 | { | ||
| 3744 | btf_verifier_log(env, "size=%u", t->size); | ||
| 3745 | } | ||
| 3746 | |||
| 3747 | static const struct btf_kind_operations float_ops = { | ||
| 3748 | .check_meta = btf_float_check_meta, | ||
| 3749 | .resolve = btf_df_resolve, | ||
| 3750 | .check_member = btf_float_check_member, | ||
| 3751 | .check_kflag_member = btf_generic_check_kflag_member, | ||
| 3752 | .log_details = btf_float_log, | ||
| 3753 | .show = btf_df_show, | ||
| 3754 | }; | ||
| 3755 | |||
| 3678 | static int btf_func_proto_check(struct btf_verifier_env *env, | 3756 | static int btf_func_proto_check(struct btf_verifier_env *env, |
| 3679 | const struct btf_type *t) | 3757 | const struct btf_type *t) |
| 3680 | { | 3758 | { |
| @@ -3808,6 +3886,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { · 127 unmodified lines | |||
| 3808 | [BTF_KIND_FUNC_PROTO] = &func_proto_ops, | 3886 | [BTF_KIND_FUNC_PROTO] = &func_proto_ops, |
| 3809 | [BTF_KIND_VAR] = &var_ops, | 3887 | [BTF_KIND_VAR] = &var_ops, |
| 3810 | [BTF_KIND_DATASEC] = &datasec_ops, | 3888 | [BTF_KIND_DATASEC] = &datasec_ops, |
| 3889 | [BTF_KIND_FLOAT] = &float_ops, | ||
| 3811 | }; | 3890 | }; |
| 3812 | 3891 | ||
| 3813 | static s32 btf_check_meta(struct btf_verifier_env *env, | 3892 | static s32 btf_check_meta(struct btf_verifier_env *env, |