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

addnote.c (6878B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Program to hack in a PT_NOTE program header entry in an ELF file.
      4 * This is needed for OF on RS/6000s to load an image correctly.
      5 * Note that OF needs a program header entry for the note, not an
      6 * ELF section.
      7 *
      8 * Copyright 2000 Paul Mackerras.
      9 *
     10 * Adapted for 64 bit little endian images by Andrew Tauferner.
     11 *
     12 * Usage: addnote zImage
     13 */
     14#include <stdio.h>
     15#include <stdlib.h>
     16#include <fcntl.h>
     17#include <unistd.h>
     18#include <string.h>
     19
     20/* CHRP note section */
     21static const char arch[] = "PowerPC";
     22
     23#define N_DESCR	6
     24unsigned int descr[N_DESCR] = {
     25	0xffffffff,		/* real-mode = true */
     26	0x02000000,		/* real-base, i.e. where we expect OF to be */
     27	0xffffffff,		/* real-size */
     28	0xffffffff,		/* virt-base */
     29	0xffffffff,		/* virt-size */
     30	0x4000,			/* load-base */
     31};
     32
     33/* RPA note section */
     34static const char rpaname[] = "IBM,RPA-Client-Config";
     35
     36/*
     37 * Note: setting ignore_my_client_config *should* mean that OF ignores
     38 * all the other fields, but there is a firmware bug which means that
     39 * it looks at the splpar field at least.  So these values need to be
     40 * reasonable.
     41 */
     42#define N_RPA_DESCR	8
     43unsigned int rpanote[N_RPA_DESCR] = {
     44	0,			/* lparaffinity */
     45	64,			/* min_rmo_size */
     46	0,			/* min_rmo_percent */
     47	40,			/* max_pft_size */
     48	1,			/* splpar */
     49	-1,			/* min_load */
     50	0,			/* new_mem_def */
     51	1,			/* ignore_my_client_config */
     52};
     53
     54#define ROUNDUP(len)	(((len) + 3) & ~3)
     55
     56unsigned char buf[1024];
     57#define ELFDATA2LSB     1
     58#define ELFDATA2MSB     2
     59static int e_data = ELFDATA2MSB;
     60#define ELFCLASS32      1
     61#define ELFCLASS64      2
     62static int e_class = ELFCLASS32;
     63
     64#define GET_16BE(off)	((buf[off] << 8) + (buf[(off)+1]))
     65#define GET_32BE(off)	((GET_16BE(off) << 16U) + GET_16BE((off)+2U))
     66#define GET_64BE(off)	((((unsigned long long)GET_32BE(off)) << 32ULL) + \
     67			((unsigned long long)GET_32BE((off)+4ULL)))
     68#define PUT_16BE(off, v)(buf[off] = ((v) >> 8) & 0xff, \
     69			 buf[(off) + 1] = (v) & 0xff)
     70#define PUT_32BE(off, v)(PUT_16BE((off), (v) >> 16L), PUT_16BE((off) + 2, (v)))
     71#define PUT_64BE(off, v)((PUT_32BE((off), (v) >> 32L), \
     72			  PUT_32BE((off) + 4, (v))))
     73
     74#define GET_16LE(off)	((buf[off]) + (buf[(off)+1] << 8))
     75#define GET_32LE(off)	(GET_16LE(off) + (GET_16LE((off)+2U) << 16U))
     76#define GET_64LE(off)	((unsigned long long)GET_32LE(off) + \
     77			(((unsigned long long)GET_32LE((off)+4ULL)) << 32ULL))
     78#define PUT_16LE(off, v) (buf[off] = (v) & 0xff, \
     79			  buf[(off) + 1] = ((v) >> 8) & 0xff)
     80#define PUT_32LE(off, v) (PUT_16LE((off), (v)), PUT_16LE((off) + 2, (v) >> 16L))
     81#define PUT_64LE(off, v) (PUT_32LE((off), (v)), PUT_32LE((off) + 4, (v) >> 32L))
     82
     83#define GET_16(off)	(e_data == ELFDATA2MSB ? GET_16BE(off) : GET_16LE(off))
     84#define GET_32(off)	(e_data == ELFDATA2MSB ? GET_32BE(off) : GET_32LE(off))
     85#define GET_64(off)	(e_data == ELFDATA2MSB ? GET_64BE(off) : GET_64LE(off))
     86#define PUT_16(off, v)	(e_data == ELFDATA2MSB ? PUT_16BE(off, v) : \
     87			 PUT_16LE(off, v))
     88#define PUT_32(off, v)  (e_data == ELFDATA2MSB ? PUT_32BE(off, v) : \
     89			 PUT_32LE(off, v))
     90#define PUT_64(off, v)  (e_data == ELFDATA2MSB ? PUT_64BE(off, v) : \
     91			 PUT_64LE(off, v))
     92
     93/* Structure of an ELF file */
     94#define E_IDENT		0	/* ELF header */
     95#define	E_PHOFF		(e_class == ELFCLASS32 ? 28 : 32)
     96#define E_PHENTSIZE	(e_class == ELFCLASS32 ? 42 : 54)
     97#define E_PHNUM		(e_class == ELFCLASS32 ? 44 : 56)
     98#define E_HSIZE		(e_class == ELFCLASS32 ? 52 : 64)
     99
    100#define EI_MAGIC	0	/* offsets in E_IDENT area */
    101#define EI_CLASS	4
    102#define EI_DATA		5
    103
    104#define PH_TYPE		0	/* ELF program header */
    105#define PH_OFFSET	(e_class == ELFCLASS32 ? 4 : 8)
    106#define PH_FILESZ	(e_class == ELFCLASS32 ? 16 : 32)
    107#define PH_HSIZE	(e_class == ELFCLASS32 ? 32 : 56)
    108
    109#define PT_NOTE		4	/* Program header type = note */
    110
    111
    112unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
    113
    114int
    115main(int ac, char **av)
    116{
    117	int fd, n, i;
    118	unsigned long ph, ps, np;
    119	long nnote, nnote2, ns;
    120
    121	if (ac != 2) {
    122		fprintf(stderr, "Usage: %s elf-file\n", av[0]);
    123		exit(1);
    124	}
    125	fd = open(av[1], O_RDWR);
    126	if (fd < 0) {
    127		perror(av[1]);
    128		exit(1);
    129	}
    130
    131	nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
    132	nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
    133
    134	n = read(fd, buf, sizeof(buf));
    135	if (n < 0) {
    136		perror("read");
    137		exit(1);
    138	}
    139
    140	if (memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
    141		goto notelf;
    142	e_class = buf[E_IDENT+EI_CLASS];
    143	if (e_class != ELFCLASS32 && e_class != ELFCLASS64)
    144		goto notelf;
    145	e_data = buf[E_IDENT+EI_DATA];
    146	if (e_data != ELFDATA2MSB && e_data != ELFDATA2LSB)
    147		goto notelf;
    148	if (n < E_HSIZE)
    149		goto notelf;
    150
    151	ph = (e_class == ELFCLASS32 ? GET_32(E_PHOFF) : GET_64(E_PHOFF));
    152	ps = GET_16(E_PHENTSIZE);
    153	np = GET_16(E_PHNUM);
    154	if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
    155		goto notelf;
    156	if (ph + (np + 2) * ps + nnote + nnote2 > n)
    157		goto nospace;
    158
    159	for (i = 0; i < np; ++i) {
    160		if (GET_32(ph + PH_TYPE) == PT_NOTE) {
    161			fprintf(stderr, "%s already has a note entry\n",
    162				av[1]);
    163			exit(0);
    164		}
    165		ph += ps;
    166	}
    167
    168	/* XXX check that the area we want to use is all zeroes */
    169	for (i = 0; i < 2 * ps + nnote + nnote2; ++i)
    170		if (buf[ph + i] != 0)
    171			goto nospace;
    172
    173	/* fill in the program header entry */
    174	ns = ph + 2 * ps;
    175	PUT_32(ph + PH_TYPE, PT_NOTE);
    176	if (e_class == ELFCLASS32)
    177		PUT_32(ph + PH_OFFSET, ns);
    178	else
    179		PUT_64(ph + PH_OFFSET, ns);
    180
    181	if (e_class == ELFCLASS32)
    182		PUT_32(ph + PH_FILESZ, nnote);
    183	else
    184		PUT_64(ph + PH_FILESZ, nnote);
    185
    186	/* fill in the note area we point to */
    187	/* XXX we should probably make this a proper section */
    188	PUT_32(ns, strlen(arch) + 1);
    189	PUT_32(ns + 4, N_DESCR * 4);
    190	PUT_32(ns + 8, 0x1275);
    191	strcpy((char *) &buf[ns + 12], arch);
    192	ns += 12 + strlen(arch) + 1;
    193	for (i = 0; i < N_DESCR; ++i, ns += 4)
    194		PUT_32BE(ns, descr[i]);
    195
    196	/* fill in the second program header entry and the RPA note area */
    197	ph += ps;
    198	PUT_32(ph + PH_TYPE, PT_NOTE);
    199	if (e_class == ELFCLASS32)
    200		PUT_32(ph + PH_OFFSET, ns);
    201	else
    202		PUT_64(ph + PH_OFFSET, ns);
    203
    204	if (e_class == ELFCLASS32)
    205		PUT_32(ph + PH_FILESZ, nnote);
    206	else
    207		PUT_64(ph + PH_FILESZ, nnote2);
    208
    209	/* fill in the note area we point to */
    210	PUT_32(ns, strlen(rpaname) + 1);
    211	PUT_32(ns + 4, sizeof(rpanote));
    212	PUT_32(ns + 8, 0x12759999);
    213	strcpy((char *) &buf[ns + 12], rpaname);
    214	ns += 12 + ROUNDUP(strlen(rpaname) + 1);
    215	for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
    216		PUT_32BE(ns, rpanote[i]);
    217
    218	/* Update the number of program headers */
    219	PUT_16(E_PHNUM, np + 2);
    220
    221	/* write back */
    222	i = lseek(fd, (long) 0, SEEK_SET);
    223	if (i < 0) {
    224		perror("lseek");
    225		exit(1);
    226	}
    227	i = write(fd, buf, n);
    228	if (i < 0) {
    229		perror("write");
    230		exit(1);
    231	}
    232	if (i < n) {
    233		fprintf(stderr, "%s: write truncated\n", av[1]);
    234		exit(1);
    235	}
    236
    237	exit(0);
    238
    239 notelf:
    240	fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]);
    241	exit(1);
    242
    243 nospace:
    244	fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
    245		av[1]);
    246	exit(1);
    247}