implement new loader

This commit is contained in:
TopchetoEU 2025-03-16 02:37:31 +02:00
parent 7c7832ba40
commit 0101ed8a24
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
17 changed files with 1594 additions and 83 deletions

View File

@ -1,14 +1,25 @@
# requires lua, curl and zlib (in the future, lua will be statically linked)
libraries := -llua -lcurl -lz
flags := -Wall
# lua is required in the build process, in order to compile the bytecode
lua := lua
cc := gcc
bundle = $(src_entry_dir)/bundle.lua
dump_loader = $(src_entry_dir)/dump_loader.lua
all_flags += -W -Wall -fPIC -std=gnu11
# requires lua, curl and zlib (in the future, lua will be statically linked)
main_libraries += -llua -lcurl -lz
main_cflags += $(all_flags)
loader_libraries += -lfuse -lpthread -lsquashfuse
loader_cflags += $(all_flags)
loader_cflags += -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=29
loader_cflags += -I/usr/include/fuse
dst_dir = dst
src_main_dir = src/main
src_entry_dir = src/entry
src_loader_dir = src/loader
# Uncomment to get debugging symbols
# flags := -g
@ -18,21 +29,27 @@ main_sources += $(wildcard $(src_main_dir)/cli/*.lua)
main_sources += $(wildcard $(src_main_dir)/formats/*.lua)
main_sources += $(wildcard $(src_main_dir)/util/*.lua)
c_sources = $(wildcard $(src_entry_dir)/*.c)
entry_sources = $(wildcard $(src_entry_dir)/*.c)
build_entry = $(src_entry_dir)/build.lua
loader_sources = $(wildcard $(src_loader_dir)/*.c)
target = $(dst_dir)/slimpack
bytecode_target = $(dst_dir)/bytecode.h
main_target = $(dst_dir)/slimpack
loader_target = $(dst_dir)/loader
bytecode_h_target = $(dst_dir)/bytecode.h
loader_h_target = $(dst_dir)/loader.h
.PHONY: build
build: $(target)
build: $(main_target)
$(dst_dir):
mkdir -p $@
$(bytecode_target): $(main_sources) $(dst_dir) $(build_entry)
$(lua) $(build_entry) $(src_main_dir) $@ $(main_sources)
$(target): $(c_sources) $(bytecode_target) $(dst_dir)
$(cc) $(flags) $(libraries) -include $(bytecode_target) $(c_sources) -o $@
$(bytecode_h_target): $(dst_dir) $(bundle) $(main_sources)
$(lua) $(bundle) $(src_main_dir) $@ $(main_sources)
$(loader_h_target): $(dst_dir) $(dump_loader) $(loader_target)
$(lua) $(dump_loader) $(loader_target) $@
$(loader_target): $(dst_dir) $(loader_sources)
$(cc) $(loader_cflags) $(loader_libraries) $(loader_sources) -o $@
$(main_target): $(dst_dir) $(bytecode_h_target) $(loader_h_target) $(entry_sources) $(main_sources)
$(cc) $(main_cflags) $(main_libraries) -include $(bytecode_h_target) -include $(loader_h_target) $(entry_sources) -o $@

6
mod/elf_loader.d.lua Normal file
View File

@ -0,0 +1,6 @@
--- @meta elf_loader
--- @type string
local res;
return res;

View File

@ -8,11 +8,11 @@ local fs = {};
--- @return string? err
function fs.mkdir(path, recursive) end
--- @param src string
--- @param dst string
--- @param target string
--- @param name string
--- @return boolean? ok
--- @return string? err
function fs.symlink(src, dst) end
function fs.symlink(target, name) end
--- @param path string
--- @param mode string | integer

36
src/entry/dump_loader.lua Normal file
View File

@ -0,0 +1,36 @@
local function escape(str)
return "\"" .. str:gsub(".", function (c)
local b = string.byte(c);
if c == "\n" then
return "\\n";
elseif c == "\\" then
return "\\\\";
elseif c == "\"" then
return "\\\"";
elseif b >= 32 and b <= 126 then
return c;
else
return ("\\%.3o"):format(b);
end
end) .. "\"";
end
local function main(in_f, out_f)
local f = assert(io.open(out_f, "w"));
f:write "#include <stdint.h>\n";
f:write "#define LOADER loader_bytecode\n";
f:write "#define LOADER_SIZE (sizeof loader_bytecode - 1)\n";
f:write "static const uint8_t loader_bytecode[] = ";
for part in io.lines(in_f, 64) do
f:write(escape(part));
f:write"\n";
end
f:write ";";
assert(f:close());
end
main(...);

View File

@ -77,7 +77,7 @@ static int fmt_parse_width(size_t *i, const char *raw, size_t raw_size) {
static fmt_code_t fmt_parse_fmt(lua_State *ctx, const char *raw, size_t raw_size) {
if (raw == NULL || *raw == 0) return FMT_BAD_ARGS;
if (raw_size == -1) raw_size = strlen(raw);
if (raw_size == SIZE_MAX) raw_size = strlen(raw);
fmt_segment_t segments[raw_size];
size_t segments_n = 0;
@ -278,7 +278,7 @@ static void write_buff_fit(write_buff_t *buff) {
static bool fmt_read_uint8(const uint8_t *raw, size_t *i, size_t size, uint8_t *res) {
if ((*i) + 1 > size || *i < 0) return false;
if ((*i) + 1 > size) return false;
*res = raw[(*i)++];
@ -289,7 +289,7 @@ static bool fmt_read_int8(const uint8_t *raw, size_t *i, size_t size, int8_t *re
}
static bool fmt_read_uint16(const uint8_t *raw, size_t *i, size_t size, uint16_t *res, bool little_endian) {
if ((*i) + 2 > size || *i < 0) return false;
if ((*i) + 2 > size) return false;
uint16_t a = raw[(*i)++];
uint16_t b = raw[(*i)++];
@ -304,7 +304,7 @@ static bool fmt_read_int16(const uint8_t *raw, size_t *i, size_t size, int16_t *
}
static bool fmt_read_uint32(const uint8_t *raw, size_t *i, size_t size, uint32_t *res, bool little_endian) {
if ((*i) + 4 > size || *i < 0) return false;
if ((*i) + 4 > size) return false;
uint8_t a = raw[(*i)++];
uint8_t b = raw[(*i)++];
@ -321,7 +321,7 @@ static bool fmt_read_int32(const uint8_t *raw, size_t *i, size_t size, int32_t *
}
static bool fmt_read_uint64(const uint8_t *raw, size_t *i, size_t size, uint64_t *res, bool little_endian) {
if ((*i) + 8 > size || *i < 0) return false;
if ((*i) + 8 > size) return false;
uint64_t a = raw[(*i)++];
uint64_t b = raw[(*i)++];
@ -342,7 +342,7 @@ static bool fmt_read_int64(const uint8_t *raw, size_t *i, size_t size, int64_t *
}
static bool fmt_read_float32(const uint8_t *raw, size_t *i, size_t size, float *res, bool little_endian) {
if ((*i) + 4 > size || *i < 0) return false;
if ((*i) + 4 > size) return false;
uint8_t a = raw[(*i)++];
uint8_t b = raw[(*i)++];
@ -356,7 +356,7 @@ static bool fmt_read_float32(const uint8_t *raw, size_t *i, size_t size, float *
return true;
}
static bool fmt_read_float64(const uint8_t *raw, size_t *i, size_t size, double *res, bool little_endian) {
if ((*i) + 8 > size || *i < 0) return false;
if ((*i) + 8 > size) return false;
uint8_t a = raw[(*i)++];
uint8_t b = raw[(*i)++];
@ -411,7 +411,6 @@ static bool fmt_read_string(lua_State *ctx, fmt_segment_t segment, const uint8_t
fprintf(stderr, "%lu %lu", len, *i);
if ((*i) + len > size) return false;
if (*i < 0) return false;
char data[len];
memcpy(data, raw + (*i), len);

View File

@ -18,7 +18,7 @@
static const char *fs_check_path(lua_State *ctx, int i, size_t *psize) {
size_t n;
const char *path = luaL_checklstring(ctx, 1, &n);
const char *path = luaL_checklstring(ctx, i, &n);
size_t real_len = strlen(path);
if (n != real_len) {
@ -71,7 +71,7 @@ static int lib_fs_symlink(lua_State *ctx) {
if (symlink(src, dst) < 0) {
lua_pushnil(ctx);
lua_pushfstring(ctx, "failed to chmod: %s", strerror(errno));
lua_pushfstring(ctx, "failed to symlink: %s", strerror(errno));
return 2;
}

View File

@ -14,6 +14,8 @@ typedef struct {
} http_body_buff_t;
static size_t body_writer(char *ptr, size_t _, size_t size, void *pbuff) {
(void)_;
http_body_buff_t *buff = pbuff;
size_t new_cap = buff->cap;

View File

@ -14,17 +14,29 @@
#define BYTECODE_SIZE (sizeof entry_bytecode - 1)
#endif
#ifndef LOADER
static uint8_t loader_bytecode[] = "";
#define LOADER loader_bytecode
#define LOADER_SIZE (sizeof loader_bytecode - 1)
#endif
static char err_bytecode[] =
"local err = ...;"
"local trace = debug.traceback(nil, 2):match \"^[^\\n]+\\n(.+)$\""
"print(table.concat { \"unhandled error: \", err, \"\\n\", trace })";
static int elf_loader_open_lib(lua_State *ctx) {
lua_pushlstring(ctx, (const char*)LOADER, LOADER_SIZE);
return 1;
}
static void load_modules(lua_State *ctx) {
luaL_openlibs(ctx);
luaL_requiref(ctx, "http", http_open_lib, false);
luaL_requiref(ctx, "fmt", fmt_open_lib, false);
luaL_requiref(ctx, "zlib", zlib_open_lib, false);
luaL_requiref(ctx, "fs", fs_open_lib, false);
luaL_requiref(ctx, "elf_loader", elf_loader_open_lib, false);
}
int main(int argc, const char **argv) {
@ -42,7 +54,7 @@ int main(int argc, const char **argv) {
return 1;
}
for (size_t i = 1; i < argc; i++) {
for (int i = 1; i < argc; i++) {
lua_pushstring(ctx, argv[i]);
}

View File

@ -39,6 +39,7 @@ static int lib_decompress_iter(lua_State *ctx) {
case Z_STREAM_END:
inflateEnd(&stream->stream);
stream->finalized = true;
// fall through
case Z_OK: {
lua_pushlstring(ctx, (const char*)stream->buff, sizeof stream->buff - stream->stream.avail_out);
stream->processed = size - stream->stream.avail_in;

204
src/loader/entry.c Normal file
View File

@ -0,0 +1,204 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <linux/limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <err.h>
#include <errno.h>
#include "loader.h"
#include "slimfs.h"
typedef struct {
char root_dir[PATH_MAX];
struct fuse *fuse;
bool freed;
} *fuse_pthread_data_t;
static slimfs_t fs;
static char *mount_dir;
static void *fuse_pthread_entry(void *pdata) {
slimfs_t fs = pdata;
if (fuse_loop(fs->fuse) < 0) err(1, "Couldn't start fuse loop");
return NULL;
}
static slimfs_t slimfs_mount(const char *target_dir, const char *root_dir, const char *img_path, size_t img_offset) {
slimfs_t fs = slimfs_new(1, (char*[]){ "", NULL }, target_dir, root_dir, img_path, img_offset);
if (fs == NULL) return NULL;
pthread_t thread;
pthread_create(&thread, NULL, fuse_pthread_entry, fs);
return fs;
}
static void handle_close() {
fprintf(stderr, "\nCTRL+C detected, closing SlimFS...\n");
slimfs_free(fs);
rmdir(mount_dir);
exit(0);
}
static int write_flag(const char *file, const char *format, ...) {
int fd = open(file, O_WRONLY);
if (fd < 0) {
warn("Failed to write to %s", file);
return -1;
}
va_list list;
va_start(list, format);
char buff[vsnprintf(NULL, 0, format, list) + 1];
va_end(list);
va_start(list, format);
vsnprintf(buff, sizeof buff, format, list);
va_end(list);
int n = write(fd, buff, sizeof buff - 1);
if (n < 0 || (size_t)n != sizeof buff - 1) {
warn("Failed to write to %s", file);
return -1;
}
close(fd);
return 0;
}
static int err_mount(const char *name) {
warn("Failed to setup virtual mount for %s", name);
return 127;
}
int slimpak_isolate(const char *root_dir, char **argv) {
pid_t pid = fork();
if (pid < 0) err(EXIT_EXECERROR, "fork error");
else if (pid == 0) {
int uid = geteuid();
int gid = getegid();
errno = 0;
// Child is responsible for running the actual command
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) < 0) {
warn("Failed to containerize");
exit(127);
}
if (write_flag("/proc/self/uid_map", "%d %d 1\n", uid, uid) < 0) exit(127);
if (write_flag("/proc/self/setgroups", "deny\n") < 0) exit(127);
if (write_flag("/proc/self/gid_map", "%d %d 1\n", gid, gid) < 0) exit(127);
char *cwd = getcwd(NULL, 0);
chdir(root_dir);
// if (mount(NULL, "/", NULL, MS_REC | MS_SILENT | MS_SLAVE, NULL) < 0) return err_mount("root");
if (mount("/dev", "dev", NULL, MS_REC | MS_SILENT | MS_BIND, NULL) < 0) return err_mount("/dev");
if (mount("/proc", "proc", NULL, MS_REC | MS_SILENT | MS_BIND, NULL) < 0) return err_mount("/proc");
if (mount("/run", "run", NULL, MS_REC | MS_SILENT | MS_BIND, NULL) < 0) return err_mount("/run");
if (chroot(root_dir) < 0) {
warn("Failed to chroot into virtual root");
exit(127);
}
chdir(cwd);
free(cwd);
execv(argv[0], argv);
err(127, "Failed to execute command");
}
else {
int status;
if (waitpid(pid, &status, 0) < 0) {
warn("Failed to get child status");
return -1;
}
if (WIFEXITED(status)) return (uint16_t)WEXITSTATUS(status);
else return -1;
}
return 0;
}
int main(int argc, char **argv) {
const char *self_path = "/proc/self/exe";
const char *temp_base = "/tmp";
const char *slimpack_arg = NULL;
size_t offset = slimpack_get_offset(self_path);
if (argc == 2 && argv[1][0] == '-' && argv[1][1] == '-') {
slimpack_arg = (const char*)argv[1] + 2;
}
if (slimpack_arg && !strcmp(slimpack_arg, "slimpack-offset")) {
printf("%zu\n", offset);
return 0;
}
mount_dir = malloc(strlen(temp_base) + 19 + 1);
strcpy(mount_dir, temp_base);
strcat(mount_dir, "/.slimpack.XXXXXXXX");
if (!mkdtemp(mount_dir)) err(EXIT_EXECERROR, "create mount dir error");
fs = slimfs_mount(mount_dir, "/", self_path, offset);
if (fs == NULL) errx(1, "Couldn't mount SlimFS");
signal(SIGINT, handle_close);
int status;
if (slimpack_arg && !strcmp(slimpack_arg, "slimpack-mount")) {
fprintf(stderr, "The mountpoint is at %s. Press Ctrl+D when you're ready\n", mount_dir);
char buff[4096];
while (read(STDIN_FILENO, buff, sizeof buff) != 0);
slimfs_free(fs);
rmdir(mount_dir);
return 0;
}
if (slimpack_arg && !strcmp(slimpack_arg, "slimpack-shell")) {
status = slimpak_isolate((const char*)mount_dir, (char*[]) { "/bin/bash", NULL });
}
else {
argv[0] = "/entry";
status = slimpak_isolate((const char*)mount_dir, argv);
}
slimfs_free(fs);
rmdir(mount_dir);
if (status < 0) {
err(127, "Failed to start isolated process (status %d)", status);
}
else {
return status;
}
}

16
src/loader/loader.h Normal file
View File

@ -0,0 +1,16 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
// Exit status to use when launching an AppImage fails.
// For applications that assign meanings to exit status codes (e.g. rsync),
// we avoid "cluttering" pre-defined exit status codes by using 127 which
// is known to alias an application exit status and also known as launcher
// error, see SYSTEM(3POSIX).
#define EXIT_EXECERROR 127
ssize_t slimpack_get_offset(const char *executable);
int slimpak_isolate(const char *root_dir, char **argv);
int slimpak_mount(const char *executable, const char *work_dir, const char *root_dir);
int slimpak_unmount(const char *work_dir, const char *root_dir);

228
src/loader/offset.c Normal file
View File

@ -0,0 +1,228 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
#include "loader.h"
#define EI_NIDENT 16
#define ELFCLASS32 1
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define ELFCLASS64 2
#define EI_CLASS 4
#define EI_DATA 5
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ELFDATANATIVE ELFDATA2LSB
#elif __BYTE_ORDER == __BIG_ENDIAN
#define ELFDATANATIVE ELFDATA2MSB
#else
#error "Unknown machine endian"
#endif
typedef struct {
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry; /* Entry point */
uint32_t e_phoff;
uint32_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} elf32_hdr_t;
typedef struct {
uint32_t sh_name;
uint32_t sh_type;
uint32_t sh_flags;
uint32_t sh_addr;
uint32_t sh_offset;
uint32_t sh_size;
uint32_t sh_link;
uint32_t sh_info;
uint32_t sh_addralign;
uint32_t sh_entsize;
} elf32_shdr_t;
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint64_t e_entry; /* Entry point virtual address */
uint64_t e_phoff; /* Program header table file offset */
uint64_t e_shoff; /* Section header table file offset */
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} elf64_hdr_t;
typedef struct {
uint32_t sh_name; /* Section name, index in string tbl */
uint32_t sh_type; /* Type of section */
uint64_t sh_flags; /* Miscellaneous section attributes */
uint64_t sh_addr; /* Section virtual addr at execution */
uint64_t sh_offset; /* Section file offset */
uint64_t sh_size; /* Size of section in bytes */
uint32_t sh_link; /* Index of another section */
uint32_t sh_info; /* Additional section information */
uint64_t sh_addralign; /* Section alignment */
uint64_t sh_entsize; /* Entry size if section holds table */
} elf64_shdr_t;
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
uint32_t n_namesz; /* Name size */
uint32_t n_descsz; /* Content size */
uint32_t n_type; /* Content type */
} Elf32_Nhdr;
typedef Elf32_Nhdr Elf_Nhdr;
static uint16_t file16_to_cpu(uint8_t ident[EI_NIDENT], uint16_t val) {
if (ident[EI_DATA] != ELFDATANATIVE) {
uint16_t a = val & 0xFF;
uint16_t b = (val >> 8) & 0xFF;
val = a << 8 | b;
}
return val;
}
static uint32_t file32_to_cpu(uint8_t ident[EI_NIDENT], uint32_t val) {
if (ident[EI_DATA] != ELFDATANATIVE) {
uint32_t a = val & 0xFF;
uint32_t b = (val >> 8) & 0xFF;
uint32_t c = (val >> 16) & 0xFF;
uint32_t d = (val >> 24) & 0xFF;
val = a << 24 | b << 16 | c << 8 | d;
}
return val;
}
static uint64_t file64_to_cpu(uint8_t ident[EI_NIDENT], uint64_t val) {
if (ident[EI_DATA] != ELFDATANATIVE) {
uint64_t a = val & 0xFF;
uint64_t b = (val >> 8) & 0xFF;
uint64_t c = (val >> 16) & 0xFF;
uint64_t d = (val >> 24) & 0xFF;
uint64_t e = (val >> 32) & 0xFF;
uint64_t f = (val >> 40) & 0xFF;
uint64_t g = (val >> 48) & 0xFF;
uint64_t h = (val >> 56) & 0xFF;
val = a << 56 | b << 48 | c << 40 | d << 32 | e << 24 | f << 16 | g << 8 | h;
}
return val;
}
static ssize_t read_elf32_size(uint8_t ident[EI_NIDENT], FILE *fd) {
ssize_t ret;
fseek(fd, 0, SEEK_SET);
elf32_hdr_t header;
ret = fread(&header, 1, sizeof(header), fd);
if (ret < 0 || ret != sizeof header) {
warn("Read of ELF header failed");
return -1;
}
size_t sh_offset = file32_to_cpu(ident, header.e_shoff);
size_t sh_entry_size = file16_to_cpu(ident, header.e_shentsize);
size_t sh_entry_n = file16_to_cpu(ident, header.e_shnum);
off_t last_shdr_offset = sh_offset + (sh_entry_size * (sh_entry_n - 1));
fseek(fd, last_shdr_offset, SEEK_SET);
elf32_shdr_t sect_header;
ret = fread(&sect_header, 1, sizeof(sect_header), fd);
if (ret < 0 || (size_t) ret != sizeof(sect_header)) {
warn("Read of ELF section header failed");
return -1;
}
/* ELF ends either with the table of section headers (SHT) or with a section. */
off_t sh_end = sh_offset + (sh_entry_size * sh_entry_n);
off_t s_end = file64_to_cpu(ident, sect_header.sh_offset) + file64_to_cpu(ident, sect_header.sh_size);
return sh_end > s_end ? sh_end : s_end;
}
static ssize_t read_elf64_size(uint8_t ident[EI_NIDENT], FILE *fd) {
off_t ret;
fseek(fd, 0, SEEK_SET);
elf64_hdr_t header;
ret = fread(&header, 1, sizeof(header), fd);
if (ret < 0 || (size_t) ret != sizeof(header)) {
warn("Read of ELF header failed");
return -1;
}
size_t sh_offset = file64_to_cpu(ident, header.e_shoff);
size_t sh_entry_size = file16_to_cpu(ident, header.e_shentsize);
size_t sh_entry_n = file16_to_cpu(ident, header.e_shnum);
off_t last_shdr_offset = sh_offset + (sh_entry_size * (sh_entry_n - 1));
fseek(fd, last_shdr_offset, SEEK_SET);
elf64_shdr_t sect_header;
ret = fread(&sect_header, 1, sizeof(sect_header), fd);
if (ret < 0 || ret != sizeof(sect_header)) {
warn("Read of ELF section header failed");
return -1;
}
/* ELF ends either with the table of section headers (SHT) or with a section. */
off_t sht_end = sh_offset + (sh_entry_size * sh_entry_n);
off_t s_end = file64_to_cpu(ident, sect_header.sh_offset) + file64_to_cpu(ident, sect_header.sh_size);
return sht_end > s_end ? sht_end : s_end;
}
ssize_t slimpack_get_offset(const char *executable) {
FILE *fd = fopen(executable, "rb");
if (fd == NULL) {
warn("Cannot open executable");
return -1;
}
uint8_t ident[EI_NIDENT];
off_t ret = fread(ident, 1, EI_NIDENT, fd);
if (ret != EI_NIDENT) {
warn("Read of e_ident failed");
return -1;
}
if (ident[EI_DATA] != ELFDATA2LSB && ident[EI_DATA] != ELFDATA2MSB) {
warnx("Unknown ELF data order %u", ident[EI_DATA]);
return -1;
}
size_t res;
if (ident[EI_CLASS] == ELFCLASS32) res = read_elf32_size(ident, fd);
else if (ident[EI_CLASS] == ELFCLASS64) res = read_elf64_size(ident, fd);
else {
fprintf(stderr, "Unknown ELF class %u\n", ident[EI_CLASS]);
return -1;
}
fclose(fd);
return res;
}

1019
src/loader/slimfs.c Normal file

File diff suppressed because it is too large Load Diff

25
src/loader/slimfs.h Normal file
View File

@ -0,0 +1,25 @@
/*
* License: BSD-style license
* Copyright: Radek Podgorny <radek@podgorny.cz>,
* Bernd Schubert <bernd-schubert@gmx.de>
*/
#pragma once
#include <fuse.h>
#include <squashfuse/squashfuse.h>
#include <stdbool.h>
typedef struct {
struct fuse *fuse;
struct fuse_chan *channel;
struct sqfs image;
char root_dir[PATH_MAX];
char target_dir[PATH_MAX];
} *slimfs_t;
extern struct fuse_operations unionfs_oper;
slimfs_t slimfs_new(int argc, char **argv, const char *target_dir, const char *root_dir, const char *img_path, size_t img_offset);
void slimfs_free(slimfs_t fs);

View File

@ -1,61 +1,7 @@
local ostree = require "ostree";
local flatpak = require "flatpak";
local fs = require "fs";
local loader = [[#!/bin/sh
set -euo pipefail;
cleanup() {
cd /;
if [ "${mountpoint_dir+x}" ]; then
umount "$mountpoint_dir";
fi
if [ "${squashfs_dir+x}" ]; then
umount "$squashfs_dir";
fi
if [ "${tmp_dir+x}" ]; then
rm -rf "$tmp_dir";
fi
}
jail_run() {
unshare -cR $mountpoint_dir $@;
}
trap cleanup EXIT;
marker="#END_OF_"LOADER"_MARKER";
offset=$(( $(grep -abo "$marker" "$PWD/$0" | head -n 1 | cut -d: -f1) + ${#marker} + 1 ));
if [ "${1-}" = "--slimpack-offset" ] || [ "${1-}" = "--appimage-offset" ]; then
echo $offset;
exit 0;
fi
tmp_dir=$(mktemp -d /tmp/.slimpack.XXXXXXXXXXXX);
mkdir "$tmp_dir/squashfs";
squashfuse -o offset=$offset "$PWD/$0" "$tmp_dir/squashfs";
squashfs_dir="$tmp_dir/squashfs";
mkdir "$tmp_dir/mount_point";
unionfs -o suid,dev "$squashfs_dir"=RO:/=RW "$tmp_dir/mount_point";
mountpoint_dir="$tmp_dir/mount_point";
if [ "${1-}" = "--slimpack-dbg" ]; then
jail_run /bin/bash;
elif [ "${1-}" = "--slimpack-dbg-2" ]; then
cd "$mountpoint_dir" && bash;
else
jail_run "/entry" $@;
fi
exit 0;
#END_OF_LOADER_MARKER
]];
local elf_loader = require "elf_loader";
local entry_preifx = [[#!/bin/sh
@ -98,7 +44,7 @@ end
local function write_res(img_path, target)
local f = assert(io.open(target, "wb"));
f:write(loader);
f:write(elf_loader);
local img_f = assert(io.open(img_path, "rb"));

View File

@ -292,7 +292,7 @@ function ostree.dump_node(path, node)
assert(fs.chmod(path, node.mode & 0xFFF));
elseif node.type == "link" then
assert(fs.mkdir(path:match "^(.+)/[^/]+$", true));
assert(fs.symlink(path, node.target));
assert(fs.symlink(node.target, path));
else
error("Unknown node type '" .. node.type .. "'");
end