Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147// SPDX-License-Identifier: GPL-2.0/* * Payload for the binfmt_misc 'L' (loader substitution) selftest. It is * executed as the MAIN image - a fully native exec - with the registered * interpreter substituted for its PT_INTERP, and asserts the native * identity from the inside. Exits 0 when every surface checks out. * * Modes, selected by the orchestrator via the environment: * - default: full assertions, path-based ones included * - BINFMT_TEST_MEMFD=1: executed from an inaccessible memfd, skip * the path-based assertions * - BINFMT_TEST_STATIC=1: static build; the override was dropped, so * expect no interpreter at all */#define _GNU_SOURCE#include <elf.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/auxv.h>#include <unistd.h>
#include "binfmt_misc_common.h"
/* Start of our own mapped image, courtesy of the linker. */extern const char __ehdr_start[];
/* An image is never this large; used to bracket "within our image". */#define IMAGE_SPAN (16UL << 20)
static int failed;
static void check(int cond, const char *what){ if (cond) return; fprintf(stderr, "[payload] FAILED: %s (errno %d)\n", what, errno); failed = 1;}
/* Return whether /proc/self/maps names a path starting with @prefix. */static int maps_has_prefix(const char *prefix){ char *line = NULL; size_t len = 0; int found = 0; FILE *f;
f = fopen("/proc/self/maps", "r"); if (!f) return -1; while (getline(&line, &len, f) > 0) { char *path = strchr(line, '/');
if (path && !strncmp(path, prefix, strlen(prefix))) { found = 1; break; } } free(line); fclose(f); return found;}
int main(int argc, char *argv[]){ const char *binary = getenv("BINFMT_TEST_BINARY"); const char *interp = getenv("BINFMT_TEST_INTERP"); int memfd_mode = getenv("BINFMT_TEST_MEMFD") != NULL; int static_mode = getenv("BINFMT_TEST_STATIC") != NULL; unsigned long self = (unsigned long)__ehdr_start; unsigned long base = getauxval(AT_BASE); unsigned long phdr = getauxval(AT_PHDR); unsigned long entry = getauxval(AT_ENTRY); unsigned long start_code, end_code;
/* The argument vector is exactly what the caller built. */ check(argc == 3 && !strcmp(argv[0], PAYLOAD_ARGV0) && !strcmp(argv[1], PAYLOAD_ARG1) && !strcmp(argv[2], PAYLOAD_ARG2), "argv was rewritten");
/* Native from birth: no execfd, no dispatch marker. */ check(getauxval(AT_EXECFD) == 0, "AT_EXECFD present"); check(getauxval(AT_FLAGS) == 0, "AT_FLAGS not native");
if (static_mode) { /* The override was dropped: no interpreter was loaded. */ check(base == 0, "AT_BASE set for a static payload"); } else { /* A loader is mapped in the interpreter slot, not our image. */ check(base != 0, "AT_BASE missing"); check(base < self || base >= self + IMAGE_SPAN, "AT_BASE inside our own image"); }
/* We occupy the main-image slot. */ check(phdr >= self && phdr < self + IMAGE_SPAN, "AT_PHDR outside our image"); check(entry >= self && entry < self + IMAGE_SPAN, "AT_ENTRY outside our image");
/* The code statistics markers describe our image, natively placed. */ if (stat_codes(getpid(), &start_code, &end_code) == 0) { check(start_code >= self && start_code < end_code && end_code < self + IMAGE_SPAN, "stat start_code/end_code not our image"); check(entry >= start_code && entry < end_code, "AT_ENTRY outside [start_code, end_code)"); } else { check(0, "cannot parse /proc/self/stat"); }
if (!memfd_mode && binary) { const char *execfn = (const char *)getauxval(AT_EXECFN); const char *base_name = strrchr(binary, '/');
base_name = base_name ? base_name + 1 : binary;
/* exe link, AT_EXECFN and comm all follow the binary. */ check(exe_is(binary), "/proc/self/exe"); check(execfn && !strcmp(execfn, binary), "AT_EXECFN"); check(comm_is(base_name), "comm");
/* The running binary is write-denied, natively. */ check(write_denied(binary), "no ETXTBSY on the binary"); }
if (interp) { int found = maps_has_prefix(interp);
if (static_mode) /* Nothing was substituted, nothing may be mapped. */ check(found == 0, "loader mapped for a static payload"); else /* The substituted loader shows under its real path. */ check(found == 1, "loader path not in /proc/self/maps"); }
if (failed) return 1; printf("[payload] native identity checks out\n"); return 0;}