Skip to content

loader: handle missing kfunc gracefully #1355

@dylandreimerink

Description

@dylandreimerink

While looking at __weak support I came across the following pattern used in selftests:

void invalid_kfunc(void) __ksym __weak;

#define bpf_ksym_exists(sym) \
	({ \
		_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \
		!!sym; \
	})

SEC("xdp") int xdp_prog(struct xdp_md *ctx) {
	if (bpf_ksym_exists(invalid_kfunc))
		invalid_kfunc();

	return 0;
}

So, essentially, this allows programs to handle cases where a given kfunc isn't available such as on older kernels or on kernels missing certain KCONFIG.

The __weak attribute is required for this to work so initially this results in a relocating instruction: asm relocation: invalid_kfunc: unsupported binding: STB_WEAK error. But assuming this is resolved by #466. We get the error: fixing up kfuncs: kfunc "invalid_kfunc": not supported.

The instructions for the example program are:

xdp_prog:
         ; if (bpf_ksym_exists(invalid_kfunc))
        0: LdImmDW dst: r1 imm: 0 <invalid_kfunc>
        2: JEqImm dst: r1 off: 1 imm: 0
         ; invalid_kfunc();
        3: Call Kfunc(-1) <invalid_kfunc>
         ; return 0;
        4: MovImm dst: r0 imm: 0
        5: Exit

The way libbpf handles this is by simply doing nothing. Since instruction 0 has a imm of 0 by default the code branch with the call is dead code and never trips the verifier.

There is a secondary issue, that being that we only relocate Call instructions, even if the kfunc were valid, instruction 0 would be ignored. So if we can fix both, we effectively allow CO-RE with kfuncs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions