The imm field of a bpf_insn is a signed 32-bit integer. For
JIT-ed bpf-to-bpf function calls, it stores the offset from
__bpf_call_base to the start of the callee function.

For some architectures, such as powerpc64, it was found that
this offset may be as large as 64 bits because of which this
cannot be accomodated in the imm field without truncation.

To resolve this, we additionally make aux->func within each
bpf_prog associated with the functions to point to the list
of all function addresses determined by the verifier.

We keep the value assigned to the off field of the bpf_insn
as a way to index into aux->func and also set aux->func_cnt
so that this can be used for performing basic upper bound
checks for the off field.

Signed-off-by: Sandipan Das <>
v2: Make aux->func point to the list of functions determined
    by the verifier rather than allocating a separate callee
    list for each function.
 kernel/bpf/verifier.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5fb69a85d967..1c4d9cd485ed 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5288,11 +5288,25 @@ static int jit_subprogs(struct bpf_verifier_env *env)
                            insn->src_reg != BPF_PSEUDO_CALL)
                        subprog = insn->off;
-                       insn->off = 0;
                        insn->imm = (u64 (*)(u64, u64, u64, u64, u64))
                                func[subprog]->bpf_func -
+               /* the offset to a callee function from __bpf_call_base
+                * may be larger than what the 32 bit integer imm can
+                * accomodate which will truncate the higher order bits
+                *
+                * to avoid this, we additionally utilize the aux data
+                * of each function to point to a list of all function
+                * addresses determined by the verifier
+                *
+                * the off field of the instruction provides the index
+                * in this list where the start address of a function
+                * is available
+                */
+               func[i]->aux->func = func;
+               func[i]->aux->func_cnt = env->subprog_cnt + 1;
        for (i = 0; i <= env->subprog_cnt; i++) {
                old_bpf_func = func[i]->bpf_func;

Reply via email to