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