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