BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / b8ae0916762df807f6a779edd3d67f0677050757

// Related

Nucleus

Barry ELF execution b8ae091 (3 years, 2 months ago)
diff --git a/task/exec.c b/task/exec.c
new file mode 100644
index 0000000..8f7da4e
--- /dev/null
+++ b/task/exec.c
@@ -0,0 +1,247 @@
+/*
+ * This file deals with loading programs into memory and executing them.  It
+ * parses ELF files for details and loads them into memory, sets up the stack
+ * and finally jumps into user-mode.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <nucleus/memory.h>
+#include <nucleus/task.h>
+#include <nucleus/vfs.h>
+
+/* ELF Types */
+enum ELFType {
+	ELF_NONE,
+	ELF_RELOCATABLE,
+	ELF_EXECUTABLE,
+	ELF_SHARED,
+	ELF_CORE,
+};
+
+/* ELF Program Header Types */
+enum ProgramType {
+	PH_NONE,
+	PH_LOAD,
+	PH_DYNAMIC,
+	PH_INTERPRET,
+	PH_NOTE,
+	PH_TLS = 7,
+};
+
+/* ELF Program Header Flags */
+enum ProgramFlag {
+	PH_EXECUTABLE = 1,
+	PH_WRITABLE = 2,
+	PH_READABLE = 4,
+};
+
+/* ELF Header */
+struct ELFHeader {
+	char magic[4];
+	uint8_t arch;
+	uint8_t endian;
+	uint8_t headerVersion;
+	uint8_t osAbi;
+	uint8_t reserved[8];
+	uint16_t type;
+	uint16_t isa;
+	uint32_t version;
+	uint32_t entry;
+	uint32_t programHeader;
+	uint32_t sectionHeader;
+	uint32_t flags;
+	uint16_t headerSize;
+	uint16_t programEntrySize;
+	uint16_t numProgramEntries;
+	uint16_t sectionEntrySize;
+	uint16_t numSectionEntries;
+	uint16_t sectionNames;
+};
+
+/* ELF Program Header */
+struct ProgramHeader {
+	uint32_t type;
+	uint32_t offset;
+	uint32_t address;
+	uint32_t reserved;
+	uint32_t filesz;
+	uint32_t memsz;
+	uint32_t flags;
+	uint32_t align;
+};
+
+/* Execute a program */
+int
+execve(const char *file, char *argv[], char *envp[])
+{
+	if (!file || !verify_access(file, strnlen(file, PATH_MAX), PROT_READ))
+		return -EFAULT;
+
+	/* Count argv and envp */
+	int argc, argi;
+	if (argv == NULL) argc = 0;
+	else for (argc = 0; argv[argc]; argc++);
+	int envc, envi;
+	if (envp == NULL) envc = 0;
+	else for (envc = 0; envp[envc]; envc++);
+
+	/* Find size of argv and envp strings */
+	size_t ssz = sizeof(int)
+	           + (sizeof(uintptr_t) * (argc + 1))
+	           + (sizeof(uintptr_t) * (envc + 1));
+	for (argi = 0; argi < argc; argi++) {
+		if (!verify_access(argv[argi], strlen(argv[argi]), PROT_READ))
+			return -EFAULT;
+		ssz += strlen(argv[argi]) + 1;
+	}
+	for (envi = 0; envi < envc; envi++) {
+		if (!verify_access(envp[envi], strlen(envp[envi]), PROT_READ))
+			return -EFAULT;
+		ssz += strlen(envp[envi]) + 1;
+	}
+
+	/* Open file */
+	int fd = open(file, O_RDONLY);
+	if (fd < 0)
+		return fd;
+
+	/* Only execute regular files */
+	File *executable = get_file_by_fd(fd);
+	if (!S_ISREG(executable->inode->mode)) {
+		close(fd);
+		return -EACCES;
+	}
+
+	/* Read ELF header */
+	struct ELFHeader header;
+	file_read(executable, (char *) &header, sizeof(struct ELFHeader));
+	if (memcmp(header.magic, "\x7F""ELF", 4) || header.isa != 3) {
+		close(fd);
+		return -ENOEXEC;
+	}
+	if (header.type != ELF_EXECUTABLE) {
+		close(fd);
+		return -ENOEXEC;
+	}
+
+	/*
+	 * POINT OF NO RETURN
+	 */
+
+	current->inSyscall = 0;
+
+	/* Store everything (pointers adjusted) in temporary buffer */
+	uintptr_t esp = 0xE0000000 - ssz;
+	char *istack = kmalloc(ssz);
+	char *isp = istack + ssz;
+	for (envi = envc - 1; envi >= 0 && envi < envc; envi--) {
+		isp -= strlen(envp[envi]) + 1;
+		memcpy(isp, envp[envi], strlen(envp[envi]) + 1);
+		envp[envi] = (char *) (isp - istack) + esp;
+	}
+	if (envp)
+		envp[envc] = NULL;
+	for (argi = argc - 1; argi >= 0 && argi < argc; argi--) {
+		isp -= strlen(argv[argi]) + 1;
+		memcpy(isp, argv[argi], strlen(argv[argi]) + 1);
+		argv[argi] = (char *) (isp - istack) + esp;
+	}
+	if (argv)
+		argv[argc] = NULL;
+	isp -= sizeof(uintptr_t);
+	*((uintptr_t *) isp) = (uintptr_t) NULL;
+	isp -= sizeof(uintptr_t) * envc;
+	memcpy(isp, envp, sizeof(uintptr_t) * envc);
+	isp -= sizeof(uintptr_t);
+	*((uintptr_t *) isp) = (uintptr_t) NULL;
+	isp -= sizeof(uintptr_t) * argc;
+	memcpy(isp, argv, sizeof(uintptr_t) * argc);
+	isp -= sizeof(int);
+	*((int *) isp) = argc;
+
+	/* Destroy previous executable */
+	VMRegion *region;
+	put(current->vm);
+	current->vm = new(&virtualMemoryType);
+
+	/* Program headers */
+	size_t p;
+	off_t off;
+	uintptr_t pgbrk, heapEnd;
+	struct ProgramHeader ph, tlsph;
+	memset(&tlsph, 0, sizeof(struct ProgramHeader));
+	for (p = 0; p < header.numProgramEntries; p++) {
+		off = header.programHeader + (p * header.programEntrySize);
+		executable->pos = off;
+		file_read(executable, (char *) &ph,
+		          sizeof(struct ProgramHeader));
+		if (ph.type != PH_LOAD) {
+//			if (ph.type == PH_TLS)
+			continue;
+		}
+
+		/* Map data into region */
+		mmap((void *) ph.address, ph.filesz, ph.flags, MAP_PRIVATE, fd,
+		     PAGE_ADDR(ph.offset));
+		/* Space left before */
+		if (ph.address % PAGE_SIZE) {
+			memset((void *) PAGE_ADDR(ph.address), 0,
+			       ph.address - PAGE_ADDR(ph.address));
+		}
+		/* Unset memory */
+		if (ph.memsz > ph.filesz) {
+			pgbrk = PAGE_ADDR(ph.address + ph.filesz);
+			if ((ph.address + ph.filesz) % PAGE_SIZE)
+				pgbrk += PAGE_SIZE;
+			memset((void *) ph.address + ph.filesz, 0,
+			       pgbrk - ph.address - ph.filesz);
+			if (ph.memsz > pgbrk - ph.address) {
+				mmap((void *) pgbrk,
+				     ph.memsz - (pgbrk - ph.address),
+				     ph.flags, MAP_PRIVATE | MAP_ANONYMOUS,
+				     -1, 0);
+			}
+		}
+		if (ph.address + ph.memsz > heapEnd)
+			heapEnd = ph.address + ph.memsz;
+	}
+
+	/* Store executable */
+	if (current->executable)
+		put(current->executable);
+	current->executable = get(executable);
+	close(fd);
+
+	/* Stack area */
+	if (current->stack)
+		put(current->stack);
+	current->stack = vm_create_stack();
+	memcpy((void *) esp, istack, ssz);
+	kfree(istack);
+
+	/* Switch to user-mode */
+	asm volatile(
+		"cli;"
+		"mov $0x23, %%ax;"
+		"mov %%ax, %%ds;"
+		"mov %%ax, %%es;"
+		"mov %%ax, %%fs;"
+		"mov %%ax, %%gs;"
+		"mov %%esi, %%eax;"
+		"pushl $0x23;"
+		"pushl %%eax;"
+		"pushf;"
+		"pop %%eax;"
+		"or $0x200, %%eax;"
+		"push %%eax;"
+		"pushl $0x1B;"
+		"pushl %%ebx;"
+		"iret;"
+		: : "b" (header.entry), "S" (esp)
+	);
+	__builtin_unreachable();
+}