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

sorttable.c (7869B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * sorttable.c: Sort the kernel's table
      4 *
      5 * Added ORC unwind tables sort support and other updates:
      6 * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
      7 * Shile Zhang <shile.zhang@linux.alibaba.com>
      8 *
      9 * Copyright 2011 - 2012 Cavium, Inc.
     10 *
     11 * Based on code taken from recortmcount.c which is:
     12 *
     13 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
     14 *
     15 * Restructured to fit Linux format, as well as other updates:
     16 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
     17 */
     18
     19/*
     20 * Strategy: alter the vmlinux file in-place.
     21 */
     22
     23#include <sys/types.h>
     24#include <sys/mman.h>
     25#include <sys/stat.h>
     26#include <getopt.h>
     27#include <elf.h>
     28#include <fcntl.h>
     29#include <stdio.h>
     30#include <stdlib.h>
     31#include <string.h>
     32#include <unistd.h>
     33#include <errno.h>
     34#include <pthread.h>
     35
     36#include <tools/be_byteshift.h>
     37#include <tools/le_byteshift.h>
     38
     39#ifndef EM_ARCOMPACT
     40#define EM_ARCOMPACT	93
     41#endif
     42
     43#ifndef EM_XTENSA
     44#define EM_XTENSA	94
     45#endif
     46
     47#ifndef EM_AARCH64
     48#define EM_AARCH64	183
     49#endif
     50
     51#ifndef EM_MICROBLAZE
     52#define EM_MICROBLAZE	189
     53#endif
     54
     55#ifndef EM_ARCV2
     56#define EM_ARCV2	195
     57#endif
     58
     59#ifndef EM_RISCV
     60#define EM_RISCV	243
     61#endif
     62
     63#ifndef EM_LOONGARCH
     64#define EM_LOONGARCH	258
     65#endif
     66
     67static uint32_t (*r)(const uint32_t *);
     68static uint16_t (*r2)(const uint16_t *);
     69static uint64_t (*r8)(const uint64_t *);
     70static void (*w)(uint32_t, uint32_t *);
     71static void (*w2)(uint16_t, uint16_t *);
     72static void (*w8)(uint64_t, uint64_t *);
     73typedef void (*table_sort_t)(char *, int);
     74
     75/*
     76 * Get the whole file as a programming convenience in order to avoid
     77 * malloc+lseek+read+free of many pieces.  If successful, then mmap
     78 * avoids copying unused pieces; else just read the whole file.
     79 * Open for both read and write.
     80 */
     81static void *mmap_file(char const *fname, size_t *size)
     82{
     83	int fd;
     84	struct stat sb;
     85	void *addr = NULL;
     86
     87	fd = open(fname, O_RDWR);
     88	if (fd < 0) {
     89		perror(fname);
     90		return NULL;
     91	}
     92	if (fstat(fd, &sb) < 0) {
     93		perror(fname);
     94		goto out;
     95	}
     96	if (!S_ISREG(sb.st_mode)) {
     97		fprintf(stderr, "not a regular file: %s\n", fname);
     98		goto out;
     99	}
    100
    101	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    102	if (addr == MAP_FAILED) {
    103		fprintf(stderr, "Could not mmap file: %s\n", fname);
    104		goto out;
    105	}
    106
    107	*size = sb.st_size;
    108
    109out:
    110	close(fd);
    111	return addr;
    112}
    113
    114static uint32_t rbe(const uint32_t *x)
    115{
    116	return get_unaligned_be32(x);
    117}
    118
    119static uint16_t r2be(const uint16_t *x)
    120{
    121	return get_unaligned_be16(x);
    122}
    123
    124static uint64_t r8be(const uint64_t *x)
    125{
    126	return get_unaligned_be64(x);
    127}
    128
    129static uint32_t rle(const uint32_t *x)
    130{
    131	return get_unaligned_le32(x);
    132}
    133
    134static uint16_t r2le(const uint16_t *x)
    135{
    136	return get_unaligned_le16(x);
    137}
    138
    139static uint64_t r8le(const uint64_t *x)
    140{
    141	return get_unaligned_le64(x);
    142}
    143
    144static void wbe(uint32_t val, uint32_t *x)
    145{
    146	put_unaligned_be32(val, x);
    147}
    148
    149static void w2be(uint16_t val, uint16_t *x)
    150{
    151	put_unaligned_be16(val, x);
    152}
    153
    154static void w8be(uint64_t val, uint64_t *x)
    155{
    156	put_unaligned_be64(val, x);
    157}
    158
    159static void wle(uint32_t val, uint32_t *x)
    160{
    161	put_unaligned_le32(val, x);
    162}
    163
    164static void w2le(uint16_t val, uint16_t *x)
    165{
    166	put_unaligned_le16(val, x);
    167}
    168
    169static void w8le(uint64_t val, uint64_t *x)
    170{
    171	put_unaligned_le64(val, x);
    172}
    173
    174/*
    175 * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
    176 * the way to -256..-1, to avoid conflicting with real section
    177 * indices.
    178 */
    179#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
    180
    181static inline int is_shndx_special(unsigned int i)
    182{
    183	return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
    184}
    185
    186/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
    187static inline unsigned int get_secindex(unsigned int shndx,
    188					unsigned int sym_offs,
    189					const Elf32_Word *symtab_shndx_start)
    190{
    191	if (is_shndx_special(shndx))
    192		return SPECIAL(shndx);
    193	if (shndx != SHN_XINDEX)
    194		return shndx;
    195	return r(&symtab_shndx_start[sym_offs]);
    196}
    197
    198/* 32 bit and 64 bit are very similar */
    199#include "sorttable.h"
    200#define SORTTABLE_64
    201#include "sorttable.h"
    202
    203static int compare_relative_table(const void *a, const void *b)
    204{
    205	int32_t av = (int32_t)r(a);
    206	int32_t bv = (int32_t)r(b);
    207
    208	if (av < bv)
    209		return -1;
    210	if (av > bv)
    211		return 1;
    212	return 0;
    213}
    214
    215static void sort_relative_table(char *extab_image, int image_size)
    216{
    217	int i = 0;
    218
    219	/*
    220	 * Do the same thing the runtime sort does, first normalize to
    221	 * being relative to the start of the section.
    222	 */
    223	while (i < image_size) {
    224		uint32_t *loc = (uint32_t *)(extab_image + i);
    225		w(r(loc) + i, loc);
    226		i += 4;
    227	}
    228
    229	qsort(extab_image, image_size / 8, 8, compare_relative_table);
    230
    231	/* Now denormalize. */
    232	i = 0;
    233	while (i < image_size) {
    234		uint32_t *loc = (uint32_t *)(extab_image + i);
    235		w(r(loc) - i, loc);
    236		i += 4;
    237	}
    238}
    239
    240static void sort_relative_table_with_data(char *extab_image, int image_size)
    241{
    242	int i = 0;
    243
    244	while (i < image_size) {
    245		uint32_t *loc = (uint32_t *)(extab_image + i);
    246
    247		w(r(loc) + i, loc);
    248		w(r(loc + 1) + i + 4, loc + 1);
    249		/* Don't touch the fixup type or data */
    250
    251		i += sizeof(uint32_t) * 3;
    252	}
    253
    254	qsort(extab_image, image_size / 12, 12, compare_relative_table);
    255
    256	i = 0;
    257	while (i < image_size) {
    258		uint32_t *loc = (uint32_t *)(extab_image + i);
    259
    260		w(r(loc) - i, loc);
    261		w(r(loc + 1) - (i + 4), loc + 1);
    262		/* Don't touch the fixup type or data */
    263
    264		i += sizeof(uint32_t) * 3;
    265	}
    266}
    267
    268static int do_file(char const *const fname, void *addr)
    269{
    270	int rc = -1;
    271	Elf32_Ehdr *ehdr = addr;
    272	table_sort_t custom_sort = NULL;
    273
    274	switch (ehdr->e_ident[EI_DATA]) {
    275	case ELFDATA2LSB:
    276		r	= rle;
    277		r2	= r2le;
    278		r8	= r8le;
    279		w	= wle;
    280		w2	= w2le;
    281		w8	= w8le;
    282		break;
    283	case ELFDATA2MSB:
    284		r	= rbe;
    285		r2	= r2be;
    286		r8	= r8be;
    287		w	= wbe;
    288		w2	= w2be;
    289		w8	= w8be;
    290		break;
    291	default:
    292		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
    293			ehdr->e_ident[EI_DATA], fname);
    294		return -1;
    295	}
    296
    297	if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
    298	    (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) ||
    299	    ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
    300		fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
    301		return -1;
    302	}
    303
    304	switch (r2(&ehdr->e_machine)) {
    305	case EM_386:
    306	case EM_AARCH64:
    307	case EM_RISCV:
    308	case EM_S390:
    309	case EM_X86_64:
    310		custom_sort = sort_relative_table_with_data;
    311		break;
    312	case EM_PARISC:
    313	case EM_PPC:
    314	case EM_PPC64:
    315		custom_sort = sort_relative_table;
    316		break;
    317	case EM_ARCOMPACT:
    318	case EM_ARCV2:
    319	case EM_ARM:
    320	case EM_LOONGARCH:
    321	case EM_MICROBLAZE:
    322	case EM_MIPS:
    323	case EM_XTENSA:
    324		break;
    325	default:
    326		fprintf(stderr, "unrecognized e_machine %d %s\n",
    327			r2(&ehdr->e_machine), fname);
    328		return -1;
    329	}
    330
    331	switch (ehdr->e_ident[EI_CLASS]) {
    332	case ELFCLASS32:
    333		if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) ||
    334		    r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
    335			fprintf(stderr,
    336				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
    337			break;
    338		}
    339		rc = do_sort_32(ehdr, fname, custom_sort);
    340		break;
    341	case ELFCLASS64:
    342		{
    343		Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
    344		if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) ||
    345		    r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
    346			fprintf(stderr,
    347				"unrecognized ET_EXEC/ET_DYN file: %s\n",
    348				fname);
    349			break;
    350		}
    351		rc = do_sort_64(ghdr, fname, custom_sort);
    352		}
    353		break;
    354	default:
    355		fprintf(stderr, "unrecognized ELF class %d %s\n",
    356			ehdr->e_ident[EI_CLASS], fname);
    357		break;
    358	}
    359
    360	return rc;
    361}
    362
    363int main(int argc, char *argv[])
    364{
    365	int i, n_error = 0;  /* gcc-4.3.0 false positive complaint */
    366	size_t size = 0;
    367	void *addr = NULL;
    368
    369	if (argc < 2) {
    370		fprintf(stderr, "usage: sorttable vmlinux...\n");
    371		return 0;
    372	}
    373
    374	/* Process each file in turn, allowing deep failure. */
    375	for (i = 1; i < argc; i++) {
    376		addr = mmap_file(argv[i], &size);
    377		if (!addr) {
    378			++n_error;
    379			continue;
    380		}
    381
    382		if (do_file(argv[i], addr))
    383			++n_error;
    384
    385		munmap(addr, size);
    386	}
    387
    388	return !!n_error;
    389}