From bf8b46c02fc0d70441e939bdb44cdc066e731d5d Mon Sep 17 00:00:00 2001 From: Michalis Pappas Date: Thu, 11 Apr 2024 15:45:16 +0200 Subject: [PATCH] Add ELF binfmt loader Add binfmt loader for ELF. This is the default loader used on execve(). Signed-off-by: Michalis Pappas --- Makefile.uk | 1 + elf_binfmt.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 elf_binfmt.c diff --git a/Makefile.uk b/Makefile.uk index 5c42642..dcf10f1 100644 --- a/Makefile.uk +++ b/Makefile.uk @@ -5,6 +5,7 @@ APPELFLOADER_CFLAGS-$(CONFIG_APPELFLOADER_DEBUG) += -DUK_DEBUG APPELFLOADER_SRCS-y += $(APPELFLOADER_BASE)/main.c APPELFLOADER_SRCS-y += $(APPELFLOADER_BASE)/elf_load.c APPELFLOADER_SRCS-y += $(APPELFLOADER_BASE)/elf_ctx.c +APPELFLOADER_SRCS-y += $(APPELFLOADER_BASE)/elf_binfmt.c APPELFLOADER_SRCS-$(CONFIG_APPELFLOADER_BRK) += $(APPELFLOADER_BASE)/syscalls/brk.c UK_PROVIDED_SYSCALLS-$(CONFIG_APPELFLOADER_BRK) += brk-1 diff --git a/elf_binfmt.c b/elf_binfmt.c new file mode 100644 index 0000000..53d2892 --- /dev/null +++ b/elf_binfmt.c @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ + +#include +#include +#include +#include +#include +#include + +#if CONFIG_LIBUKSWRAND +#include +#endif /* CONFIG_LIBUKSWRAND */ + +#include "elf_prog.h" + +static int uk_binfmt_load_elf(struct uk_binfmt_loader_args *args) +{ + struct elf_prog *prog; + __u64 rand[2]; + int rc; + + UK_ASSERT(args); + UK_ASSERT(args->alloc); + + prog = elf_load_vfs(args->alloc, args->pathname, args->progname); + if (PTRISERR(prog) || !prog) { + if (PTR2ERR(prog) == -ENOEXEC) + return UK_BINFMT_NOT_HANDLED; + return PTR2ERR(prog); + } + + /* Save to private data in case we are requested to unload */ + args->user = (void *)prog; + + uk_pr_debug("%s: ELF loaded to 0x%lx-0x%lx (%lx B)\n", args->progname, + (__u64)prog->vabase, (__u64)prog->vabase + prog->valen, + prog->valen); + uk_pr_debug("%s: Entry at %p\n", args->progname, (void *)prog->entry); + +#if CONFIG_LIBUKSWRAND + uk_swrand_fill_buffer(rand, sizeof(rand)); +#else /* !CONFIG_LIBUKSWRAND */ + /* Without random numbers, use a hardcoded seed */ + uk_pr_warn("%s: Using hard-coded random seed\n", args->progname); + rand[0] = 0xB0B0; + rand[1] = 0xF00D; +#endif /* !CONFIG_LIBUKSWRAND */ + + rc = elf_arg_env_count(&args->argc, args->argv, + &args->envc, args->envp, + args->stack_size); + if (unlikely(rc < 0)) { + elf_unload(prog); + return rc; + } + + elf_ctx_init(&args->ctx, prog, args->progname, + args->argc, args->argv, + args->envc, args->envp, rand); + + return UK_BINFMT_HANDLED; +} + +static int uk_binfmt_unload_elf(struct uk_binfmt_loader_args *args) +{ + UK_ASSERT(args); + UK_ASSERT(args->user); + + elf_unload((struct elf_prog *)args->user); + + return UK_BINFMT_HANDLED; +} + +static struct uk_binfmt_loader elf_loader = { + .name = "ELF loader", + .type = UK_BINFMT_LOADER_TYPE_EXEC, + .ops = { + .load = uk_binfmt_load_elf, + .unload = uk_binfmt_unload_elf + } +}; + +static int uk_binfmt_elf_loader_init(struct uk_init_ctx *init_ctx __unused) +{ + uk_binfmt_register(&elf_loader); + return 0; +} + +uk_late_initcall(uk_binfmt_elf_loader_init, 0);