cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

earlycpio.c (3637B)


      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
     24enum 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 * 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 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
     59struct cpio_data find_cpio_data(const char *path, void *data,
     60				size_t len,  long *nextoff)
     61{
     62	const size_t cpio_header_len = 8*C_NFIELDS - 2;
     63	struct cpio_data cd = { NULL, 0, "" };
     64	const char *p, *dptr, *nptr;
     65	unsigned int ch[C_NFIELDS], *chp, v;
     66	unsigned char c, x;
     67	size_t mypathsize = strlen(path);
     68	int i, j;
     69
     70	p = data;
     71
     72	while (len > cpio_header_len) {
     73		if (!*p) {
     74			/* All cpio headers need to be 4-byte aligned */
     75			p += 4;
     76			len -= 4;
     77			continue;
     78		}
     79
     80		j = 6;		/* The magic field is only 6 characters */
     81		chp = ch;
     82		for (i = C_NFIELDS; i; i--) {
     83			v = 0;
     84			while (j--) {
     85				v <<= 4;
     86				c = *p++;
     87
     88				x = c - '0';
     89				if (x < 10) {
     90					v += x;
     91					continue;
     92				}
     93
     94				x = (c | 0x20) - 'a';
     95				if (x < 6) {
     96					v += x + 10;
     97					continue;
     98				}
     99
    100				goto quit; /* Invalid hexadecimal */
    101			}
    102			*chp++ = v;
    103			j = 8;	/* All other fields are 8 characters */
    104		}
    105
    106		if ((ch[C_MAGIC] - 0x070701) > 1)
    107			goto quit; /* Invalid magic */
    108
    109		len -= cpio_header_len;
    110
    111		dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4);
    112		nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4);
    113
    114		if (nptr > p + len || dptr < p || nptr < dptr)
    115			goto quit; /* Buffer overrun */
    116
    117		if ((ch[C_MODE] & 0170000) == 0100000 &&
    118		    ch[C_NAMESIZE] >= mypathsize &&
    119		    !memcmp(p, path, mypathsize)) {
    120
    121			if (nextoff)
    122				*nextoff = (long)nptr - (long)data;
    123
    124			if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) {
    125				pr_warn(
    126				"File %s exceeding MAX_CPIO_FILE_NAME [%d]\n",
    127				p, MAX_CPIO_FILE_NAME);
    128			}
    129			strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME);
    130
    131			cd.data = (void *)dptr;
    132			cd.size = ch[C_FILESIZE];
    133			return cd; /* Found it! */
    134		}
    135		len -= (nptr - p);
    136		p = nptr;
    137	}
    138
    139quit:
    140	return cd;
    141}