static bool is_ptr_cast_function(enum bpf_func_id func_id)
 {
        return func_id == BPF_FUNC_tcp_sock ||
-               func_id == BPF_FUNC_sk_fullsock;
+               func_id == BPF_FUNC_sk_fullsock ||
+               func_id == BPF_FUNC_skc_to_tcp_sock ||
+               func_id == BPF_FUNC_skc_to_tcp6_sock ||
+               func_id == BPF_FUNC_skc_to_udp6_sock ||
+               func_id == BPF_FUNC_skc_to_tcp_timewait_sock ||
+               func_id == BPF_FUNC_skc_to_tcp_request_sock;
 }
 
 /* string representation of 'enum bpf_reg_type' */
 
 struct bpf_reg_types {
        const enum bpf_reg_type types[10];
+       u32 *btf_id;
 };
 
 static const struct bpf_reg_types map_key_value_types = {
        },
 };
 
+static const struct bpf_reg_types btf_id_sock_common_types = {
+       .types = {
+               PTR_TO_SOCK_COMMON,
+               PTR_TO_SOCKET,
+               PTR_TO_TCP_SOCK,
+               PTR_TO_XDP_SOCK,
+               PTR_TO_BTF_ID,
+       },
+       .btf_id = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
+};
+
 static const struct bpf_reg_types mem_types = {
        .types = {
                PTR_TO_STACK,
        [ARG_PTR_TO_CTX]                = &context_types,
        [ARG_PTR_TO_CTX_OR_NULL]        = &context_types,
        [ARG_PTR_TO_SOCK_COMMON]        = &sock_types,
+       [ARG_PTR_TO_BTF_ID_SOCK_COMMON] = &btf_id_sock_common_types,
        [ARG_PTR_TO_SOCKET]             = &fullsock_types,
        [ARG_PTR_TO_SOCKET_OR_NULL]     = &fullsock_types,
        [ARG_PTR_TO_BTF_ID]             = &btf_ptr_types,
 
 found:
        if (type == PTR_TO_BTF_ID) {
+               if (!arg_btf_id) {
+                       if (!compatible->btf_id) {
+                               verbose(env, "verifier internal error: missing arg compatible BTF ID\n");
+                               return -EFAULT;
+                       }
+                       arg_btf_id = compatible->btf_id;
+               }
+
                if (!btf_struct_ids_match(&env->log, reg->off, reg->btf_id,
                                          *arg_btf_id)) {
                        verbose(env, "R%d is of type %s but %s is expected\n",
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++)
+       for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
                if (fn->arg_type[i] == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i])
                        return false;
 
+               if (fn->arg_type[i] != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i])
+                       return false;
+       }
+
        return true;
 }
 
 
 #include <net/transp_v6.h>
 #include <linux/btf_ids.h>
 
+static const struct bpf_func_proto *
+bpf_sk_base_func_proto(enum bpf_func_id func_id);
+
 int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len)
 {
        if (in_compat_syscall()) {
                        return NULL;
                }
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
        case BPF_FUNC_perf_event_output:
                return &bpf_skb_event_output_proto;
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
                return &bpf_sk_assign_proto;
 #endif
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
                return &bpf_tcp_gen_syncookie_proto;
 #endif
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
                return &bpf_tcp_sock_proto;
 #endif /* CONFIG_INET */
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
                return &bpf_get_cgroup_classid_curr_proto;
 #endif
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
                return &bpf_skc_lookup_tcp_proto;
 #endif
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
        case BPF_FUNC_skb_load_bytes:
                return &bpf_flow_dissector_load_bytes_proto;
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
        case BPF_FUNC_skb_under_cgroup:
                return &bpf_skb_under_cgroup_proto;
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
        case BPF_FUNC_sk_release:
                return &bpf_sk_release_proto;
        default:
-               return bpf_base_func_proto(func_id);
+               return bpf_sk_base_func_proto(func_id);
        }
 }
 
        .func                   = bpf_skc_to_tcp6_sock,
        .gpl_only               = false,
        .ret_type               = RET_PTR_TO_BTF_ID_OR_NULL,
-       .arg1_type              = ARG_PTR_TO_BTF_ID,
-       .arg1_btf_id            = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
+       .arg1_type              = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
        .ret_btf_id             = &btf_sock_ids[BTF_SOCK_TYPE_TCP6],
 };
 
        .func                   = bpf_skc_to_tcp_sock,
        .gpl_only               = false,
        .ret_type               = RET_PTR_TO_BTF_ID_OR_NULL,
-       .arg1_type              = ARG_PTR_TO_BTF_ID,
-       .arg1_btf_id            = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
+       .arg1_type              = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
        .ret_btf_id             = &btf_sock_ids[BTF_SOCK_TYPE_TCP],
 };
 
        .func                   = bpf_skc_to_tcp_timewait_sock,
        .gpl_only               = false,
        .ret_type               = RET_PTR_TO_BTF_ID_OR_NULL,
-       .arg1_type              = ARG_PTR_TO_BTF_ID,
-       .arg1_btf_id            = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
+       .arg1_type              = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
        .ret_btf_id             = &btf_sock_ids[BTF_SOCK_TYPE_TCP_TW],
 };
 
        .func                   = bpf_skc_to_tcp_request_sock,
        .gpl_only               = false,
        .ret_type               = RET_PTR_TO_BTF_ID_OR_NULL,
-       .arg1_type              = ARG_PTR_TO_BTF_ID,
-       .arg1_btf_id            = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
+       .arg1_type              = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
        .ret_btf_id             = &btf_sock_ids[BTF_SOCK_TYPE_TCP_REQ],
 };
 
        .func                   = bpf_skc_to_udp6_sock,
        .gpl_only               = false,
        .ret_type               = RET_PTR_TO_BTF_ID_OR_NULL,
-       .arg1_type              = ARG_PTR_TO_BTF_ID,
-       .arg1_btf_id            = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
+       .arg1_type              = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
        .ret_btf_id             = &btf_sock_ids[BTF_SOCK_TYPE_UDP6],
 };
+
+static const struct bpf_func_proto *
+bpf_sk_base_func_proto(enum bpf_func_id func_id)
+{
+       const struct bpf_func_proto *func;
+
+       switch (func_id) {
+       case BPF_FUNC_skc_to_tcp6_sock:
+               func = &bpf_skc_to_tcp6_sock_proto;
+               break;
+       case BPF_FUNC_skc_to_tcp_sock:
+               func = &bpf_skc_to_tcp_sock_proto;
+               break;
+       case BPF_FUNC_skc_to_tcp_timewait_sock:
+               func = &bpf_skc_to_tcp_timewait_sock_proto;
+               break;
+       case BPF_FUNC_skc_to_tcp_request_sock:
+               func = &bpf_skc_to_tcp_request_sock_proto;
+               break;
+       case BPF_FUNC_skc_to_udp6_sock:
+               func = &bpf_skc_to_udp6_sock_proto;
+               break;
+       default:
+               return bpf_base_func_proto(func_id);
+       }
+
+       if (!perfmon_capable())
+               return NULL;
+
+       return func;
+}