diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 369faeddf1df..96cd24020a38 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -3439,7 +3439,7 @@ static s32 btf_func_check_meta(struct btf_verifier_env *env,
 		return -EINVAL;
 	}
 
-	if (btf_type_vlen(t) > BTF_FUNC_GLOBAL) {
+	if (btf_type_vlen(t) > BTF_FUNC_EXTERN) {
 		btf_verifier_log_type(env, t, "Invalid func linkage");
 		return -EINVAL;
 	}
@@ -3532,7 +3532,7 @@ static s32 btf_datasec_check_meta(struct btf_verifier_env *env,
 				  u32 meta_left)
 {
 	const struct btf_var_secinfo *vsi;
-	u64 last_vsi_end_off = 0, sum = 0;
+	u64 last_vsi_end_off = 0;
 	u32 i, meta_needed;
 
 	meta_needed = btf_type_vlen(t) * sizeof(*vsi);
@@ -3543,11 +3543,6 @@ static s32 btf_datasec_check_meta(struct btf_verifier_env *env,
 		return -EINVAL;
 	}
 
-	if (!t->size) {
-		btf_verifier_log_type(env, t, "size == 0");
-		return -EINVAL;
-	}
-
 	if (btf_type_kflag(t)) {
 		btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
 		return -EINVAL;
@@ -3569,19 +3564,13 @@ static s32 btf_datasec_check_meta(struct btf_verifier_env *env,
 			return -EINVAL;
 		}
 
-		if (vsi->offset < last_vsi_end_off || vsi->offset >= t->size) {
+		if (vsi->offset < last_vsi_end_off) {
 			btf_verifier_log_vsi(env, t, vsi,
 					     "Invalid offset");
 			return -EINVAL;
 		}
 
-		if (!vsi->size || vsi->size > t->size) {
-			btf_verifier_log_vsi(env, t, vsi,
-					     "Invalid size");
-			return -EINVAL;
-		}
-
-		last_vsi_end_off = vsi->offset + vsi->size;
+		last_vsi_end_off = (u64)vsi->offset + vsi->size;
 		if (last_vsi_end_off > t->size) {
 			btf_verifier_log_vsi(env, t, vsi,
 					     "Invalid offset+size");
@@ -3589,12 +3578,6 @@ static s32 btf_datasec_check_meta(struct btf_verifier_env *env,
 		}
 
 		btf_verifier_log_vsi(env, t, vsi, NULL);
-		sum += vsi->size;
-	}
-
-	if (t->size < sum) {
-		btf_verifier_log_type(env, t, "Invalid btf_info size");
-		return -EINVAL;
 	}
 
 	return meta_needed;
@@ -3611,9 +3594,28 @@ static int btf_datasec_resolve(struct btf_verifier_env *env,
 		u32 var_type_id = vsi->type, type_id, type_size = 0;
 		const struct btf_type *var_type = btf_type_by_id(env->btf,
 								 var_type_id);
-		if (!var_type || !btf_type_is_var(var_type)) {
+		if (!var_type) {
+			btf_verifier_log_vsi(env, v->t, vsi,
+					     "type not found");
+			return -EINVAL;
+		}
+
+		if (btf_type_is_func(var_type)) {
+			if (vsi->size || vsi->offset) {
+				btf_verifier_log_vsi(env, v->t, vsi,
+						     "Invalid size/offset");
+				return -EINVAL;
+			}
+			continue;
+		} else if (btf_type_is_var(var_type)) {
+			if (!vsi->size) {
+				btf_verifier_log_vsi(env, v->t, vsi,
+						     "Invalid size");
+				return -EINVAL;
+			}
+		} else {
 			btf_verifier_log_vsi(env, v->t, vsi,
-					     "Not a VAR kind member");
+					     "Neither a VAR nor a FUNC");
 			return -EINVAL;
 		}
 
@@ -3849,9 +3851,11 @@ static int btf_func_check(struct btf_verifier_env *env,
 	const struct btf_param *args;
 	const struct btf *btf;
 	u16 nr_args, i;
+	bool is_extern;
 
 	btf = env->btf;
 	proto_type = btf_type_by_id(btf, t->type);
+	is_extern = btf_type_vlen(t) == BTF_FUNC_EXTERN;
 
 	if (!proto_type || !btf_type_is_func_proto(proto_type)) {
 		btf_verifier_log_type(env, t, "Invalid type_id");
@@ -3861,7 +3865,7 @@ static int btf_func_check(struct btf_verifier_env *env,
 	args = (const struct btf_param *)(proto_type + 1);
 	nr_args = btf_type_vlen(proto_type);
 	for (i = 0; i < nr_args; i++) {
-		if (!args[i].name_off && args[i].type) {
+		if (!is_extern && !args[i].name_off && args[i].type) {
 			btf_verifier_log_type(env, t, "Invalid arg#%u", i + 1);
 			return -EINVAL;
 		}
diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index 0457ae32b270..e469482833b2 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -498,7 +498,7 @@ static struct btf_raw_test raw_tests[] = {
 	.value_type_id = 7,
 	.max_entries = 1,
 	.btf_load_err = true,
-	.err_str = "Invalid size",
+	.err_str = "Invalid offset+size",
 },
 {
 	.descr = "global data test #10, invalid var size",
@@ -696,7 +696,7 @@ static struct btf_raw_test raw_tests[] = {
 	.err_str = "Invalid offset",
 },
 {
-	.descr = "global data test #15, not var kind",
+	.descr = "global data test #15, not var/func kind",
 	.raw_types = {
 		/* int */
 		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),	/* [1] */
@@ -716,7 +716,7 @@ static struct btf_raw_test raw_tests[] = {
 	.value_type_id = 3,
 	.max_entries = 1,
 	.btf_load_err = true,
-	.err_str = "Not a VAR kind member",
+	.err_str = "Neither a VAR nor a FUNC",
 },
 {
 	.descr = "global data test #16, invalid var referencing sec",
@@ -2803,7 +2803,7 @@ static struct btf_raw_test raw_tests[] = {
 			BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
 			BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
 		/* void func(int a, unsigned int b) */
-		BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 3), 	/* [4] */
+		BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 3), 3), 	/* [4] */
 		BTF_END_RAW,
 	},
 	.str_sec = "\0a\0b\0func",
@@ -3531,6 +3531,152 @@ static struct btf_raw_test raw_tests[] = {
 	.max_entries = 1,
 },
 
+{
+	.descr = "datasec: func only",
+	.raw_types = {
+		/* int */
+		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),	/* [1] */
+		/* void (*)(void) */
+		BTF_FUNC_PROTO_ENC(0, 0),		/* [2] */
+		BTF_FUNC_ENC(NAME_NTH(1), 2),		/* [3] */
+		BTF_FUNC_ENC(NAME_NTH(2), 2),		/* [4] */
+		/* .ksym section */
+		BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 2), 0), /* [5] */
+		BTF_VAR_SECINFO_ENC(3, 0, 0),
+		BTF_VAR_SECINFO_ENC(4, 0, 0),
+		BTF_END_RAW,
+	},
+	BTF_STR_SEC("\0foo1\0foo2\0.ksym\0"),
+	.map_type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.key_type_id = 1,
+	.value_type_id = 1,
+	.max_entries = 1,
+},
+
+{
+	.descr = "datasec: func and var",
+	.raw_types = {
+		/* int */
+		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),	/* [1] */
+		/* void (*)(void) */
+		BTF_FUNC_PROTO_ENC(0, 0),		/* [2] */
+		BTF_FUNC_ENC(NAME_NTH(1), 2),		/* [3] */
+		BTF_FUNC_ENC(NAME_NTH(2), 2),		/* [4] */
+		/* int */
+		BTF_VAR_ENC(NAME_NTH(4), 1, 0),		/* [5] */
+		BTF_VAR_ENC(NAME_NTH(5), 1, 0),		/* [6] */
+		/* .ksym section */
+		BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 4), 8), /* [7] */
+		BTF_VAR_SECINFO_ENC(3, 0, 0),
+		BTF_VAR_SECINFO_ENC(4, 0, 0),
+		BTF_VAR_SECINFO_ENC(5, 0, 4),
+		BTF_VAR_SECINFO_ENC(6, 4, 4),
+		BTF_END_RAW,
+	},
+	BTF_STR_SEC("\0foo1\0foo2\0.ksym\0a\0b\0"),
+	.map_type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.key_type_id = 1,
+	.value_type_id = 1,
+	.max_entries = 1,
+},
+
+{
+	.descr = "datasec: func and var, invalid size/offset for func",
+	.raw_types = {
+		/* int */
+		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),	/* [1] */
+		/* void (*)(void) */
+		BTF_FUNC_PROTO_ENC(0, 0),		/* [2] */
+		BTF_FUNC_ENC(NAME_NTH(1), 2),		/* [3] */
+		BTF_FUNC_ENC(NAME_NTH(2), 2),		/* [4] */
+		/* int */
+		BTF_VAR_ENC(NAME_NTH(4), 1, 0),		/* [5] */
+		BTF_VAR_ENC(NAME_NTH(5), 1, 0),		/* [6] */
+		/* .ksym section */
+		BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 4), 8), /* [7] */
+		BTF_VAR_SECINFO_ENC(3, 0, 0),
+		BTF_VAR_SECINFO_ENC(5, 0, 4),
+		BTF_VAR_SECINFO_ENC(4, 4, 0),	/* func has non zero vsi->offset */
+		BTF_VAR_SECINFO_ENC(6, 4, 4),
+		BTF_END_RAW,
+	},
+	BTF_STR_SEC("\0foo1\0foo2\0.ksym\0a\0b\0"),
+	.map_type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.key_type_id = 1,
+	.value_type_id = 1,
+	.max_entries = 1,
+	.btf_load_err = true,
+	.err_str = "Invalid size/offset",
+},
+
+{
+	.descr = "datasec: func and var, datasec size 0",
+	.raw_types = {
+		/* int */
+		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),	/* [1] */
+		/* void (*)(void) */
+		BTF_FUNC_PROTO_ENC(0, 0),		/* [2] */
+		BTF_FUNC_ENC(NAME_NTH(1), 2),		/* [3] */
+		BTF_FUNC_ENC(NAME_NTH(2), 2),		/* [4] */
+		/* int */
+		BTF_VAR_ENC(NAME_NTH(4), 1, 0),		/* [5] */
+		BTF_VAR_ENC(NAME_NTH(5), 1, 0),		/* [6] */
+		/* .ksym section */
+		BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 4), 0), /* [7] */
+		BTF_VAR_SECINFO_ENC(3, 0, 0),
+		BTF_VAR_SECINFO_ENC(4, 0, 0),
+		BTF_VAR_SECINFO_ENC(5, 0, 4),
+		BTF_VAR_SECINFO_ENC(6, 4, 4),
+		BTF_END_RAW,
+	},
+	BTF_STR_SEC("\0foo1\0foo2\0.ksym\0a\0b\0"),
+	.map_type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.key_type_id = 1,
+	.value_type_id = 1,
+	.max_entries = 1,
+	.btf_load_err = true,
+	.err_str = "Invalid offset+size",
+},
+
+{
+	.descr = "datasec: func and var, zero vsi->size for var",
+	.raw_types = {
+		/* int */
+		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),	/* [1] */
+		/* void (*)(void) */
+		BTF_FUNC_PROTO_ENC(0, 0),		/* [2] */
+		BTF_FUNC_ENC(NAME_NTH(1), 2),		/* [3] */
+		BTF_FUNC_ENC(NAME_NTH(2), 2),		/* [4] */
+		/* int */
+		BTF_VAR_ENC(NAME_NTH(4), 1, 0),		/* [5] */
+		BTF_VAR_ENC(NAME_NTH(5), 1, 0),		/* [6] */
+		/* .ksym section */
+		BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 4), 8), /* [7] */
+		BTF_VAR_SECINFO_ENC(3, 0, 0),
+		BTF_VAR_SECINFO_ENC(4, 0, 0),
+		BTF_VAR_SECINFO_ENC(5, 0, 0),	/* var has zero vsi->size */
+		BTF_VAR_SECINFO_ENC(6, 0, 4),
+		BTF_END_RAW,
+	},
+	BTF_STR_SEC("\0foo1\0foo2\0.ksym\0a\0b\0"),
+	.map_type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.key_type_id = 1,
+	.value_type_id = 1,
+	.max_entries = 1,
+	.btf_load_err = true,
+	.err_str = "Invalid size",
+},
+
 {
 	.descr = "float test #1, well-formed",
 	.raw_types = {
