1 /* $OpenBSD: firmload.c,v 1.12 2015/03/13 23:05:04 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 29 int 30 loadfirmware(const char *name, u_char **bufp, size_t *buflen) 31 { 32 struct proc *p = curproc; 33 struct nameidata nid; 34 char *path, *ptr; 35 struct iovec iov; 36 struct uio uio; 37 struct vattr va; 38 int error; 39 40 if (!rootvp || !vcount(rootvp)) 41 return (EIO); 42 43 path = malloc(MAXPATHLEN, M_TEMP, M_NOWAIT); 44 if (path == NULL) 45 return (ENOMEM); 46 47 if (snprintf(path, MAXPATHLEN, "/etc/firmware/%s", name) >= 48 MAXPATHLEN) { 49 error = ENAMETOOLONG; 50 goto err; 51 } 52 53 NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, path, p); 54 error = namei(&nid); 55 #ifdef RAMDISK_HOOKS 56 /* try again with mounted disk */ 57 if (error) { 58 if (snprintf(path, MAXPATHLEN, "/mnt/etc/firmware/%s", name) >= 59 MAXPATHLEN) { 60 error = ENAMETOOLONG; 61 goto err; 62 } 63 64 NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, path, p); 65 error = namei(&nid); 66 } 67 #endif 68 if (error) 69 goto err; 70 error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p); 71 if (error) 72 goto fail; 73 if (nid.ni_vp->v_type != VREG || va.va_size == 0) { 74 error = EINVAL; 75 goto fail; 76 } 77 if (va.va_size > FIRMWARE_MAX) { 78 error = E2BIG; 79 goto fail; 80 } 81 ptr = malloc(va.va_size, M_DEVBUF, M_NOWAIT); 82 if (ptr == NULL) { 83 error = ENOMEM; 84 goto fail; 85 } 86 87 iov.iov_base = ptr; 88 iov.iov_len = va.va_size; 89 uio.uio_iov = &iov; 90 uio.uio_iovcnt = 1; 91 uio.uio_offset = 0; 92 uio.uio_resid = va.va_size; 93 uio.uio_segflg = UIO_SYSSPACE; 94 uio.uio_rw = UIO_READ; 95 uio.uio_procp = p; 96 97 error = VOP_READ(nid.ni_vp, &uio, 0, p->p_ucred); 98 99 if (error == 0) { 100 *bufp = ptr; 101 *buflen = va.va_size; 102 } else 103 free(ptr, M_DEVBUF, 0); 104 105 fail: 106 vput(nid.ni_vp); 107 err: 108 if (path) 109 free(path, M_TEMP, 0); 110 return (error); 111 } 112