prog_aux->kfunc_tab = tab;
        }
 
+       /* func_id == 0 is always invalid, but instead of returning an error, be
+        * conservative and wait until the code elimination pass before returning
+        * error, so that invalid calls that get pruned out can be in BPF programs
+        * loaded from userspace.  It is also required that offset be untouched
+        * for such calls.
+        */
+       if (!func_id && !offset)
+               return 0;
+
        if (!btf_tab && offset) {
                btf_tab = kzalloc(sizeof(*btf_tab), GFP_KERNEL);
                if (!btf_tab)
        struct btf *desc_btf;
        int err;
 
+       /* skip for now, but return error when we find this in fixup_kfunc_call */
+       if (!insn->imm)
+               return 0;
+
        desc_btf = find_kfunc_desc_btf(env, insn->imm, insn->off, &btf_mod);
        if (IS_ERR(desc_btf))
                return PTR_ERR(desc_btf);
 {
        const struct bpf_kfunc_desc *desc;
 
+       if (!insn->imm) {
+               verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
+               return -EINVAL;
+       }
+
        /* insn->imm has the btf func_id. Replace it with
         * an address (relative to __bpf_base_call).
         */