1 /* $OpenBSD: firmload.c,v 1.16 2018/08/13 23:12:39 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Theo de Raadt <deraadt@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/syslimits.h> 22 #include <sys/namei.h> 23 #include <sys/vnode.h> 24 #include <sys/errno.h> 25 #include <sys/malloc.h> 26 #include <sys/proc.h> 27 #include <sys/device.h> 28 #include <sys/pledge.h> 29 30 int 31 loadfirmware(const char *name, u_char **bufp, size_t *buflen) 32 { 33 struct proc *p = curproc; 34 struct nameidata nid; 35 char *path, *ptr; 36 struct iovec iov; 37 struct uio uio; 38 struct vattr va; 39 int error; 40 41 if (!rootvp || !vcount(rootvp)) 42 return (EIO); 43 44 path = malloc(MAXPATHLEN, M_TEMP, M_NOWAIT); 45 if (path == NULL) 46 return (ENOMEM); 47 48 if (snprintf(path, MAXPATHLEN, "/etc/firmware/%s", name) >= 49 MAXPATHLEN) { 50 error = ENAMETOOLONG; 51 goto err; 52 } 53 54 NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF|KERNELPATH, 55 UIO_SYSSPACE, path, p); 56 nid.ni_pledge = PLEDGE_RPATH; 57 error = namei(&nid); 58 #ifdef RAMDISK_HOOKS 59 /* try again with mounted disk */ 60 if (error) { 61 if (snprintf(path, MAXPATHLEN, "/mnt/etc/firmware/%s", name) >= 62 MAXPATHLEN) { 63 error = ENAMETOOLONG; 64 goto err; 65 } 66 67 NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF|KERNELPATH, 68 UIO_SYSSPACE, path, p); 69 nid.ni_pledge = PLEDGE_RPATH; 70 error = namei(&nid); 71 } 72 #endif 73 if (error) 74 goto err; 75 error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p); 76 if (error) 77 goto fail; 78 if (nid.ni_vp->v_type != VREG || va.va_size == 0) { 79 error = EINVAL; 80 goto fail; 81 } 82 if (va.va_size > FIRMWARE_MAX) { 83 error = E2BIG; 84 goto fail; 85 } 86 ptr = malloc(va.va_size, M_DEVBUF, M_NOWAIT); 87 if (ptr == NULL) { 88 error = ENOMEM; 89 goto fail; 90 } 91 92 iov.iov_base = ptr; 93 iov.iov_len = va.va_size; 94 uio.uio_iov = &iov; 95 uio.uio_iovcnt = 1; 96 uio.uio_offset = 0; 97 uio.uio_resid = va.va_size; 98 uio.uio_segflg = UIO_SYSSPACE; 99 uio.uio_rw = UIO_READ; 100 uio.uio_procp = p; 101 102 error = VOP_READ(nid.ni_vp, &uio, 0, p->p_ucred); 103 104 if (error == 0) { 105 *bufp = ptr; 106 *buflen = va.va_size; 107 } else 108 free(ptr, M_DEVBUF, va.va_size); 109 110 fail: 111 vput(nid.ni_vp); 112 err: 113 free(path, M_TEMP, MAXPATHLEN); 114 return (error); 115 } 116