mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-26 03:43:58 -06:00

There are a number of resource leaks in gen-vdso. In theory they are harmless because this is a short lived process, but when building QEMU with --extra-cflags="-fsanitize=address" problems ensure. The gen-vdso program is run as part of the build, and that aborts due to the sanitizer identifying memory leaks, leaving QEMU unbuildable. FAILED: libqemu-x86_64-linux-user.a.p/vdso.c.inc /var/home/berrange/src/virt/qemu/build/linux-user/gen-vdso -o libqemu-x86_64-linux-user.a.p/vdso.c.inc ../linux-user/x86_64/vdso.so ================================================================= ==1696332==ERROR: LeakSanitizer: detected memory leaks Direct leak of 2968 byte(s) in 1 object(s) allocated from: #0 0x56495873f1f3 (/var/home/berrange/src/virt/qemu/build/linux-user/gen-vdso+0xa11f3) (BuildId: b69e241ad44719b6f3934f3c71dfc6727e8bdb12) #1 0x564958780b90 (/var/home/berrange/src/virt/qemu/build/linux-user/gen-vdso+0xe2b90) (BuildId: b69e241ad44719b6f3934f3c71dfc6727e8bdb12) This complaint is about the 'buf' variable, however, the FILE objects are also leaked in some error scenarios, so this fix refactors the cleanup paths to fix all leaks. For completeness it also reports an error if fclose() fails on 'inf'. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Tested-by: Arusekk <floss@arusekk.pl> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20250513150346.1328217-1-berrange@redhat.com>
228 lines
5.7 KiB
C
228 lines
5.7 KiB
C
/*
|
|
* Post-process a vdso elf image for inclusion into qemu.
|
|
*
|
|
* Copyright 2023 Linaro, Ltd.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <endian.h>
|
|
#include <unistd.h>
|
|
#include "elf.h"
|
|
|
|
|
|
#define bswap_(p) _Generic(*(p), \
|
|
uint16_t: __builtin_bswap16, \
|
|
uint32_t: __builtin_bswap32, \
|
|
uint64_t: __builtin_bswap64, \
|
|
int16_t: __builtin_bswap16, \
|
|
int32_t: __builtin_bswap32, \
|
|
int64_t: __builtin_bswap64)
|
|
#define bswaps(p) (*(p) = bswap_(p)(*(p)))
|
|
|
|
static void output_reloc(FILE *outf, void *buf, void *loc)
|
|
{
|
|
fprintf(outf, " 0x%08tx,\n", loc - buf);
|
|
}
|
|
|
|
static const char *sigreturn_sym;
|
|
static const char *rt_sigreturn_sym;
|
|
|
|
static unsigned sigreturn_addr;
|
|
static unsigned rt_sigreturn_addr;
|
|
|
|
#define N 32
|
|
#define elfN(x) elf32_##x
|
|
#define ElfN(x) Elf32_##x
|
|
#include "gen-vdso-elfn.c.inc"
|
|
#undef N
|
|
#undef elfN
|
|
#undef ElfN
|
|
|
|
#define N 64
|
|
#define elfN(x) elf64_##x
|
|
#define ElfN(x) Elf64_##x
|
|
#include "gen-vdso-elfn.c.inc"
|
|
#undef N
|
|
#undef elfN
|
|
#undef ElfN
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
FILE *inf = NULL, *outf = NULL;
|
|
long total_len;
|
|
const char *prefix = "vdso";
|
|
const char *inf_name;
|
|
const char *outf_name = NULL;
|
|
unsigned char *buf = NULL;
|
|
bool need_bswap;
|
|
int ret = EXIT_FAILURE;
|
|
|
|
while (1) {
|
|
int opt = getopt(argc, argv, "o:p:r:s:");
|
|
if (opt < 0) {
|
|
break;
|
|
}
|
|
switch (opt) {
|
|
case 'o':
|
|
outf_name = optarg;
|
|
break;
|
|
case 'p':
|
|
prefix = optarg;
|
|
break;
|
|
case 'r':
|
|
rt_sigreturn_sym = optarg;
|
|
break;
|
|
case 's':
|
|
sigreturn_sym = optarg;
|
|
break;
|
|
default:
|
|
usage:
|
|
fprintf(stderr, "usage: [-p prefix] [-r rt-sigreturn-name] "
|
|
"[-s sigreturn-name] -o output-file input-file\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (optind >= argc || outf_name == NULL) {
|
|
goto usage;
|
|
}
|
|
inf_name = argv[optind];
|
|
|
|
/*
|
|
* Open the input and output files.
|
|
*/
|
|
inf = fopen(inf_name, "rb");
|
|
if (inf == NULL) {
|
|
goto perror_inf;
|
|
}
|
|
outf = fopen(outf_name, "w");
|
|
if (outf == NULL) {
|
|
goto perror_outf;
|
|
}
|
|
|
|
/*
|
|
* Read the input file into a buffer.
|
|
* We expect the vdso to be small, on the order of one page,
|
|
* therefore we do not expect a partial read.
|
|
*/
|
|
fseek(inf, 0, SEEK_END);
|
|
total_len = ftell(inf);
|
|
fseek(inf, 0, SEEK_SET);
|
|
|
|
buf = malloc(total_len);
|
|
if (buf == NULL) {
|
|
goto perror_inf;
|
|
}
|
|
|
|
errno = 0;
|
|
if (fread(buf, 1, total_len, inf) != total_len) {
|
|
if (errno) {
|
|
goto perror_inf;
|
|
}
|
|
fprintf(stderr, "%s: incomplete read\n", inf_name);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Identify which elf flavor we're processing.
|
|
* The first 16 bytes of the file are e_ident.
|
|
*/
|
|
|
|
if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 ||
|
|
buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) {
|
|
fprintf(stderr, "%s: not an elf file\n", inf_name);
|
|
return EXIT_FAILURE;
|
|
}
|
|
switch (buf[EI_DATA]) {
|
|
case ELFDATA2LSB:
|
|
need_bswap = BYTE_ORDER != LITTLE_ENDIAN;
|
|
break;
|
|
case ELFDATA2MSB:
|
|
need_bswap = BYTE_ORDER != BIG_ENDIAN;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "%s: invalid elf EI_DATA (%u)\n",
|
|
inf_name, buf[EI_DATA]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* We need to relocate the VDSO image. The one built into the kernel
|
|
* is built for a fixed address. The one we built for QEMU is not,
|
|
* since that requires close control of the guest address space.
|
|
*
|
|
* Output relocation addresses as we go.
|
|
*/
|
|
|
|
fprintf(outf,
|
|
"/* Automatically generated by linux-user/gen-vdso.c. */\n"
|
|
"\n"
|
|
"static const unsigned %s_relocs[] = {\n", prefix);
|
|
|
|
switch (buf[EI_CLASS]) {
|
|
case ELFCLASS32:
|
|
elf32_process(outf, buf, total_len, need_bswap);
|
|
break;
|
|
case ELFCLASS64:
|
|
elf64_process(outf, buf, total_len, need_bswap);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "%s: invalid elf EI_CLASS (%u)\n",
|
|
inf_name, buf[EI_CLASS]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
fprintf(outf, "};\n\n"); /* end vdso_relocs. */
|
|
|
|
/*
|
|
* Write out the vdso image now, after we made local changes.
|
|
*/
|
|
fprintf(outf,
|
|
"static const uint8_t %s_image[] = {",
|
|
prefix);
|
|
for (long i = 0; i < total_len; ++i) {
|
|
if (i % 12 == 0) {
|
|
fputs("\n ", outf);
|
|
}
|
|
fprintf(outf, " 0x%02x,", buf[i]);
|
|
}
|
|
fprintf(outf, "\n};\n\n");
|
|
|
|
fprintf(outf, "static const VdsoImageInfo %s_image_info = {\n", prefix);
|
|
fprintf(outf, " .image = %s_image,\n", prefix);
|
|
fprintf(outf, " .relocs = %s_relocs,\n", prefix);
|
|
fprintf(outf, " .image_size = sizeof(%s_image),\n", prefix);
|
|
fprintf(outf, " .reloc_count = ARRAY_SIZE(%s_relocs),\n", prefix);
|
|
fprintf(outf, " .sigreturn_ofs = 0x%x,\n", sigreturn_addr);
|
|
fprintf(outf, " .rt_sigreturn_ofs = 0x%x,\n", rt_sigreturn_addr);
|
|
fprintf(outf, "};\n");
|
|
|
|
ret = EXIT_SUCCESS;
|
|
|
|
cleanup:
|
|
free(buf);
|
|
|
|
if (outf && fclose(outf) != 0) {
|
|
ret = EXIT_FAILURE;
|
|
}
|
|
if (inf && fclose(inf) != 0) {
|
|
ret = EXIT_FAILURE;
|
|
}
|
|
return ret;
|
|
|
|
perror_inf:
|
|
perror(inf_name);
|
|
goto cleanup;
|
|
|
|
perror_outf:
|
|
perror(outf_name);
|
|
goto cleanup;
|
|
}
|