File Index
Files and directories
Sign in
FILE

relacheck.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm64/kernel/pi/relacheck.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2023 - Google LLC
  4 * Author: Ard Biesheuvel <ardb@google.com>
  5 */
  6
  7#include <elf.h>
  8#include <fcntl.h>
  9#include <stdbool.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <string.h>
 13#include <sys/mman.h>
 14#include <sys/stat.h>
 15#include <sys/types.h>
 16#include <unistd.h>
 17
 18#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 19#define HOST_ORDER ELFDATA2LSB
 20#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 21#define HOST_ORDER ELFDATA2MSB
 22#endif
 23
 24static Elf64_Ehdr *ehdr;
 25static Elf64_Shdr *shdr;
 26static const char *strtab;
 27static bool swap;
 28
 29static uint64_t swab_elfxword(uint64_t val)
 30{
 31	return swap ? __builtin_bswap64(val) : val;
 32}
 33
 34static uint32_t swab_elfword(uint32_t val)
 35{
 36	return swap ? __builtin_bswap32(val) : val;
 37}
 38
 39static uint16_t swab_elfhword(uint16_t val)
 40{
 41	return swap ? __builtin_bswap16(val) : val;
 42}
 43
 44int main(int argc, char *argv[])
 45{
 46	struct stat stat;
 47	int fd, ret;
 48
 49	if (argc < 3) {
 50		fprintf(stderr, "file arguments missing\n");
 51		exit(EXIT_FAILURE);
 52	}
 53
 54	fd = open(argv[1], O_RDWR);
 55	if (fd < 0) {
 56		fprintf(stderr, "failed to open %s\n", argv[1]);
 57		exit(EXIT_FAILURE);
 58	}
 59
 60	ret = fstat(fd, &stat);
 61	if (ret < 0) {
 62		fprintf(stderr, "failed to stat() %s\n", argv[1]);
 63		exit(EXIT_FAILURE);
 64	}
 65
 66	ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 67	if (ehdr == MAP_FAILED) {
 68		fprintf(stderr, "failed to mmap() %s\n", argv[1]);
 69		exit(EXIT_FAILURE);
 70	}
 71
 72	swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
 73	shdr = (void *)ehdr + swab_elfxword(ehdr->e_shoff);
 74	strtab = (void *)ehdr +
 75		 swab_elfxword(shdr[swab_elfhword(ehdr->e_shstrndx)].sh_offset);
 76
 77	for (int i = 0; i < swab_elfhword(ehdr->e_shnum); i++) {
 78		unsigned long info, flags;
 79		bool prel64 = false;
 80		Elf64_Rela *rela;
 81		int numrela;
 82
 83		if (swab_elfword(shdr[i].sh_type) != SHT_RELA)
 84			continue;
 85
 86		/* only consider RELA sections operating on data */
 87		info = swab_elfword(shdr[i].sh_info);
 88		flags = swab_elfxword(shdr[info].sh_flags);
 89		if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) != SHF_ALLOC)
 90			continue;
 91
 92		/*
 93		 * We generally don't permit ABS64 relocations in the code that
 94		 * runs before relocation processing occurs. If statically
 95		 * initialized absolute symbol references are unavoidable, they
 96		 * may be emitted into a *.rodata.prel64 section and they will
 97		 * be converted to place-relative 64-bit references. This
 98		 * requires special handling in the referring code.
 99		 */
100		if (strstr(strtab + swab_elfword(shdr[info].sh_name),
101			   ".rodata.prel64")) {
102			prel64 = true;
103		}
104
105		rela = (void *)ehdr + swab_elfxword(shdr[i].sh_offset);
106		numrela = swab_elfxword(shdr[i].sh_size) / sizeof(*rela);
107
108		for (int j = 0; j < numrela; j++) {
109			uint64_t info = swab_elfxword(rela[j].r_info);
110
111			if (ELF64_R_TYPE(info) != R_AARCH64_ABS64)
112				continue;
113
114			if (prel64) {
115				/* convert ABS64 into PREL64 */
116				info ^= R_AARCH64_ABS64 ^ R_AARCH64_PREL64;
117				rela[j].r_info = swab_elfxword(info);
118			} else {
119				fprintf(stderr,
120					"Unexpected absolute relocations detected in %s\n",
121					argv[2]);
122				close(fd);
123				unlink(argv[1]);
124				exit(EXIT_FAILURE);
125			}
126		}
127	}
128	close(fd);
129	return 0;
130}
~/ Read-only file preview.