1*87c50a58SChristian Brauner // SPDX-License-Identifier: GPL-2.0 2*87c50a58SChristian Brauner /* 3*87c50a58SChristian Brauner * binfmt_misc_ops handler for the loader-substitution case: match the 4*87c50a58SChristian Brauner * marker the harness poked into the payload's e_ident padding and ask for 5*87c50a58SChristian Brauner * the selected interpreter to be substituted for the binary's PT_INTERP, 6*87c50a58SChristian Brauner * so the binary itself runs as a fully native exec. 7*87c50a58SChristian Brauner */ 8*87c50a58SChristian Brauner #include "vmlinux.h" 9*87c50a58SChristian Brauner #include <bpf/bpf_helpers.h> 10*87c50a58SChristian Brauner #include <bpf/bpf_tracing.h> 11*87c50a58SChristian Brauner 12*87c50a58SChristian Brauner char _license[] SEC("license") = "GPL"; 13*87c50a58SChristian Brauner 14*87c50a58SChristian Brauner #define EI_CLASS 4 15*87c50a58SChristian Brauner #define EI_PAD 9 16*87c50a58SChristian Brauner #define ELFCLASS64 2 17*87c50a58SChristian Brauner 18*87c50a58SChristian Brauner extern int bpf_binprm_set_interp(struct linux_binprm *bprm, const char *path, 19*87c50a58SChristian Brauner size_t path__sz) __ksym; 20*87c50a58SChristian Brauner extern int bpf_binprm_set_flags(struct linux_binprm *bprm, 21*87c50a58SChristian Brauner enum bpf_binprm_flags flags) __ksym; 22*87c50a58SChristian Brauner 23*87c50a58SChristian Brauner SEC("struct_ops.s/match") 24*87c50a58SChristian Brauner bool BPF_PROG(loader_match, struct linux_binprm *bprm) 25*87c50a58SChristian Brauner { 26*87c50a58SChristian Brauner if (bprm->buf[0] != 0x7f || bprm->buf[1] != 'E' || 27*87c50a58SChristian Brauner bprm->buf[2] != 'L' || bprm->buf[3] != 'F' || 28*87c50a58SChristian Brauner bprm->buf[EI_CLASS] != ELFCLASS64) 29*87c50a58SChristian Brauner return false; 30*87c50a58SChristian Brauner 31*87c50a58SChristian Brauner /* The harness marks the payload with "LDRTST" at EI_PAD. */ 32*87c50a58SChristian Brauner return bprm->buf[EI_PAD + 0] == 'L' && bprm->buf[EI_PAD + 1] == 'D' && 33*87c50a58SChristian Brauner bprm->buf[EI_PAD + 2] == 'R' && bprm->buf[EI_PAD + 3] == 'T' && 34*87c50a58SChristian Brauner bprm->buf[EI_PAD + 4] == 'S' && bprm->buf[EI_PAD + 5] == 'T'; 35*87c50a58SChristian Brauner } 36*87c50a58SChristian Brauner 37*87c50a58SChristian Brauner SEC("struct_ops.s/load") 38*87c50a58SChristian Brauner int BPF_PROG(loader_load, struct linux_binprm *bprm) 39*87c50a58SChristian Brauner { 40*87c50a58SChristian Brauner char interp[] = "/tmp/binfmt_loader_interp"; 41*87c50a58SChristian Brauner int err; 42*87c50a58SChristian Brauner 43*87c50a58SChristian Brauner err = bpf_binprm_set_flags(bprm, BPF_BINPRM_LOADER); 44*87c50a58SChristian Brauner if (err) 45*87c50a58SChristian Brauner return err; 46*87c50a58SChristian Brauner 47*87c50a58SChristian Brauner /* @path__sz includes the terminating NUL; 0 commits the selection. */ 48*87c50a58SChristian Brauner return bpf_binprm_set_interp(bprm, interp, sizeof(interp)); 49*87c50a58SChristian Brauner } 50*87c50a58SChristian Brauner 51*87c50a58SChristian Brauner SEC(".struct_ops.link") 52*87c50a58SChristian Brauner struct binfmt_misc_ops loader = { 53*87c50a58SChristian Brauner .match = (void *)loader_match, 54*87c50a58SChristian Brauner .load = (void *)loader_load, 55*87c50a58SChristian Brauner .name = "loader", 56*87c50a58SChristian Brauner }; 57