// SPDX-License-Identifier: GPL-2.0/* * Test the static transparent flag 'T' of binfmt_misc. A magic-matched * binary is dispatched to an interpreter with the argument vector left * untouched, the binary passed through AT_EXECFD and mm->exe_file labeled * with the binary. The asserting interpreter (binfmt_transparent_interp) * verifies the constructed identity from inside the process and exits 0. * * Needs root for the registration; no bpf toolchain involved. */#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include "binfmt_misc_common.h"#include "kselftest_harness.h"#define MAGIC "#TRANSPARENT-SELFTEST#"#define TARGET_PATH "/tmp/binfmt_transparent_target"#define INTERP_PATH "/tmp/binfmt_transparent_interp"#define ENTRY "test_transparent"#define RULE(flags) ":" ENTRY ":M:0:" MAGIC "::" INTERP_PATH ":" flags/* The target only has to carry the magic; it is never actually loaded. */static int create_target(void){ char buf[128] = MAGIC "\n"; int fd; unlink(TARGET_PATH); fd = open(TARGET_PATH, O_WRONLY | O_CREAT | O_EXCL, 0755); if (fd < 0) return -1; if (write(fd, buf, sizeof(buf)) != (ssize_t)sizeof(buf)) { close(fd); return -1; } close(fd); return 0;}FIXTURE(transparent) {};FIXTURE_SETUP(transparent){ char src[PATH_MAX]; if (getuid() != 0) SKIP(return, "test must be run as root"); if (!binfmt_misc_available()) SKIP(return, "no binfmt_misc"); ASSERT_EQ(artifact_path(src, sizeof(src), "binfmt_transparent_interp"), 0); ASSERT_EQ(copy_file(src, INTERP_PATH), 0); ASSERT_EQ(create_target(), 0); /* Skip the whole suite on a kernel that does not know 'T'. */ if (!binfmt_flag_supported('T')) { ASSERT_EQ(errno, EINVAL); SKIP(return, "kernel without the 'T' flag"); }}FIXTURE_TEARDOWN(transparent){ unregister(ENTRY); unlink(TARGET_PATH); unlink(INTERP_PATH);}/* Grammar sanity check: the same entry without 'T' has to register. */TEST_F(transparent, plain_entry_registers){ ASSERT_EQ(write_reg(RULE("")), 0);}/* 'T' preserves the whole argv, so combining it with 'P' is rejected. */TEST_F(transparent, rejects_preserve_argv0){ ASSERT_NE(write_reg(RULE("TP")), 0); EXPECT_EQ(errno, EINVAL);}/* The interpreter asserts the identity the kernel built for it. */TEST_F(transparent, dispatch){ ASSERT_EQ(write_reg(RULE("T")), 0); setenv("BINFMT_TEST_BINARY", TARGET_PATH, 1); setenv("BINFMT_TEST_ARGV0", PAYLOAD_ARGV0, 1); EXPECT_EQ(run_payload(TARGET_PATH), 0);}TEST_HARNESS_MAIN
// SPDX-License-Identifier: GPL-2.0
/*
* Test the static transparent flag 'T' of binfmt_misc. A magic-matched
* binary is dispatched to an interpreter with the argument vector left
* untouched, the binary passed through AT_EXECFD and mm->exe_file labeled
* with the binary. The asserting interpreter (binfmt_transparent_interp)
* verifies the constructed identity from inside the process and exits 0.
*
* Needs root for the registration; no bpf toolchain involved.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include "binfmt_misc_common.h"
#include "kselftest_harness.h"
#define MAGIC "#TRANSPARENT-SELFTEST#"
#define TARGET_PATH "/tmp/binfmt_transparent_target"
#define INTERP_PATH "/tmp/binfmt_transparent_interp"
#define ENTRY "test_transparent"
#define RULE(flags) ":" ENTRY ":M:0:" MAGIC "::" INTERP_PATH ":" flags
/* The target only has to carry the magic; it is never actually loaded. */
static int create_target(void)
{
char buf[128] = MAGIC "\n";
int fd;
unlink(TARGET_PATH);
fd = open(TARGET_PATH, O_WRONLY | O_CREAT | O_EXCL, 0755);
if (fd < 0)
return -1;
if (write(fd, buf, sizeof(buf)) != (ssize_t)sizeof(buf)) {
close(fd);
return -1;
}
close(fd);
return 0;
}
FIXTURE(transparent) {
};
FIXTURE_SETUP(transparent)
{
char src[PATH_MAX];
if (getuid() != 0)
SKIP(return, "test must be run as root");
if (!binfmt_misc_available())
SKIP(return, "no binfmt_misc");
ASSERT_EQ(artifact_path(src, sizeof(src), "binfmt_transparent_interp"), 0);
ASSERT_EQ(copy_file(src, INTERP_PATH), 0);
ASSERT_EQ(create_target(), 0);
/* Skip the whole suite on a kernel that does not know 'T'. */
if (!binfmt_flag_supported('T')) {
ASSERT_EQ(errno, EINVAL);
SKIP(return, "kernel without the 'T' flag");
}
}
FIXTURE_TEARDOWN(transparent)
{
unregister(ENTRY);
unlink(TARGET_PATH);
unlink(INTERP_PATH);
}
/* Grammar sanity check: the same entry without 'T' has to register. */
TEST_F(transparent, plain_entry_registers)
{
ASSERT_EQ(write_reg(RULE("")), 0);
}
/* 'T' preserves the whole argv, so combining it with 'P' is rejected. */
TEST_F(transparent, rejects_preserve_argv0)
{
ASSERT_NE(write_reg(RULE("TP")), 0);
EXPECT_EQ(errno, EINVAL);
}
/* The interpreter asserts the identity the kernel built for it. */
TEST_F(transparent, dispatch)
{
ASSERT_EQ(write_reg(RULE("T")), 0);
setenv("BINFMT_TEST_BINARY", TARGET_PATH, 1);
setenv("BINFMT_TEST_ARGV0", PAYLOAD_ARGV0, 1);
EXPECT_EQ(run_payload(TARGET_PATH), 0);
}
TEST_HARNESS_MAIN