diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f45870..d1ecc16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 3.0.0) project(FatELF) +include(CheckSymbolExists) +include(GNUInstallDirs) + execute_process( COMMAND git rev-list HEAD~.. WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" @@ -37,5 +40,19 @@ add_fatelf_executable(fatelf-verify) add_fatelf_executable(fatelf-split) add_fatelf_executable(fatelf-validate) +set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) +check_symbol_exists(memfd_create sys/mman.h MEMFD) +check_symbol_exists(fexecve unistd.h FEXECVE) +if(MEMFD AND FEXECVE AND EXISTS /proc/self/exe) + add_fatelf_executable(fatelf-exec) + + find_program(BINFMT systemd-binfmt PATHS /usr/lib/systemd) + if(BINFMT) + configure_file(fatelf.conf.in fatelf.conf) + install(DIRECTORY DESTINATION ${CMAKE_INSTALL_LIBDIR}/binfmt.d) + install(FILES ${CMAKE_BINARY_DIR}/fatelf.conf DESTINATION ${CMAKE_INSTALL_LIBDIR}/binfmt.d/) + endif() +endif() + # end of CMakeLists.txt ... diff --git a/fatelf.conf.in b/fatelf.conf.in new file mode 100644 index 0000000..0fa3078 --- /dev/null +++ b/fatelf.conf.in @@ -0,0 +1 @@ +:fatelf-v1:M::\xFA\x70\x0E\x1F\x01\x00::${CMAKE_INSTALL_FULL_BINDIR}/fatelf-exec: diff --git a/utils/fatelf-exec.c b/utils/fatelf-exec.c new file mode 100644 index 0000000..8ff4309 --- /dev/null +++ b/utils/fatelf-exec.c @@ -0,0 +1,49 @@ +/** + * FatELF; support multiple ELF binaries in one file. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Henry W. Wilson. + */ + +#define _GNU_SOURCE +#define FATELF_UTILS 1 +#include "fatelf-utils.h" +#include +#include + +static FATELF_record * xfind_matching_record(FATELF_record const *tgt, FATELF_header *header) +{ + for (uint8_t i = 0; i < header->num_records; i++) + if (fatelf_record_matches(header->records + i, tgt)) + return header->records + i; + + xfail("Unable to find %s in FatElf records", fatelf_get_target_name(tgt, FATELF_WANT_EVERYTHING)); +} // xfind_matching_record + +int main(int argc, char *argv[], char *envp[]) +{ + xfatelf_init(argc, (char const**)argv); + if (argc < 2) + xfail("USAGE: %s [--version] fatelf-file [args...]", argv[0]); + + int fd = xopen(argv[1], O_RDONLY | O_CLOEXEC, 0); + FATELF_header *header = xread_fatelf_header(argv[1], fd); + + int self = xopen("/proc/self/exe", O_RDONLY | O_CLOEXEC, 0); + FATELF_record self_elf; + xread_elf_header(argv[0], self, 0, &self_elf); + + FATELF_record const *rec = xfind_matching_record(&self_elf, header); + + int outfd = memfd_create("ELF", MFD_CLOEXEC); + if (outfd < 0) + xfail("memfd_create"); + + xcopyfile_range(argv[1], fd, "memfd:ELF", outfd, rec->offset, rec->size); + + fexecve(outfd, (argv + 1), envp); + xfail("fexecve"); +} // main + +// end of fatelf-exec.c ... diff --git a/utils/fatelf-utils.c b/utils/fatelf-utils.c index 0a07752..d4727e8 100644 --- a/utils/fatelf-utils.c +++ b/utils/fatelf-utils.c @@ -73,7 +73,7 @@ const char *fatelf_build_version = MAKEBUILDVERSTRINGLITERAL(APPID, APPREV); // Report an error to stderr and terminate immediately with exit(1). -void xfail(const char *fmt, ...) +[[noreturn]] void xfail(const char *fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/utils/fatelf-utils.h b/utils/fatelf-utils.h index 3e38c64..5570027 100644 --- a/utils/fatelf-utils.h +++ b/utils/fatelf-utils.h @@ -57,7 +57,7 @@ typedef struct fatelf_osabi_info // all functions that start with 'x' may call exit() on error! // Report an error to stderr and terminate immediately with exit(1). -void xfail(const char *fmt, ...) FATELF_ISPRINTF(1,2); +[[noreturn]] void xfail(const char *fmt, ...) FATELF_ISPRINTF(1,2); // Wrap malloc() with an xfail(), so this returns memory or calls exit(). // Memory is guaranteed to be initialized to zero.