The Elf loading logic will initially use the `data` section field to stash a
pointer to the temporary loaded data (from the buffer allocated in
livepatch_upload(), which is later relocated and the new pointer stashed in
`load_addr`.
Remove this dual field usage and use an `addr` uniformly. Initially data will
point to the temporary buffer, until relocation happens, at which point the
pointer will be updated to the relocated address.
This avoids leaving a dangling pointer in the `data` field once the temporary
buffer is freed by livepatch_upload().
Note the `addr` field cannot retain the const attribute from the previous
`data`field, as there's logic that performs manipulations against the loaded
sections, like applying relocations or sorting the exception table.
No functional change intended.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Michal Orzel <michal.orzel@amd.com>
master commit:
8c81423038f17f6cbc853dd35d69d50a4458f764
master date: 2024-09-26 14:18:03 +0100
if ( use_rela )
{
- const Elf_RelA *r_a = rela->data + i * rela->sec->sh_entsize;
+ const Elf_RelA *r_a = rela->addr + i * rela->sec->sh_entsize;
symndx = ELF32_R_SYM(r_a->r_info);
type = ELF32_R_TYPE(r_a->r_info);
- dest = base->load_addr + r_a->r_offset; /* P */
+ dest = base->addr + r_a->r_offset; /* P */
addend = r_a->r_addend;
}
else
{
- const Elf_Rel *r = rela->data + i * rela->sec->sh_entsize;
+ const Elf_Rel *r = rela->addr + i * rela->sec->sh_entsize;
symndx = ELF32_R_SYM(r->r_info);
type = ELF32_R_TYPE(r->r_info);
- dest = base->load_addr + r->r_offset; /* P */
+ dest = base->addr + r->r_offset; /* P */
addend = get_addend(type, dest);
}
for ( i = 0; i < (rela->sec->sh_size / rela->sec->sh_entsize); i++ )
{
- const Elf_RelA *r = rela->data + i * rela->sec->sh_entsize;
+ const Elf_RelA *r = rela->addr + i * rela->sec->sh_entsize;
unsigned int symndx = ELF64_R_SYM(r->r_info);
- void *dest = base->load_addr + r->r_offset; /* P */
+ void *dest = base->addr + r->r_offset; /* P */
bool overflow_check = true;
int ovf = 0;
uint64_t val;
for ( i = 0; i < (rela->sec->sh_size / rela->sec->sh_entsize); i++ )
{
- const Elf_RelA *r = rela->data + i * rela->sec->sh_entsize;
+ const Elf_RelA *r = rela->addr + i * rela->sec->sh_entsize;
unsigned int symndx = ELF64_R_SYM(r->r_info);
- uint8_t *dest = base->load_addr + r->r_offset;
+ uint8_t *dest = base->addr + r->r_offset;
uint64_t val;
if ( symndx == STN_UNDEF )
ASSERT(offset[i] != UINT_MAX);
- elf->sec[i].load_addr = buf + offset[i];
+ buf += offset[i];
/* Don't copy NOBITS - such as BSS. */
if ( elf->sec[i].sec->sh_type != SHT_NOBITS )
{
- memcpy(elf->sec[i].load_addr, elf->sec[i].data,
+ memcpy(buf, elf->sec[i].addr,
elf->sec[i].sec->sh_size);
dprintk(XENLOG_DEBUG, LIVEPATCH "%s: Loaded %s at %p\n",
- elf->name, elf->sec[i].name, elf->sec[i].load_addr);
+ elf->name, elf->sec[i].name, buf);
}
else
- memset(elf->sec[i].load_addr, 0, elf->sec[i].sec->sh_size);
+ memset(buf, 0, elf->sec[i].sec->sh_size);
+
+ /* Update sec[] to refer to its final location. */
+ elf->sec[i].addr = buf;
}
}
break; \
if ( !section_ok(elf, __sec, sizeof(*hook)) || __sec->sec->sh_size != sizeof(*hook) ) \
return -EINVAL; \
- hook = __sec->load_addr; \
+ hook = __sec->addr; \
} while (0)
/*
break; \
if ( !section_ok(elf, __sec, sizeof(*hook)) ) \
return -EINVAL; \
- hook = __sec->load_addr; \
+ hook = __sec->addr; \
nhooks = __sec->sec->sh_size / sizeof(*hook); \
} while (0)
if ( !section_ok(elf, sec, sizeof(*payload->funcs)) )
return -EINVAL;
- payload->funcs = funcs = sec->load_addr;
+ payload->funcs = funcs = sec->addr;
payload->nfuncs = sec->sec->sh_size / sizeof(*payload->funcs);
payload->fstate = xzalloc_array(typeof(*payload->fstate),
{
const struct payload *data;
- n = sec->load_addr;
+ n = sec->addr;
if ( sec->sec->sh_size <= sizeof(*n) )
return -EINVAL;
sec = livepatch_elf_sec_by_name(elf, ELF_LIVEPATCH_DEPENDS);
if ( sec )
{
- n = sec->load_addr;
+ n = sec->addr;
if ( sec->sec->sh_size <= sizeof(*n) )
return -EINVAL;
sec = livepatch_elf_sec_by_name(elf, ELF_LIVEPATCH_XEN_DEPENDS);
if ( sec )
{
- n = sec->load_addr;
+ n = sec->addr;
if ( sec->sec->sh_size <= sizeof(*n) )
return -EINVAL;
if ( !section_ok(elf, sec, sizeof(*region->frame[i].bugs)) )
return -EINVAL;
- region->frame[i].bugs = sec->load_addr;
+ region->frame[i].bugs = sec->addr;
region->frame[i].n_bugs = sec->sec->sh_size /
sizeof(*region->frame[i].bugs);
}
return -EINVAL;
}
- start = sec->load_addr;
- end = sec->load_addr + sec->sec->sh_size;
+ start = sec->addr;
+ end = sec->addr + sec->sec->sh_size;
for ( a = start; a < end; a++ )
{
* repl must be fully within .altinstr_replacement, even if the
* replacement and the section happen to both have zero length.
*/
- if ( repl < repl_sec->load_addr ||
+ if ( repl < repl_sec->addr ||
a->repl_len > repl_sec->sec->sh_size ||
- repl + a->repl_len > repl_sec->load_addr + repl_sec->sec->sh_size )
+ repl + a->repl_len > repl_sec->addr + repl_sec->sec->sh_size )
{
printk(XENLOG_ERR LIVEPATCH
"%s Alternative repl %p+%#x outside .altinstr_replacement %p+%#"PRIxElfWord"\n",
elf->name, repl, a->repl_len,
- repl_sec->load_addr, repl_sec->sec->sh_size);
+ repl_sec->addr, repl_sec->sec->sh_size);
return -EINVAL;
}
}
if ( !section_ok(elf, sec, sizeof(*region->ex)) )
return -EINVAL;
- s = sec->load_addr;
- e = sec->load_addr + sec->sec->sh_size;
+ s = sec->addr;
+ e = sec->addr + sec->sec->sh_size;
sort_exception_table(s ,e);
if ( !section_ok(elf, sec, sizeof(*payload->metadata.data)) )
return -EINVAL;
- payload->metadata.data = sec->load_addr;
+ payload->metadata.data = sec->addr;
payload->metadata.len = sec->sec->sh_size;
/* The metadata is required to consists of null terminated strings. */
if ( !s->sh_size )
return -EINVAL;
- contents = sec->data;
+ contents = sec->addr;
if ( contents[0] || contents[s->sh_size - 1] )
return -EINVAL;
return 0;
}
-static int elf_resolve_sections(struct livepatch_elf *elf, const void *data)
+static int elf_resolve_sections(struct livepatch_elf *elf, void *data)
{
struct livepatch_elf_sec *sec;
unsigned int i;
sec[i].sec->sh_size > LIVEPATCH_MAX_SIZE )
return -EINVAL;
- sec[i].data = data + delta;
+ sec[i].addr = data + delta;
/* Name is populated in elf_resolve_section_names. */
sec[i].name = NULL;
strtab_sec = elf->strtab;
/* Pointers arithmetic to get file offset. */
- offset = strtab_sec->data - data;
+ offset = strtab_sec->addr - data;
/* Checked already in elf_resolve_sections, but just in case. */
ASSERT(offset == strtab_sec->sec->sh_offset);
ASSERT(offset < elf->len && (offset + strtab_sec->sec->sh_size <= elf->len));
- /* symtab_sec->data was computed in elf_resolve_sections. */
- ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->data);
+ /* symtab_sec->addr was computed in elf_resolve_sections. */
+ ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->addr);
/* No need to check values as elf_resolve_sections did it. */
nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize;
for ( i = 1; i < nsym; i++ )
{
- const Elf_Sym *s = symtab_sec->data + symtab_sec->sec->sh_entsize * i;
+ const Elf_Sym *s = symtab_sec->addr + symtab_sec->sec->sh_entsize * i;
delta = s->st_name;
/* Boundary check within the .strtab. */
}
sym[i].sym = s;
- sym[i].name = strtab_sec->data + delta;
+ sym[i].name = strtab_sec->addr + delta;
if ( arch_livepatch_symbol_deny(elf, &sym[i]) )
{
printk(XENLOG_ERR LIVEPATCH "%s: Symbol '%s' should not be in payload\n",
break;
}
- st_value += (unsigned long)elf->sec[idx].load_addr;
+ st_value += (unsigned long)elf->sec[idx].addr;
if ( elf->sym[i].name )
dprintk(XENLOG_DEBUG, LIVEPATCH "%s: Symbol resolved: %s => %#"PRIxElfAddr" (%s)\n",
elf->name, elf->sym[i].name,
return 0;
}
-int livepatch_elf_load(struct livepatch_elf *elf, const void *data)
+int livepatch_elf_load(struct livepatch_elf *elf, void *data)
{
int rc;
const Elf_Shdr *sec; /* Hooked up in elf_resolve_sections.*/
const char *name; /* Human readable name hooked in
elf_resolve_section_names. */
- const void *data; /* Pointer to the section (done by
- elf_resolve_sections). */
- void *load_addr; /* A pointer to the allocated destination.
- Done by load_payload_data. */
+ void *addr; /*
+ * Pointer to the section. This is
+ * first a temporary buffer, then
+ * later the relocated load address.
+ */
};
struct livepatch_elf_sym {
const struct livepatch_elf_sec *
livepatch_elf_sec_by_name(const struct livepatch_elf *elf,
const char *name);
-int livepatch_elf_load(struct livepatch_elf *elf, const void *data);
+int livepatch_elf_load(struct livepatch_elf *elf, void *data);
void livepatch_elf_free(struct livepatch_elf *elf);
int livepatch_elf_resolve_symbols(struct livepatch_elf *elf);