firmload.c 2.7 KB

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