diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2020-05-26 13:21:59 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2020-05-26 13:21:59 +0000 |
commit | e88836b81666de52bc1b18c648db163d6d2d2506 (patch) | |
tree | 9784445e23e0b72126c78d8c5d51eb21f958cd6b | |
parent | bed96a8e8aed2b608d16c2d2b44af92bc5162715 (diff) |
Rework kernel loading with octboot(4)
Load the kernel image from the filesystem upfront in rdboot and pass
the loaded image to octboot(4)'s kexec call in a memory buffer. As a
result, octboot(4) does not rely on a mounted filesystem.
OK deraadt@
-rw-r--r-- | sys/arch/octeon/dev/octboot.c | 51 | ||||
-rw-r--r-- | sys/arch/octeon/include/octboot.h | 7 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/rdboot.c | 50 |
3 files changed, 61 insertions, 47 deletions
diff --git a/sys/arch/octeon/dev/octboot.c b/sys/arch/octeon/dev/octboot.c index 659b165e632..22779986c27 100644 --- a/sys/arch/octeon/dev/octboot.c +++ b/sys/arch/octeon/dev/octboot.c @@ -1,7 +1,7 @@ -/* $OpenBSD: octboot.c,v 1.1 2019/07/17 14:36:32 visa Exp $ */ +/* $OpenBSD: octboot.c,v 1.2 2020/05/26 13:21:58 visa Exp $ */ /* - * Copyright (c) 2019 Visa Hankala + * Copyright (c) 2019-2020 Visa Hankala * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,9 +20,7 @@ #include <sys/systm.h> #include <sys/exec_elf.h> #include <sys/malloc.h> -#include <sys/namei.h> #include <sys/proc.h> -#include <sys/vnode.h> #include <uvm/uvm_extern.h> @@ -36,7 +34,7 @@ typedef void (*kentry)(register_t, register_t, register_t, register_t); #define PRIMARY 1 int octboot_kexec(struct octboot_kexec_args *, struct proc *); -int octboot_read(struct proc *, struct vnode *, void *, size_t, off_t); +int octboot_read(struct octboot_kexec_args *, void *, size_t, off_t); uint64_t octeon_boot_entry; uint32_t octeon_boot_ready; @@ -94,29 +92,12 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) Elf_Ehdr eh; Elf_Phdr *ph = NULL; Elf_Shdr *sh = NULL; - struct nameidata nid; - struct vattr va; paddr_t ekern = 0, elfp, maxp = 0, off, pa, shp; size_t len, phsize, shsize, shstrsize, size; char *argbuf = NULL, *argptr; char *shstr = NULL; int argc = 0, error, havesyms = 0, i, nalloc = 0; - NDINIT(&nid, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, kargs->path, p); - error = namei(&nid); - if (error != 0) - return error; - error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p); - if (error != 0) - goto fail; - if (nid.ni_vp->v_type != VREG || va.va_size == 0) { - error = EINVAL; - goto fail; - } - error = VOP_ACCESS(nid.ni_vp, VREAD, p->p_ucred, p); - if (error != 0) - goto fail; - /* * Load kernel arguments into a temporary buffer. * This also translates the userspace argv pointers to kernel pointers. @@ -140,7 +121,7 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) /* * Read the headers and validate them. */ - error = octboot_read(p, nid.ni_vp, &eh, sizeof(eh), 0); + error = octboot_read(kargs, &eh, sizeof(eh), 0); if (error != 0) goto fail; @@ -151,7 +132,7 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) goto fail; } phsize = eh.e_phnum * sizeof(Elf_Phdr); - error = octboot_read(p, nid.ni_vp, ph, phsize, eh.e_phoff); + error = octboot_read(kargs, ph, phsize, eh.e_phoff); if (error != 0) goto fail; @@ -162,7 +143,7 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) goto fail; } shsize = eh.e_shnum * sizeof(Elf_Shdr); - error = octboot_read(p, nid.ni_vp, sh, shsize, eh.e_shoff); + error = octboot_read(kargs, sh, shsize, eh.e_shoff); if (error != 0) goto fail; @@ -208,7 +189,7 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) if (ph[i].p_type != PT_LOAD) continue; - error = octboot_read(p, nid.ni_vp, (caddr_t)ph[i].p_paddr, + error = octboot_read(kargs, (caddr_t)ph[i].p_paddr, ph[i].p_filesz, ph[i].p_offset); if (error != 0) goto fail; @@ -250,7 +231,7 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) error = ENOMEM; goto fail; } - error = octboot_read(p, nid.ni_vp, shstr, shstrsize, + error = octboot_read(kargs, shstr, shstrsize, sh[eh.e_shstrndx].sh_offset); if (error != 0) goto fail; @@ -269,7 +250,7 @@ octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p) error = ENOMEM; goto fail; } - error = octboot_read(p, nid.ni_vp, + error = octboot_read(kargs, (caddr_t)PHYS_TO_CKSEG0(maxp), sh[i].sh_size, sh[i].sh_offset); maxp += bsize; @@ -366,22 +347,14 @@ fail: free(sh, M_TEMP, shsize); free(ph, M_TEMP, phsize); free(argbuf, M_TEMP, PAGE_SIZE); - vput(nid.ni_vp); return error; } int -octboot_read(struct proc *p, struct vnode *vp, void *buf, size_t size, +octboot_read(struct octboot_kexec_args *kargs, void *buf, size_t size, off_t off) { - size_t resid; - int error; - - error = vn_rdwr(UIO_READ, vp, buf, size, off, UIO_SYSSPACE, 0, - p->p_ucred, &resid, p); - if (error != 0) - return error; - if (resid != 0) + if (off + size < off || off + size > kargs->klen) return ENOEXEC; - return 0; + return copyin(kargs->kimg + off, buf, size); } diff --git a/sys/arch/octeon/include/octboot.h b/sys/arch/octeon/include/octboot.h index 60c9f300169..12a62f87354 100644 --- a/sys/arch/octeon/include/octboot.h +++ b/sys/arch/octeon/include/octboot.h @@ -1,7 +1,7 @@ -/* $OpenBSD: octboot.h,v 1.1 2019/07/17 14:36:32 visa Exp $ */ +/* $OpenBSD: octboot.h,v 1.2 2020/05/26 13:21:58 visa Exp $ */ /* - * Copyright (c) 2019 Visa Hankala + * Copyright (c) 2019-2020 Visa Hankala * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,7 +24,8 @@ #define OCTBOOT_MAX_ARGS 8 /* maximum number of boot arguments */ struct octboot_kexec_args { - const char *path; /* kernel path */ + char *kimg; /* kernel image buffer */ + size_t klen; /* size of kernel image */ char *argv[OCTBOOT_MAX_ARGS]; /* kernel boot arguments */ }; diff --git a/sys/arch/octeon/stand/rdboot/rdboot.c b/sys/arch/octeon/stand/rdboot/rdboot.c index 2a215eb13f9..540a7a5d20a 100644 --- a/sys/arch/octeon/stand/rdboot/rdboot.c +++ b/sys/arch/octeon/stand/rdboot/rdboot.c @@ -1,7 +1,7 @@ -/* $OpenBSD: rdboot.c,v 1.4 2020/05/25 13:04:25 visa Exp $ */ +/* $OpenBSD: rdboot.c,v 1.5 2020/05/26 13:21:58 visa Exp $ */ /* - * Copyright (c) 2019 Visa Hankala + * Copyright (c) 2019-2020 Visa Hankala * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,12 +22,14 @@ #include <sys/mount.h> #include <sys/reboot.h> #include <sys/select.h> +#include <sys/stat.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <paths.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <termios.h> #include <unistd.h> @@ -150,17 +152,47 @@ void kexec(void) { struct octboot_kexec_args kargs; + struct stat sb; char boothowtostr[32]; char rootdev[32]; + char *kimg = NULL; const char *path; - int argc, ret; + ssize_t n; + off_t pos; + int argc, fd = -1, ret; path = disk_open(cmd.path); if (path == NULL) return; + fd = open(path, O_RDONLY); + if (fd == -1) + goto load_failed; + if (fstat(fd, &sb) == -1) + goto load_failed; + if (!S_ISREG(sb.st_mode) || sb.st_size == 0) { + errno = ENOEXEC; + goto load_failed; + } + + kimg = malloc(sb.st_size); + if (kimg == NULL) + goto load_failed; + + pos = 0; + while (pos < sb.st_size) { + n = read(fd, kimg + pos, sb.st_size - pos); + if (n == -1) + goto load_failed; + pos += n; + } + + close(fd); + disk_close(); + memset(&kargs, 0, sizeof(kargs)); - kargs.path = path; + kargs.kimg = kimg; + kargs.klen = sb.st_size; argc = 0; if (cmd.boothowto != 0) { snprintf(boothowtostr, sizeof(boothowtostr), "boothowto=%d", @@ -184,6 +216,14 @@ kexec(void) cmd.path, strerror(errno)); else fprintf(stderr, "kexec() returned unexpectedly\n"); - + free(kimg); + return; + +load_failed: + fprintf(stderr, "failed to load kernel %s: %s\n", + cmd.path, strerror(errno)); + if (fd != -1) + close(fd); disk_close(); + free(kimg); } |