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