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