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