diff mbox series

[v2,bpf-next,4/9] btf: support kernel parsing of BTF with kind layout

Message ID 20230616171728.530116-5-alan.maguire@oracle.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series bpf: support BTF kind layout info, CRCs | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 14 this patch: 14
netdev/cc_maintainers success CCed 12 of 12 maintainers
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 14 this patch: 14
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-17 fail Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-11 fail Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 fail Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 fail Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 fail Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on s390x with gcc

Commit Message

Alan Maguire June 16, 2023, 5:17 p.m. UTC
Use kind layout to parse BTF with unknown kinds that have a
kind layout representation.

Validate kind layout if present, and use it to parse BTF with
unrecognized kinds. Reject BTF that contains a type
of a kind that is not optional.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
 kernel/bpf/btf.c | 102 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 82 insertions(+), 20 deletions(-)

Comments

Jiri Olsa June 18, 2023, 1:08 p.m. UTC | #1
On Fri, Jun 16, 2023 at 06:17:22PM +0100, Alan Maguire wrote:

SNIP

>  static int btf_sec_info_cmp(const void *a, const void *b)
> @@ -5193,32 +5246,37 @@ static int btf_check_sec_info(struct btf_verifier_env *env,
>  			      u32 btf_data_size)
>  {
>  	struct btf_sec_info secs[ARRAY_SIZE(btf_sec_info_offset)];
> -	u32 total, expected_total, i;
> +	u32 nr_secs = ARRAY_SIZE(btf_sec_info_offset);
> +	u32 total, expected_total, gap, i;
>  	const struct btf_header *hdr;
>  	const struct btf *btf;
>  
>  	btf = env->btf;
>  	hdr = &btf->hdr;
>  
> +	if (hdr->hdr_len < sizeof(struct btf_header))
> +		nr_secs--;
> +
>  	/* Populate the secs from hdr */
> -	for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++)
> +	for (i = 0; i < nr_secs; i++)
>  		secs[i] = *(struct btf_sec_info *)((void *)hdr +
>  						   btf_sec_info_offset[i]);
>  
> -	sort(secs, ARRAY_SIZE(btf_sec_info_offset),
> +	sort(secs, nr_secs,
>  	     sizeof(struct btf_sec_info), btf_sec_info_cmp, NULL);
>  
>  	/* Check for gaps and overlap among sections */
>  	total = 0;
>  	expected_total = btf_data_size - hdr->hdr_len;
> -	for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++) {
> +	for (i = 0; i < nr_secs; i++) {
>  		if (expected_total < secs[i].off) {
>  			btf_verifier_log(env, "Invalid section offset");
>  			return -EINVAL;
>  		}
> -		if (total < secs[i].off) {
> -			/* gap */
> -			btf_verifier_log(env, "Unsupported section found");
> +		gap = secs[i].off - total;
> +		if (gap >= 4) {
> +			/* gap larger than alignment gap */
> +			btf_verifier_log(env, "Unsupported section gap found");
>  			return -EINVAL;

this sems to break several btf header tests with:

	do_test_raw:PASS:check 0 nsec
	do_test_raw:FAIL:check expected err_str:Unsupported section found

	magic: 0xeb9f
	version: 1
	flags: 0x0
	hdr_len: 40
	type_off: 4
	type_len: 16
	str_off: 16
	str_len: 5
	btf_total_size: 61
	Unsupported section gap found
	#23/48   btf/btf_header test. Gap between hdr and type:FAIL


jirka

>  		}
>  		if (total > secs[i].off) {
> @@ -5230,7 +5288,7 @@ static int btf_check_sec_info(struct btf_verifier_env *env,
>  					 "Total section length too long");
>  			return -EINVAL;
>  		}
> -		total += secs[i].len;
> +		total += secs[i].len + gap;
>  	}
>  
>  	/* There is data other than hdr and known sections */
> @@ -5293,7 +5351,7 @@ static int btf_parse_hdr(struct btf_verifier_env *env)
>  		return -ENOTSUPP;
>  	}
>  
> -	if (hdr->flags) {
> +	if (hdr->flags & ~(BTF_FLAG_CRC_SET | BTF_FLAG_BASE_CRC_SET)) {
>  		btf_verifier_log(env, "Unsupported flags");
>  		return -ENOTSUPP;
>  	}
> @@ -5530,6 +5588,10 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
>  	if (err)
>  		goto errout;
>  
> +	err = btf_parse_kind_layout_sec(env);
> +	if (err)
> +		goto errout;
> +
>  	err = btf_parse_type_sec(env);
>  	if (err)
>  		goto errout;
> -- 
> 2.39.3
>
Alan Maguire June 20, 2023, 8:40 a.m. UTC | #2
On 18/06/2023 14:08, Jiri Olsa wrote:
> On Fri, Jun 16, 2023 at 06:17:22PM +0100, Alan Maguire wrote:
> 
> SNIP
> 
>>  static int btf_sec_info_cmp(const void *a, const void *b)
>> @@ -5193,32 +5246,37 @@ static int btf_check_sec_info(struct btf_verifier_env *env,
>>  			      u32 btf_data_size)
>>  {
>>  	struct btf_sec_info secs[ARRAY_SIZE(btf_sec_info_offset)];
>> -	u32 total, expected_total, i;
>> +	u32 nr_secs = ARRAY_SIZE(btf_sec_info_offset);
>> +	u32 total, expected_total, gap, i;
>>  	const struct btf_header *hdr;
>>  	const struct btf *btf;
>>  
>>  	btf = env->btf;
>>  	hdr = &btf->hdr;
>>  
>> +	if (hdr->hdr_len < sizeof(struct btf_header))
>> +		nr_secs--;
>> +
>>  	/* Populate the secs from hdr */
>> -	for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++)
>> +	for (i = 0; i < nr_secs; i++)
>>  		secs[i] = *(struct btf_sec_info *)((void *)hdr +
>>  						   btf_sec_info_offset[i]);
>>  
>> -	sort(secs, ARRAY_SIZE(btf_sec_info_offset),
>> +	sort(secs, nr_secs,
>>  	     sizeof(struct btf_sec_info), btf_sec_info_cmp, NULL);
>>  
>>  	/* Check for gaps and overlap among sections */
>>  	total = 0;
>>  	expected_total = btf_data_size - hdr->hdr_len;
>> -	for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++) {
>> +	for (i = 0; i < nr_secs; i++) {
>>  		if (expected_total < secs[i].off) {
>>  			btf_verifier_log(env, "Invalid section offset");
>>  			return -EINVAL;
>>  		}
>> -		if (total < secs[i].off) {
>> -			/* gap */
>> -			btf_verifier_log(env, "Unsupported section found");
>> +		gap = secs[i].off - total;
>> +		if (gap >= 4) {
>> +			/* gap larger than alignment gap */
>> +			btf_verifier_log(env, "Unsupported section gap found");
>>  			return -EINVAL;
> 
> this sems to break several btf header tests with:
> 
> 	do_test_raw:PASS:check 0 nsec
> 	do_test_raw:FAIL:check expected err_str:Unsupported section found
> 
> 	magic: 0xeb9f
> 	version: 1
> 	flags: 0x0
> 	hdr_len: 40
> 	type_off: 4
> 	type_len: 16
> 	str_off: 16
> 	str_len: 5
> 	btf_total_size: 61
> 	Unsupported section gap found
> 	#23/48   btf/btf_header test. Gap between hdr and type:FAIL
> 
>

thanks for spotting this Jiri! I've reworked the logic and the
messages for v3 (in progress), and these pass now.

Alan

> jirka
> 
>>  		}
>>  		if (total > secs[i].off) {
>> @@ -5230,7 +5288,7 @@ static int btf_check_sec_info(struct btf_verifier_env *env,
>>  					 "Total section length too long");
>>  			return -EINVAL;
>>  		}
>> -		total += secs[i].len;
>> +		total += secs[i].len + gap;
>>  	}
>>  
>>  	/* There is data other than hdr and known sections */
>> @@ -5293,7 +5351,7 @@ static int btf_parse_hdr(struct btf_verifier_env *env)
>>  		return -ENOTSUPP;
>>  	}
>>  
>> -	if (hdr->flags) {
>> +	if (hdr->flags & ~(BTF_FLAG_CRC_SET | BTF_FLAG_BASE_CRC_SET)) {
>>  		btf_verifier_log(env, "Unsupported flags");
>>  		return -ENOTSUPP;
>>  	}
>> @@ -5530,6 +5588,10 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
>>  	if (err)
>>  		goto errout;
>>  
>> +	err = btf_parse_kind_layout_sec(env);
>> +	if (err)
>> +		goto errout;
>> +
>>  	err = btf_parse_type_sec(env);
>>  	if (err)
>>  		goto errout;
>> -- 
>> 2.39.3
>>
Andrii Nakryiko June 22, 2023, 10:03 p.m. UTC | #3
On Fri, Jun 16, 2023 at 10:18 AM Alan Maguire <alan.maguire@oracle.com> wrote:
>
> Use kind layout to parse BTF with unknown kinds that have a
> kind layout representation.
>
> Validate kind layout if present, and use it to parse BTF with
> unrecognized kinds. Reject BTF that contains a type
> of a kind that is not optional.
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
>  kernel/bpf/btf.c | 102 +++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 82 insertions(+), 20 deletions(-)
>
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index bd2cac057928..ffe3926ea051 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -257,6 +257,7 @@ struct btf {
>         struct btf_kfunc_set_tab *kfunc_set_tab;
>         struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab;
>         struct btf_struct_metas *struct_meta_tab;
> +       struct btf_kind_layout *kind_layout;
>
>         /* split BTF support */
>         struct btf *base_btf;
> @@ -4965,22 +4966,41 @@ static s32 btf_check_meta(struct btf_verifier_env *env,
>                 return -EINVAL;
>         }
>
> -       if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX ||
> -           BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
> -               btf_verifier_log(env, "[%u] Invalid kind:%u",
> -                                env->log_type_id, BTF_INFO_KIND(t->info));
> -               return -EINVAL;
> -       }
> -
>         if (!btf_name_offset_valid(env->btf, t->name_off)) {
>                 btf_verifier_log(env, "[%u] Invalid name_offset:%u",
>                                  env->log_type_id, t->name_off);
>                 return -EINVAL;
>         }
>
> -       var_meta_size = btf_type_ops(t)->check_meta(env, t, meta_left);
> -       if (var_meta_size < 0)
> -               return var_meta_size;
> +       if (BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
> +               btf_verifier_log(env, "[%u] Invalid kind:%u",
> +                                env->log_type_id, BTF_INFO_KIND(t->info));
> +               return -EINVAL;
> +       }
> +
> +       if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX && env->btf->kind_layout &&
> +           (BTF_INFO_KIND(t->info) * sizeof(struct btf_kind_layout)) <
> +            env->btf->hdr.kind_layout_len) {
> +               struct btf_kind_layout *k = &env->btf->kind_layout[BTF_INFO_KIND(t->info)];
> +
> +               if (!(k->flags & BTF_KIND_LAYOUT_OPTIONAL)) {

same question as on previous patch, should kernel trust and handle
OPTIONAL flag?

I'd say let's drop it for now, doesn't seem worth the trouble

> +                       btf_verifier_log(env, "[%u] unknown but required kind %u",
> +                                        env->log_type_id,
> +                                        BTF_INFO_KIND(t->info));
> +                       return -EINVAL;
> +               }
> +               var_meta_size = sizeof(struct btf_type);
> +               var_meta_size += k->info_sz + (btf_type_vlen(t) * k->elem_sz);
> +       } else {
> +               if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX) {
> +                       btf_verifier_log(env, "[%u] Invalid kind:%u",
> +                                        env->log_type_id, BTF_INFO_KIND(t->info));
> +                       return -EINVAL;
> +               }
> +               var_meta_size = btf_type_ops(t)->check_meta(env, t, meta_left);
> +               if (var_meta_size < 0)
> +                       return var_meta_size;
> +       }
>
>         meta_left -= var_meta_size;
>
> @@ -5155,7 +5175,8 @@ static int btf_parse_str_sec(struct btf_verifier_env *env)
>         start = btf->nohdr_data + hdr->str_off;
>         end = start + hdr->str_len;
>
> -       if (end != btf->data + btf->data_size) {
> +       if (hdr->hdr_len < sizeof(struct btf_header) &&
> +           end != btf->data + btf->data_size) {
>                 btf_verifier_log(env, "String section is not at the end");
>                 return -EINVAL;
>         }
> @@ -5176,9 +5197,41 @@ static int btf_parse_str_sec(struct btf_verifier_env *env)
>         return 0;
>  }
>
> +static int btf_parse_kind_layout_sec(struct btf_verifier_env *env)
> +{
> +       const struct btf_header *hdr = &env->btf->hdr;
> +       struct btf *btf = env->btf;
> +       void *start, *end;
> +
> +       if (hdr->hdr_len < sizeof(struct btf_header) ||
> +           hdr->kind_layout_len == 0)

let's make sure that kind_layout_off is zero in this case as well

> +               return 0;
> +
> +       /* Kind layout section must align to 4 bytes */
> +       if (hdr->kind_layout_off & (sizeof(u32) - 1)) {
> +               btf_verifier_log(env, "Unaligned kind_layout_off");
> +               return -EINVAL;
> +       }
> +       start = btf->nohdr_data + hdr->kind_layout_off;
> +       end = start + hdr->kind_layout_len;
> +
> +       if (hdr->kind_layout_len < sizeof(struct btf_kind_layout)) {

same as on libbpf side, more generally kind_layout_len should be a
multiple of sizeof(struct btf_kind_layout)

> +               btf_verifier_log(env, "Kind layout section is too small");
> +               return -EINVAL;
> +       }
> +       if (end != btf->data + btf->data_size) {
> +               btf_verifier_log(env, "Kind layout section is not at the end");
> +               return -EINVAL;
> +       }
> +       btf->kind_layout = start;
> +
> +       return 0;
> +}
> +

[...]
diff mbox series

Patch

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index bd2cac057928..ffe3926ea051 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -257,6 +257,7 @@  struct btf {
 	struct btf_kfunc_set_tab *kfunc_set_tab;
 	struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab;
 	struct btf_struct_metas *struct_meta_tab;
+	struct btf_kind_layout *kind_layout;
 
 	/* split BTF support */
 	struct btf *base_btf;
@@ -4965,22 +4966,41 @@  static s32 btf_check_meta(struct btf_verifier_env *env,
 		return -EINVAL;
 	}
 
-	if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX ||
-	    BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
-		btf_verifier_log(env, "[%u] Invalid kind:%u",
-				 env->log_type_id, BTF_INFO_KIND(t->info));
-		return -EINVAL;
-	}
-
 	if (!btf_name_offset_valid(env->btf, t->name_off)) {
 		btf_verifier_log(env, "[%u] Invalid name_offset:%u",
 				 env->log_type_id, t->name_off);
 		return -EINVAL;
 	}
 
-	var_meta_size = btf_type_ops(t)->check_meta(env, t, meta_left);
-	if (var_meta_size < 0)
-		return var_meta_size;
+	if (BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
+		btf_verifier_log(env, "[%u] Invalid kind:%u",
+				 env->log_type_id, BTF_INFO_KIND(t->info));
+		return -EINVAL;
+	}
+
+	if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX && env->btf->kind_layout &&
+	    (BTF_INFO_KIND(t->info) * sizeof(struct btf_kind_layout)) <
+	     env->btf->hdr.kind_layout_len) {
+		struct btf_kind_layout *k = &env->btf->kind_layout[BTF_INFO_KIND(t->info)];
+
+		if (!(k->flags & BTF_KIND_LAYOUT_OPTIONAL)) {
+			btf_verifier_log(env, "[%u] unknown but required kind %u",
+					 env->log_type_id,
+					 BTF_INFO_KIND(t->info));
+			return -EINVAL;
+		}
+		var_meta_size = sizeof(struct btf_type);
+		var_meta_size += k->info_sz + (btf_type_vlen(t) * k->elem_sz);
+	} else {
+		if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX) {
+			btf_verifier_log(env, "[%u] Invalid kind:%u",
+					 env->log_type_id, BTF_INFO_KIND(t->info));
+			return -EINVAL;
+		}
+		var_meta_size = btf_type_ops(t)->check_meta(env, t, meta_left);
+		if (var_meta_size < 0)
+			return var_meta_size;
+	}
 
 	meta_left -= var_meta_size;
 
@@ -5155,7 +5175,8 @@  static int btf_parse_str_sec(struct btf_verifier_env *env)
 	start = btf->nohdr_data + hdr->str_off;
 	end = start + hdr->str_len;
 
-	if (end != btf->data + btf->data_size) {
+	if (hdr->hdr_len < sizeof(struct btf_header) &&
+	    end != btf->data + btf->data_size) {
 		btf_verifier_log(env, "String section is not at the end");
 		return -EINVAL;
 	}
@@ -5176,9 +5197,41 @@  static int btf_parse_str_sec(struct btf_verifier_env *env)
 	return 0;
 }
 
+static int btf_parse_kind_layout_sec(struct btf_verifier_env *env)
+{
+	const struct btf_header *hdr = &env->btf->hdr;
+	struct btf *btf = env->btf;
+	void *start, *end;
+
+	if (hdr->hdr_len < sizeof(struct btf_header) ||
+	    hdr->kind_layout_len == 0)
+		return 0;
+
+	/* Kind layout section must align to 4 bytes */
+	if (hdr->kind_layout_off & (sizeof(u32) - 1)) {
+		btf_verifier_log(env, "Unaligned kind_layout_off");
+		return -EINVAL;
+	}
+	start = btf->nohdr_data + hdr->kind_layout_off;
+	end = start + hdr->kind_layout_len;
+
+	if (hdr->kind_layout_len < sizeof(struct btf_kind_layout)) {
+		btf_verifier_log(env, "Kind layout section is too small");
+		return -EINVAL;
+	}
+	if (end != btf->data + btf->data_size) {
+		btf_verifier_log(env, "Kind layout section is not at the end");
+		return -EINVAL;
+	}
+	btf->kind_layout = start;
+
+	return 0;
+}
+
 static const size_t btf_sec_info_offset[] = {
 	offsetof(struct btf_header, type_off),
 	offsetof(struct btf_header, str_off),
+	offsetof(struct btf_header, kind_layout_off),
 };
 
 static int btf_sec_info_cmp(const void *a, const void *b)
@@ -5193,32 +5246,37 @@  static int btf_check_sec_info(struct btf_verifier_env *env,
 			      u32 btf_data_size)
 {
 	struct btf_sec_info secs[ARRAY_SIZE(btf_sec_info_offset)];
-	u32 total, expected_total, i;
+	u32 nr_secs = ARRAY_SIZE(btf_sec_info_offset);
+	u32 total, expected_total, gap, i;
 	const struct btf_header *hdr;
 	const struct btf *btf;
 
 	btf = env->btf;
 	hdr = &btf->hdr;
 
+	if (hdr->hdr_len < sizeof(struct btf_header))
+		nr_secs--;
+
 	/* Populate the secs from hdr */
-	for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++)
+	for (i = 0; i < nr_secs; i++)
 		secs[i] = *(struct btf_sec_info *)((void *)hdr +
 						   btf_sec_info_offset[i]);
 
-	sort(secs, ARRAY_SIZE(btf_sec_info_offset),
+	sort(secs, nr_secs,
 	     sizeof(struct btf_sec_info), btf_sec_info_cmp, NULL);
 
 	/* Check for gaps and overlap among sections */
 	total = 0;
 	expected_total = btf_data_size - hdr->hdr_len;
-	for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++) {
+	for (i = 0; i < nr_secs; i++) {
 		if (expected_total < secs[i].off) {
 			btf_verifier_log(env, "Invalid section offset");
 			return -EINVAL;
 		}
-		if (total < secs[i].off) {
-			/* gap */
-			btf_verifier_log(env, "Unsupported section found");
+		gap = secs[i].off - total;
+		if (gap >= 4) {
+			/* gap larger than alignment gap */
+			btf_verifier_log(env, "Unsupported section gap found");
 			return -EINVAL;
 		}
 		if (total > secs[i].off) {
@@ -5230,7 +5288,7 @@  static int btf_check_sec_info(struct btf_verifier_env *env,
 					 "Total section length too long");
 			return -EINVAL;
 		}
-		total += secs[i].len;
+		total += secs[i].len + gap;
 	}
 
 	/* There is data other than hdr and known sections */
@@ -5293,7 +5351,7 @@  static int btf_parse_hdr(struct btf_verifier_env *env)
 		return -ENOTSUPP;
 	}
 
-	if (hdr->flags) {
+	if (hdr->flags & ~(BTF_FLAG_CRC_SET | BTF_FLAG_BASE_CRC_SET)) {
 		btf_verifier_log(env, "Unsupported flags");
 		return -ENOTSUPP;
 	}
@@ -5530,6 +5588,10 @@  static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
 	if (err)
 		goto errout;
 
+	err = btf_parse_kind_layout_sec(env);
+	if (err)
+		goto errout;
+
 	err = btf_parse_type_sec(env);
 	if (err)
 		goto errout;