projects/linux·blob master · refs

95 lines · 2.4 KiB

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. */
25static 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
42FIXTURE(transparent) {
43};
44
45FIXTURE_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
65FIXTURE_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. */
73TEST_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. */
79TEST_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. */
86TEST_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
95TEST_HARNESS_MAIN