mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/livepatch: Support new altcall scheme
The new altcall scheme uses an .alt_call_sites section. Wire this up in very much the same way as the .altinstructions section, although there is less sanity checking necessary. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
This commit is contained in:
1 parent
ac02ee9c82
commit
d2fd5f0fcd
3 files changed
+70
-2
No files matched your search
@@ -479,6 +479,12 @@ int apply_alternatives(struct alt_instr *start, struct alt_instr *end)
|
||||
{
|
||||
return _apply_alternatives(start, end, true);
|
||||
}
|
||||
|
||||
int livepatch_apply_alt_calls(const struct alt_call *start,
|
||||
const struct alt_call *end)
|
||||
{
|
||||
return apply_alt_calls(start, end);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ALT_INSNS (1U << 0)
|
||||
|
||||
@@ -905,6 +905,64 @@ static int prepare_payload(struct payload *payload,
|
||||
#endif
|
||||
}
|
||||
|
||||
sec = livepatch_elf_sec_by_name(elf, ".alt_call_sites");
|
||||
if ( sec )
|
||||
{
|
||||
#ifdef CONFIG_ALTERNATIVE_CALL
|
||||
const struct alt_call *a, *start, *end;
|
||||
|
||||
if ( !section_ok(elf, sec, sizeof(*a)) )
|
||||
return -EINVAL;
|
||||
|
||||
/* Tolerate an empty .alt_call_sites section... */
|
||||
if ( sec->sec->sh_size == 0 )
|
||||
goto alt_call_done;
|
||||
|
||||
/* ... but otherwise, there needs to be something to alter... */
|
||||
if ( payload->text_size == 0 )
|
||||
{
|
||||
printk(XENLOG_ERR LIVEPATCH "%s Alternative calls provided, but no .text\n",
|
||||
elf->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
start = sec->addr;
|
||||
end = sec->addr + sec->sec->sh_size;
|
||||
|
||||
for ( a = start; a < end; a++ )
|
||||
{
|
||||
const void *orig = ALT_CALL_PTR(a);
|
||||
size_t len = ALT_CALL_LEN(a);
|
||||
|
||||
/* orig must be fully within .text. */
|
||||
if ( orig < payload->text_addr ||
|
||||
len > payload->text_size ||
|
||||
orig + len > payload->text_addr + payload->text_size )
|
||||
{
|
||||
printk(XENLOG_ERR LIVEPATCH
|
||||
"%s: Alternative call %p+%#zx outside payload text %p+%#zx\n",
|
||||
elf->name, orig, len,
|
||||
payload->text_addr, payload->text_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
rc = livepatch_apply_alt_calls(start, end);
|
||||
if ( rc )
|
||||
{
|
||||
printk(XENLOG_ERR LIVEPATCH "%s: Applying alternative calls failed: %d\n",
|
||||
elf->name, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
alt_call_done:;
|
||||
#else /* CONFIG_ALTERNATIVE_CALL */
|
||||
printk(XENLOG_ERR LIVEPATCH "%s: Alternative calls not supported\n",
|
||||
elf->name);
|
||||
return -EOPNOTSUPP;
|
||||
#endif /* !CONFIG_ALTERNATIVE_CALL */
|
||||
}
|
||||
|
||||
sec = livepatch_elf_sec_by_name(elf, ".ex_table");
|
||||
if ( sec )
|
||||
{
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* generation requirements are to emit a function pointer call at build
|
||||
* time, and stash enough metadata to simplify the call at boot once the
|
||||
* implementation has been resolved.
|
||||
* - Implement boot_apply_alt_calls() to convert the function pointer calls
|
||||
* into direct calls on boot.
|
||||
* - Implement {boot,livepatch}_apply_alt_calls() to convert the function
|
||||
* pointer calls into direct calls on boot/livepatch.
|
||||
* - Select ALTERNATIVE_CALL in Kconfig.
|
||||
*
|
||||
* To use:
|
||||
@@ -65,6 +65,10 @@
|
||||
*/
|
||||
void boot_apply_alt_calls(void);
|
||||
|
||||
/* As per boot_apply_alt_calls() but for a livepatch. */
|
||||
int livepatch_apply_alt_calls(const struct alt_call *start,
|
||||
const struct alt_call *end);
|
||||
|
||||
#else /* CONFIG_ALTERNATIVE_CALL */
|
||||
|
||||
#define alternative_call(func, args...) (func)(args)
|
||||
|
||||