1*277d787fSFarid Zakaria // SPDX-License-Identifier: GPL-2.0 2*277d787fSFarid Zakaria /* 3*277d787fSFarid Zakaria * binfmt_misc_ops handler for the selftest's fixed-interpreter case: match a 4*277d787fSFarid Zakaria * 64-bit aarch64 ELF header from the prefetched buffer and route it to a fixed 5*277d787fSFarid Zakaria * interpreter chosen by the program. This is the portable, self-contained 6*277d787fSFarid Zakaria * equivalent of routing a foreign binary to an emulator: it matches 7*277d787fSFarid Zakaria * programmatically and computes the interpreter, but points at a test binary 8*277d787fSFarid Zakaria * the harness installs rather than a system emulator. 9*277d787fSFarid Zakaria */ 10*277d787fSFarid Zakaria #include "vmlinux.h" 11*277d787fSFarid Zakaria #include <bpf/bpf_helpers.h> 12*277d787fSFarid Zakaria #include <bpf/bpf_tracing.h> 13*277d787fSFarid Zakaria 14*277d787fSFarid Zakaria char _license[] SEC("license") = "GPL"; 15*277d787fSFarid Zakaria 16*277d787fSFarid Zakaria #define EI_CLASS 4 17*277d787fSFarid Zakaria #define ELFCLASS64 2 18*277d787fSFarid Zakaria #define EM_AARCH64 183 19*277d787fSFarid Zakaria 20*277d787fSFarid Zakaria extern int bpf_binprm_set_interp(struct linux_binprm *bprm, const char *path, 21*277d787fSFarid Zakaria size_t path__sz) __ksym; 22*277d787fSFarid Zakaria 23*277d787fSFarid Zakaria /* 24*277d787fSFarid Zakaria * A magic-style decision needs nothing beyond the prefetched bprm->buf, 25*277d787fSFarid Zakaria * even though the match program could read the file. 26*277d787fSFarid Zakaria */ 27*277d787fSFarid Zakaria SEC("struct_ops.s/match") 28*277d787fSFarid Zakaria bool BPF_PROG(bpf_interp_match, struct linux_binprm *bprm) 29*277d787fSFarid Zakaria { 30*277d787fSFarid Zakaria __u16 machine; 31*277d787fSFarid Zakaria 32*277d787fSFarid Zakaria if (bprm->buf[0] != 0x7f || bprm->buf[1] != 'E' || 33*277d787fSFarid Zakaria bprm->buf[2] != 'L' || bprm->buf[3] != 'F' || 34*277d787fSFarid Zakaria bprm->buf[EI_CLASS] != ELFCLASS64) 35*277d787fSFarid Zakaria return false; 36*277d787fSFarid Zakaria 37*277d787fSFarid Zakaria /* e_machine is a 16-bit little-endian field at offset 18. */ 38*277d787fSFarid Zakaria machine = (__u8)bprm->buf[18] | ((__u16)(__u8)bprm->buf[19] << 8); 39*277d787fSFarid Zakaria return machine == EM_AARCH64; 40*277d787fSFarid Zakaria } 41*277d787fSFarid Zakaria 42*277d787fSFarid Zakaria SEC("struct_ops.s/load") 43*277d787fSFarid Zakaria int BPF_PROG(bpf_interp_load, struct linux_binprm *bprm) 44*277d787fSFarid Zakaria { 45*277d787fSFarid Zakaria /* 46*277d787fSFarid Zakaria * Keep the path on the (writable) stack: bpf_binprm_set_interp() takes 47*277d787fSFarid Zakaria * a sized memory arg and the verifier rejects a read-only .rodata 48*277d787fSFarid Zakaria * buffer for it. The harness installs the interpreter at this path. 49*277d787fSFarid Zakaria */ 50*277d787fSFarid Zakaria char interp[] = "/tmp/binfmt_bpf_interp"; 51*277d787fSFarid Zakaria 52*277d787fSFarid Zakaria /* @path__sz includes the terminating NUL; 0 commits the selection. */ 53*277d787fSFarid Zakaria return bpf_binprm_set_interp(bprm, interp, sizeof(interp)); 54*277d787fSFarid Zakaria } 55*277d787fSFarid Zakaria 56*277d787fSFarid Zakaria SEC(".struct_ops.link") 57*277d787fSFarid Zakaria struct binfmt_misc_ops bpf_interp = { 58*277d787fSFarid Zakaria .match = (void *)bpf_interp_match, 59*277d787fSFarid Zakaria .load = (void *)bpf_interp_load, 60*277d787fSFarid Zakaria .name = "bpf_interp", 61*277d787fSFarid Zakaria }; 62