earlycpio.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* ----------------------------------------------------------------------- *
  2. *
  3. * Copyright 2012 Intel Corporation; author H. Peter Anvin
  4. *
  5. * This file is part of the Linux kernel, and is made available
  6. * under the terms of the GNU General Public License version 2, as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * ----------------------------------------------------------------------- */
  15. /*
  16. * earlycpio.c
  17. *
  18. * Find a specific cpio member; must precede any compressed content.
  19. * This is used to locate data items in the initramfs used by the
  20. * kernel itself during early boot (before the main initramfs is
  21. * decompressed.) It is the responsibility of the initramfs creator
  22. * to ensure that these items are uncompressed at the head of the
  23. * blob. Depending on the boot loader or package tool that may be a
  24. * separate file or part of the same file.
  25. */
  26. #include <linux/earlycpio.h>
  27. #include <linux/kernel.h>
  28. #include <linux/string.h>
  29. enum cpio_fields {
  30. C_MAGIC,
  31. C_INO,
  32. C_MODE,
  33. C_UID,
  34. C_GID,
  35. C_NLINK,
  36. C_MTIME,
  37. C_FILESIZE,
  38. C_MAJ,
  39. C_MIN,
  40. C_RMAJ,
  41. C_RMIN,
  42. C_NAMESIZE,
  43. C_CHKSUM,
  44. C_NFIELDS
  45. };
  46. /**
  47. * cpio_data find_cpio_data - Search for files in an uncompressed cpio
  48. * @path: The directory to search for, including a slash at the end
  49. * @data: Pointer to the the cpio archive or a header inside
  50. * @len: Remaining length of the cpio based on data pointer
  51. * @nextoff: When a matching file is found, this is the offset from the
  52. * beginning of the cpio to the beginning of the next file, not the
  53. * matching file itself. It can be used to iterate through the cpio
  54. * to find all files inside of a directory path.
  55. *
  56. * @return: struct cpio_data containing the address, length and
  57. * filename (with the directory path cut off) of the found file.
  58. * If you search for a filename and not for files in a directory,
  59. * pass the absolute path of the filename in the cpio and make sure
  60. * the match returned an empty filename string.
  61. */
  62. struct cpio_data find_cpio_data(const char *path, void *data,
  63. size_t len, long *nextoff)
  64. {
  65. const size_t cpio_header_len = 8*C_NFIELDS - 2;
  66. struct cpio_data cd = { NULL, 0, "" };
  67. const char *p, *dptr, *nptr;
  68. unsigned int ch[C_NFIELDS], *chp, v;
  69. unsigned char c, x;
  70. size_t mypathsize = strlen(path);
  71. int i, j;
  72. p = data;
  73. while (len > cpio_header_len) {
  74. if (!*p) {
  75. /* All cpio headers need to be 4-byte aligned */
  76. p += 4;
  77. len -= 4;
  78. continue;
  79. }
  80. j = 6; /* The magic field is only 6 characters */
  81. chp = ch;
  82. for (i = C_NFIELDS; i; i--) {
  83. v = 0;
  84. while (j--) {
  85. v <<= 4;
  86. c = *p++;
  87. x = c - '0';
  88. if (x < 10) {
  89. v += x;
  90. continue;
  91. }
  92. x = (c | 0x20) - 'a';
  93. if (x < 6) {
  94. v += x + 10;
  95. continue;
  96. }
  97. goto quit; /* Invalid hexadecimal */
  98. }
  99. *chp++ = v;
  100. j = 8; /* All other fields are 8 characters */
  101. }
  102. if ((ch[C_MAGIC] - 0x070701) > 1)
  103. goto quit; /* Invalid magic */
  104. len -= cpio_header_len;
  105. dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4);
  106. nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4);
  107. if (nptr > p + len || dptr < p || nptr < dptr)
  108. goto quit; /* Buffer overrun */
  109. if ((ch[C_MODE] & 0170000) == 0100000 &&
  110. ch[C_NAMESIZE] >= mypathsize &&
  111. !memcmp(p, path, mypathsize)) {
  112. *nextoff = (long)nptr - (long)data;
  113. if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) {
  114. pr_warn(
  115. "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n",
  116. p, MAX_CPIO_FILE_NAME);
  117. }
  118. strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME);
  119. cd.data = (void *)dptr;
  120. cd.size = ch[C_FILESIZE];
  121. return cd; /* Found it! */
  122. }
  123. len -= (nptr - p);
  124. p = nptr;
  125. }
  126. quit:
  127. return cd;
  128. }