linux-user/elfload: Parse NT_GNU_PROPERTY_TYPE_0 notes
This is generic support, with the code disabled for all targets. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201021173749.111103-11-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
808f656318
commit
83f990eb5a
@ -1522,6 +1522,15 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
|
||||
const uint32_t *data,
|
||||
struct image_info *info,
|
||||
Error **errp)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
#define ARCH_USE_GNU_PROPERTY 0
|
||||
|
||||
struct exec
|
||||
{
|
||||
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
||||
@ -2373,6 +2382,150 @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
|
||||
"@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
|
||||
}
|
||||
|
||||
enum {
|
||||
/* The string "GNU\0" as a magic number. */
|
||||
GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
|
||||
NOTE_DATA_SZ = 1 * KiB,
|
||||
NOTE_NAME_SZ = 4,
|
||||
ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
|
||||
};
|
||||
|
||||
/*
|
||||
* Process a single gnu_property entry.
|
||||
* Return false for error.
|
||||
*/
|
||||
static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
|
||||
struct image_info *info, bool have_prev_type,
|
||||
uint32_t *prev_type, Error **errp)
|
||||
{
|
||||
uint32_t pr_type, pr_datasz, step;
|
||||
|
||||
if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
|
||||
goto error_data;
|
||||
}
|
||||
datasz -= *off;
|
||||
data += *off / sizeof(uint32_t);
|
||||
|
||||
if (datasz < 2 * sizeof(uint32_t)) {
|
||||
goto error_data;
|
||||
}
|
||||
pr_type = data[0];
|
||||
pr_datasz = data[1];
|
||||
data += 2;
|
||||
datasz -= 2 * sizeof(uint32_t);
|
||||
step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
|
||||
if (step > datasz) {
|
||||
goto error_data;
|
||||
}
|
||||
|
||||
/* Properties are supposed to be unique and sorted on pr_type. */
|
||||
if (have_prev_type && pr_type <= *prev_type) {
|
||||
if (pr_type == *prev_type) {
|
||||
error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
|
||||
} else {
|
||||
error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*prev_type = pr_type;
|
||||
|
||||
if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*off += 2 * sizeof(uint32_t) + step;
|
||||
return true;
|
||||
|
||||
error_data:
|
||||
error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Process NT_GNU_PROPERTY_TYPE_0. */
|
||||
static bool parse_elf_properties(int image_fd,
|
||||
struct image_info *info,
|
||||
const struct elf_phdr *phdr,
|
||||
char bprm_buf[BPRM_BUF_SIZE],
|
||||
Error **errp)
|
||||
{
|
||||
union {
|
||||
struct elf_note nhdr;
|
||||
uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
|
||||
} note;
|
||||
|
||||
int n, off, datasz;
|
||||
bool have_prev_type;
|
||||
uint32_t prev_type;
|
||||
|
||||
/* Unless the arch requires properties, ignore them. */
|
||||
if (!ARCH_USE_GNU_PROPERTY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the properties are crazy large, that's too bad. */
|
||||
n = phdr->p_filesz;
|
||||
if (n > sizeof(note)) {
|
||||
error_setg(errp, "PT_GNU_PROPERTY too large");
|
||||
return false;
|
||||
}
|
||||
if (n < sizeof(note.nhdr)) {
|
||||
error_setg(errp, "PT_GNU_PROPERTY too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
|
||||
memcpy(¬e, bprm_buf + phdr->p_offset, n);
|
||||
} else {
|
||||
ssize_t len = pread(image_fd, ¬e, n, phdr->p_offset);
|
||||
if (len != n) {
|
||||
error_setg_errno(errp, errno, "Error reading file header");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The contents of a valid PT_GNU_PROPERTY is a sequence
|
||||
* of uint32_t -- swap them all now.
|
||||
*/
|
||||
#ifdef BSWAP_NEEDED
|
||||
for (int i = 0; i < n / 4; i++) {
|
||||
bswap32s(note.data + i);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note that nhdr is 3 words, and that the "name" described by namesz
|
||||
* immediately follows nhdr and is thus at the 4th word. Further, all
|
||||
* of the inputs to the kernel's round_up are multiples of 4.
|
||||
*/
|
||||
if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
|
||||
note.nhdr.n_namesz != NOTE_NAME_SZ ||
|
||||
note.data[3] != GNU0_MAGIC) {
|
||||
error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
|
||||
return false;
|
||||
}
|
||||
off = sizeof(note.nhdr) + NOTE_NAME_SZ;
|
||||
|
||||
datasz = note.nhdr.n_descsz + off;
|
||||
if (datasz > n) {
|
||||
error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
|
||||
return false;
|
||||
}
|
||||
|
||||
have_prev_type = false;
|
||||
prev_type = 0;
|
||||
while (1) {
|
||||
if (off == datasz) {
|
||||
return true; /* end, exit ok */
|
||||
}
|
||||
if (!parse_elf_property(note.data, &off, datasz, info,
|
||||
have_prev_type, &prev_type, errp)) {
|
||||
return false;
|
||||
}
|
||||
have_prev_type = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load an ELF image into the address space.
|
||||
|
||||
IMAGE_NAME is the filename of the image, to use in error messages.
|
||||
@ -2467,6 +2620,10 @@ static void load_elf_image(const char *image_name, int image_fd,
|
||||
goto exit_errmsg;
|
||||
}
|
||||
*pinterp_name = g_steal_pointer(&interp_name);
|
||||
} else if (eppnt->p_type == PT_GNU_PROPERTY) {
|
||||
if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
|
||||
goto exit_errmsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,10 @@ struct image_info {
|
||||
abi_ulong interpreter_loadmap_addr;
|
||||
abi_ulong interpreter_pt_dynamic_addr;
|
||||
struct image_info *other_info;
|
||||
|
||||
/* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */
|
||||
uint32_t note_flags;
|
||||
|
||||
#ifdef TARGET_MIPS
|
||||
int fp_abi;
|
||||
int interp_fp_abi;
|
||||
|
Loading…
Reference in New Issue
Block a user