diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 4bcf76a9bb06..cd38aca4cfc0 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -28,6 +28,10 @@ int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
 			const struct bpf_prog *prog);
 
 bool bpf_lsm_is_sleepable_hook(u32 btf_id);
+bool bpf_lsm_can_ret_pos_value(u32 btf_id);
+bool bpf_lsm_can_ret_only_one_as_pos_value(u32 btf_id);
+bool bpf_lsm_cannot_ret_zero(u32 btf_id);
+bool bpf_lsm_cannot_ret_neg_value(u32 btf_id);
 
 static inline struct bpf_storage_blob *bpf_inode(
 	const struct inode *inode)
@@ -51,6 +55,26 @@ static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id)
 	return false;
 }
 
+static inline bool bpf_lsm_can_ret_pos_value(u32 btf_id)
+{
+	return false;
+}
+
+static inline bool bpf_lsm_can_ret_only_one_as_pos_value(u32 btf_id)
+{
+	return false;
+}
+
+static inline bool bpf_lsm_cannot_ret_zero(u32 btf_id)
+{
+	return false;
+}
+
+static inline bool bpf_lsm_cannot_ret_neg_value(u32 btf_id)
+{
+	return false;
+}
+
 static inline int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
 				      const struct bpf_prog *prog)
 {
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index d6c9b3705f24..3dcb70b2f978 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -348,6 +348,62 @@ bool bpf_lsm_is_sleepable_hook(u32 btf_id)
 	return btf_id_set_contains(&sleepable_lsm_hooks, btf_id);
 }
 
+/* The set of hooks which are allowed to return a positive value. */
+BTF_SET_START(pos_ret_value_lsm_hooks)
+BTF_ID(func, bpf_lsm_vm_enough_memory)
+BTF_ID(func, bpf_lsm_inode_getsecurity)
+BTF_ID(func, bpf_lsm_inode_listsecurity)
+BTF_ID(func, bpf_lsm_inode_need_killpriv)
+BTF_ID(func, bpf_lsm_inode_copy_up_xattr)
+BTF_ID(func, bpf_lsm_getprocattr)
+BTF_ID(func, bpf_lsm_setprocattr)
+BTF_ID(func, bpf_lsm_xfrm_state_pol_flow_match)
+BTF_ID(func, bpf_lsm_key_getsecurity)
+BTF_ID(func, bpf_lsm_ismaclabel)
+BTF_ID(func, bpf_lsm_audit_rule_known)
+BTF_ID(func, bpf_lsm_audit_rule_match)
+BTF_SET_END(pos_ret_value_lsm_hooks)
+
+bool bpf_lsm_can_ret_pos_value(u32 btf_id)
+{
+	return btf_id_set_contains(&pos_ret_value_lsm_hooks, btf_id);
+}
+
+BTF_SET_START(one_ret_value_lsm_hooks)
+BTF_ID(func, bpf_lsm_vm_enough_memory)
+BTF_ID(func, bpf_lsm_inode_copy_up_xattr)
+BTF_ID(func, bpf_lsm_xfrm_state_pol_flow_match)
+BTF_ID(func, bpf_lsm_ismaclabel)
+BTF_ID(func, bpf_lsm_audit_rule_known)
+BTF_ID(func, bpf_lsm_audit_rule_match)
+BTF_SET_END(one_ret_value_lsm_hooks)
+
+bool bpf_lsm_can_ret_only_one_as_pos_value(u32 btf_id)
+{
+	return btf_id_set_contains(&one_ret_value_lsm_hooks, btf_id);
+}
+
+/* The set of hooks which are not allowed to return zero. */
+BTF_SET_START(not_zero_ret_value_lsm_hooks)
+BTF_ID(func, bpf_lsm_inode_init_security)
+BTF_SET_END(not_zero_ret_value_lsm_hooks)
+
+bool bpf_lsm_cannot_ret_zero(u32 btf_id)
+{
+	return btf_id_set_contains(&not_zero_ret_value_lsm_hooks, btf_id);
+}
+
+/* The set of hooks which are not allowed to return a negative value. */
+BTF_SET_START(not_neg_ret_value_lsm_hooks)
+BTF_ID(func, bpf_lsm_vm_enough_memory)
+BTF_ID(func, bpf_lsm_audit_rule_known)
+BTF_SET_END(not_neg_ret_value_lsm_hooks)
+
+bool bpf_lsm_cannot_ret_neg_value(u32 btf_id)
+{
+	return btf_id_set_contains(&not_neg_ret_value_lsm_hooks, btf_id);
+}
+
 const struct bpf_prog_ops lsm_prog_ops = {
 };
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7f0a9f6cb889..099c1bf88fed 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -10623,9 +10623,38 @@ static int check_return_code(struct bpf_verifier_env *env)
 
 	case BPF_PROG_TYPE_LSM:
 		if (env->prog->expected_attach_type != BPF_LSM_CGROUP) {
-			/* Regular BPF_PROG_TYPE_LSM programs can return
-			 * any value.
-			 */
+			/* < 0 */
+			if (tnum_in(tnum_range((u64)(~0) << 31, (u64)(~0)), reg->var_off)) {
+				if (bpf_lsm_cannot_ret_neg_value(env->prog->aux->attach_btf_id)) {
+					verbose(env, "Invalid R0, cannot return negative value\n");
+					return -EINVAL;
+				}
+			/* = 0 */
+			} else if (tnum_equals_const(reg->var_off, 0)) {
+				if (bpf_lsm_cannot_ret_zero(env->prog->aux->attach_btf_id)) {
+					verbose(env, "Invalid R0, cannot return zero value\n");
+					return -EINVAL;
+				}
+			/* = 1 */
+			} else if (tnum_equals_const(reg->var_off, 1)) {
+				if (!bpf_lsm_can_ret_pos_value(env->prog->aux->attach_btf_id)) {
+					verbose(env, "Invalid R0, cannot return positive value\n");
+					return -EINVAL;
+				}
+			/* > 1 */
+			} else {
+				if (!bpf_lsm_can_ret_pos_value(env->prog->aux->attach_btf_id)) {
+					verbose(env, "Invalid R0, cannot return positive value\n");
+					return -EINVAL;
+				}
+
+				if (bpf_lsm_can_ret_only_one_as_pos_value(env->prog->aux->attach_btf_id)) {
+					verbose(env,
+						"Invalid R0, can return only one as positive value\n");
+					return -EINVAL;
+				}
+			}
+
 			return 0;
 		}
 		if (!env->prog->aux->attach_func_proto->type) {
