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