| 1 | |
| 2 | |
| 3 | * binfmt_misc_ops handler for the selftest's bound-interpreter case: one
|
| 4 | * handler, one entry, an interpreter per guest architecture - each bound to
|
| 5 | * a file when the entry was registered rather than to a path resolved at
|
| 6 | * exec time. The load program names the one it wants; a name the entry did
|
| 7 | * not bind fails the exec, which the harness checks too.
|
| 8 |
|
| 9 | #include "vmlinux.h"
|
| 10 | #include <bpf/bpf_helpers.h>
|
| 11 | #include <bpf/bpf_tracing.h>
|
| 12 |
|
| 13 | char _license[] SEC("license") = "GPL";
|
| 14 |
|
| 15 | #define EI_CLASS 4
|
| 16 | #define ELFCLASS64 2
|
| 17 | #define E_MACHINE_OFF 18
|
| 18 | #define EM_ARM 40
|
| 19 | #define EM_AARCH64 183
|
| 20 | #define EM_RISCV 243
|
| 21 |
|
| 22 | extern int bpf_binprm_select_interp(struct linux_binprm *bprm,
|
| 23 | const char *name, size_t name__sz) __ksym;
|
| 24 |
|
| 25 |
|
| 26 | static __u16 elf_machine(struct linux_binprm *bprm)
|
| 27 | {
|
| 28 | if (bprm->buf[0] != 0x7f || bprm->buf[1] != 'E' ||
|
| 29 | bprm->buf[2] != 'L' || bprm->buf[3] != 'F' ||
|
| 30 | bprm->buf[EI_CLASS] != ELFCLASS64)
|
| 31 | return 0;
|
| 32 |
|
| 33 |
|
| 34 | return (__u8)bprm->buf[E_MACHINE_OFF] |
|
| 35 | ((__u16)(__u8)bprm->buf[E_MACHINE_OFF + 1] << 8);
|
| 36 | }
|
| 37 |
|
| 38 | SEC("struct_ops.s/match")
|
| 39 | bool BPF_PROG(interp_bind_match, struct linux_binprm *bprm)
|
| 40 | {
|
| 41 | __u16 machine = elf_machine(bprm);
|
| 42 |
|
| 43 | return machine == EM_AARCH64 || machine == EM_RISCV ||
|
| 44 | machine == EM_ARM;
|
| 45 | }
|
| 46 |
|
| 47 | SEC("struct_ops.s/load")
|
| 48 | int BPF_PROG(interp_bind_load, struct linux_binprm *bprm)
|
| 49 | {
|
| 50 | |
| 51 | * Names, not paths: each one selects a file the entry pre-opened, so
|
| 52 | * nothing is resolved here or later, in any namespace. The buffers
|
| 53 | * are on the stack because the verifier rejects .rodata for a sized
|
| 54 | * memory argument.
|
| 55 |
|
| 56 | char first[] = "first";
|
| 57 | char second[] = "second";
|
| 58 | char unbound[] = "unbound";
|
| 59 |
|
| 60 | switch (elf_machine(bprm)) {
|
| 61 | case EM_AARCH64:
|
| 62 | return bpf_binprm_select_interp(bprm, first, sizeof(first));
|
| 63 | case EM_RISCV:
|
| 64 | return bpf_binprm_select_interp(bprm, second, sizeof(second));
|
| 65 | }
|
| 66 |
|
| 67 |
|
| 68 | return bpf_binprm_select_interp(bprm, unbound, sizeof(unbound));
|
| 69 | }
|
| 70 |
|
| 71 | SEC(".struct_ops.link")
|
| 72 | struct binfmt_misc_ops interp_bind = {
|
| 73 | .match = (void *)interp_bind_match,
|
| 74 | .load = (void *)interp_bind_load,
|
| 75 | .name = "interp_bind",
|
| 76 | };
|