xref: /linux/tools/testing/selftests/exec/transparent.bpf.c (revision b9cba7ebfe539f3e4bbdd03a1e0efa3b30b3f592)
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