xref: /linux/tools/testing/selftests/exec/binfmt_misc_transparent.c (revision b9cba7ebfe539f3e4bbdd03a1e0efa3b30b3f592)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test the static transparent flag 'T' of binfmt_misc. A magic-matched
4  * binary is dispatched to an interpreter with the argument vector left
5  * untouched, the binary passed through AT_EXECFD and mm->exe_file labeled
6  * with the binary. The asserting interpreter (binfmt_transparent_interp)
7  * verifies the constructed identity from inside the process and exits 0.
8  *
9  * Needs root for the registration; no bpf toolchain involved.
10  */
11 #define _GNU_SOURCE
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 #include "binfmt_misc_common.h"
16 #include "kselftest_harness.h"
17 
18 #define MAGIC		"#TRANSPARENT-SELFTEST#"
19 #define TARGET_PATH	"/tmp/binfmt_transparent_target"
20 #define INTERP_PATH	"/tmp/binfmt_transparent_interp"
21 #define ENTRY		"test_transparent"
22 #define RULE(flags)	":" ENTRY ":M:0:" MAGIC "::" INTERP_PATH ":" flags
23 
24 /* The target only has to carry the magic; it is never actually loaded. */
25 static int create_target(void)
26 {
27 	char buf[128] = MAGIC "\n";
28 	int fd;
29 
30 	unlink(TARGET_PATH);
31 	fd = open(TARGET_PATH, O_WRONLY | O_CREAT | O_EXCL, 0755);
32 	if (fd < 0)
33 		return -1;
34 	if (write(fd, buf, sizeof(buf)) != (ssize_t)sizeof(buf)) {
35 		close(fd);
36 		return -1;
37 	}
38 	close(fd);
39 	return 0;
40 }
41 
42 FIXTURE(transparent) {
43 };
44 
45 FIXTURE_SETUP(transparent)
46 {
47 	char src[PATH_MAX];
48 
49 	if (getuid() != 0)
50 		SKIP(return, "test must be run as root");
51 	if (!binfmt_misc_available())
52 		SKIP(return, "no binfmt_misc");
53 
54 	ASSERT_EQ(artifact_path(src, sizeof(src), "binfmt_transparent_interp"), 0);
55 	ASSERT_EQ(copy_file(src, INTERP_PATH), 0);
56 	ASSERT_EQ(create_target(), 0);
57 
58 	/* Skip the whole suite on a kernel that does not know 'T'. */
59 	if (!binfmt_flag_supported('T')) {
60 		ASSERT_EQ(errno, EINVAL);
61 		SKIP(return, "kernel without the 'T' flag");
62 	}
63 }
64 
65 FIXTURE_TEARDOWN(transparent)
66 {
67 	unregister(ENTRY);
68 	unlink(TARGET_PATH);
69 	unlink(INTERP_PATH);
70 }
71 
72 /* Grammar sanity check: the same entry without 'T' has to register. */
73 TEST_F(transparent, plain_entry_registers)
74 {
75 	ASSERT_EQ(write_reg(RULE("")), 0);
76 }
77 
78 /* 'T' preserves the whole argv, so combining it with 'P' is rejected. */
79 TEST_F(transparent, rejects_preserve_argv0)
80 {
81 	ASSERT_NE(write_reg(RULE("TP")), 0);
82 	EXPECT_EQ(errno, EINVAL);
83 }
84 
85 /* The interpreter asserts the identity the kernel built for it. */
86 TEST_F(transparent, dispatch)
87 {
88 	ASSERT_EQ(write_reg(RULE("T")), 0);
89 
90 	setenv("BINFMT_TEST_BINARY", TARGET_PATH, 1);
91 	setenv("BINFMT_TEST_ARGV0", PAYLOAD_ARGV0, 1);
92 	EXPECT_EQ(run_payload(TARGET_PATH), 0);
93 }
94 
95 TEST_HARNESS_MAIN
96