1*7baee96fSChristian Brauner // SPDX-License-Identifier: GPL-2.0 2*7baee96fSChristian Brauner /* 3*7baee96fSChristian Brauner * binfmt_misc_ops handler for the transparent-mode case: match a synthetic 4*7baee96fSChristian Brauner * riscv ELF header and run the asserting interpreter transparently - the 5*7baee96fSChristian Brauner * argument vector untouched, the binary in AT_EXECFD and mm->exe_file 6*7baee96fSChristian Brauner * labeled with the binary. 7*7baee96fSChristian Brauner */ 8*7baee96fSChristian Brauner #include "vmlinux.h" 9*7baee96fSChristian Brauner #include <bpf/bpf_helpers.h> 10*7baee96fSChristian Brauner #include <bpf/bpf_tracing.h> 11*7baee96fSChristian Brauner 12*7baee96fSChristian Brauner char _license[] SEC("license") = "GPL"; 13*7baee96fSChristian Brauner 14*7baee96fSChristian Brauner #define EI_CLASS 4 15*7baee96fSChristian Brauner #define ELFCLASS64 2 16*7baee96fSChristian Brauner #define EM_RISCV 243 17*7baee96fSChristian Brauner 18*7baee96fSChristian Brauner extern int bpf_binprm_set_interp(struct linux_binprm *bprm, const char *path, 19*7baee96fSChristian Brauner size_t path__sz) __ksym; 20*7baee96fSChristian Brauner extern int bpf_binprm_set_flags(struct linux_binprm *bprm, 21*7baee96fSChristian Brauner enum bpf_binprm_flags flags) __ksym; 22*7baee96fSChristian Brauner 23*7baee96fSChristian Brauner SEC("struct_ops.s/match") 24*7baee96fSChristian Brauner bool BPF_PROG(transparent_match, struct linux_binprm *bprm) 25*7baee96fSChristian Brauner { 26*7baee96fSChristian Brauner __u16 machine; 27*7baee96fSChristian Brauner 28*7baee96fSChristian Brauner if (bprm->buf[0] != 0x7f || bprm->buf[1] != 'E' || 29*7baee96fSChristian Brauner bprm->buf[2] != 'L' || bprm->buf[3] != 'F' || 30*7baee96fSChristian Brauner bprm->buf[EI_CLASS] != ELFCLASS64) 31*7baee96fSChristian Brauner return false; 32*7baee96fSChristian Brauner 33*7baee96fSChristian Brauner /* e_machine is a 16-bit little-endian field at offset 18. */ 34*7baee96fSChristian Brauner machine = (__u8)bprm->buf[18] | ((__u16)(__u8)bprm->buf[19] << 8); 35*7baee96fSChristian Brauner return machine == EM_RISCV; 36*7baee96fSChristian Brauner } 37*7baee96fSChristian Brauner 38*7baee96fSChristian Brauner SEC("struct_ops.s/load") 39*7baee96fSChristian Brauner int BPF_PROG(transparent_load, struct linux_binprm *bprm) 40*7baee96fSChristian Brauner { 41*7baee96fSChristian Brauner char interp[] = "/tmp/binfmt_transparent_interp"; 42*7baee96fSChristian Brauner int err; 43*7baee96fSChristian Brauner 44*7baee96fSChristian Brauner err = bpf_binprm_set_flags(bprm, BPF_BINPRM_TRANSPARENT); 45*7baee96fSChristian Brauner if (err) 46*7baee96fSChristian Brauner return err; 47*7baee96fSChristian Brauner 48*7baee96fSChristian Brauner /* @path__sz includes the terminating NUL; 0 commits the selection. */ 49*7baee96fSChristian Brauner return bpf_binprm_set_interp(bprm, interp, sizeof(interp)); 50*7baee96fSChristian Brauner } 51*7baee96fSChristian Brauner 52*7baee96fSChristian Brauner SEC(".struct_ops.link") 53*7baee96fSChristian Brauner struct binfmt_misc_ops transparent = { 54*7baee96fSChristian Brauner .match = (void *)transparent_match, 55*7baee96fSChristian Brauner .load = (void *)transparent_load, 56*7baee96fSChristian Brauner .name = "transparent", 57*7baee96fSChristian Brauner }; 58