earlycpio.c 3.6 KB

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