summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2020-05-26 13:21:59 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2020-05-26 13:21:59 +0000
commite88836b81666de52bc1b18c648db163d6d2d2506 (patch)
tree9784445e23e0b72126c78d8c5d51eb21f958cd6b
parentbed96a8e8aed2b608d16c2d2b44af92bc5162715 (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.c51
-rw-r--r--sys/arch/octeon/include/octboot.h7
-rw-r--r--sys/arch/octeon/stand/rdboot/rdboot.c50
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);
}