Blame view

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