[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC 5/5] xen/x86: livepatch: enable attaching callbacks


  • To: andrew.cooper3@xxxxxxxxxx
  • From: Ryo Takakura <takakura@xxxxxxxxxxxxx>
  • Date: Tue, 3 Nov 2026 15:04:42 +0900
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=valinux.co.jp; dmarc=pass action=none header.from=valinux.co.jp; dkim=pass header.d=valinux.co.jp; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=kUkl3RtsSxBVJ/HZu/hZ9Lm1nvwsMgutWtd4I+5L8b4=; b=YVpiDndgVDFfIYtbJp14skOQ2a3f+RaCOYl6lE4Ui3rfelgn7yzEeMIylBdugedlaqHtodgnT4VABAFsP3GZQgr+PK2WKXdxpKcaqNZnMh3OXQmH12Yg/d/N8RsZM1kQeqzEqml20W4N5UUxJ9PW6T6cqXSSUVwWt0N2+Yl922i7AtNlIYtjcmFhr0YQGTpqxjiu2JAj6alCYBu/j3dixUL1ZiRRasrZP+P/ww/bL+swv/LCSu9ocvEdGvkY7ud6JFrft2zULvY/KYplFFm8DnqTFxLgahML4WieF2UzuzfzZtTTNBM+xD7RXBKaTkunJJzNsrYf6XnSVcWvC+AriQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=L0cQ1v0OIYtS/6bYaruPagq4EOAFVz+GonF8UMrM9ISus+3ePJY+Gp7hW5KnFwcFVoic8Z1nkBXUCuhJN1UdV0lmg7w2yBybutJa25+MTpoQVxZwfLcNv4i/7z0Uz5Ck5eb+EEHeQk2qADxsKNH5igUGUPm8tJj0Tl5EYneNNkofdMz6TJYLpRwox5OK+L97RqAfRE0jt433WIA4O7LiTeILOrQXG27TfDTwQcUZUC5mRq1QJX0sv97y5Dh2M0rZpdIg7ruIYmAYaKxyyjBdg7hfrl9z+8ckb3gl3l9FFvjxQUQnb3Ti9hmQoAfCLmSh7tW2zKsiEiN6IqoIiRYE/Q==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=valinux.co.jp header.i="@valinux.co.jp" header.h="From:Date:Subject:Message-Id:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=valinux.co.jp;
  • Cc: Volodymyr_Babchuk@xxxxxxxx, anthony.perard@xxxxxxxxxx, bertrand.marquis@xxxxxxx, jbeulich@xxxxxxxx, julien@xxxxxxx, michal.orzel@xxxxxxx, roger@xxxxxxxxxxxxxx, ross.lagerwall@xxxxxxxxxx, sstabellini@xxxxxxxxxx, takakura@xxxxxxxxxxxxx, teddy.astie@xxxxxxxxxx, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • Delivery-date: Tue, 03 Nov 2026 06:04:57 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On Mon, 26 Oct 2026 11:42:37 +0000, Andrew Cooper wrote:
>On 23/10/2026 5:58 am, Ryo Takakura wrote:
>> diff --git a/xen/arch/x86/livepatch-asm.S b/xen/arch/x86/livepatch-asm.S
>> new file mode 100644
>> index 0000000000..005765b476
>> --- /dev/null
>> +++ b/xen/arch/x86/livepatch-asm.S
>> @@ -0,0 +1,60 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +#include <asm/asm_defns.h>
>> +
>> +        .text
>> +
>
>You need ".file __FILE__" too.  IIRC this is a workaround for a binutils
>bug.

Understood. I'll add ".file __FILE__".

>> +/*
>> + * xen/arch/x86/livepatch-asm.S
>> + *
>> + * Trampoline for livepatch tracer.
>> + *
>> + * If livepatch tracer is enabled, function entries are placed
>> + * with five NOPs. arch_livepatch_apply_trace() will be livepatching
>> + * those NOPs to:
>> + *
>> + *     CALL      xen_livepatch_trace_caller
>> + *
>> + * 0(%rsp): traced function + 5
>> + * 8(%rsp): return address to the traced function's caller
>
>Somewhere in this comment needs to say that all GPRs need preserving.

Ok. I'll add a comment.

>Except...  Looking at arch_generic_hweightl(), my notes about
>__attribute__((no_caller_saved_registers)) say GCC >= 7 and 8 is already
>a minimum for the (broken) patchable function entry, let alone the fixed
>one.

I see.

>So I think you don't need an ASM trampoline at all.  I think you can
>merge xen_livepatch_trace_caller() and xen_livepatch_trace_dispatcher()
>and just tell the compiler to spill all ABI registers.

Yes, it would be nice to merge the two...
But xen_livepatch_trace_dispatcher() is also shared with arm64,
and GCC does not appear to support no_caller_saved_registers on arm64.
That makes arm64 still need its ASM trampoline to preserve
the registers and common C dispatcher.
Do you think rewriting livepatch_trace_caller() in C while keeping
livepatch_trace_dispatcher() as common dispatcher would be reasonable?

I'm also thinking of adding the attribute force_align_arg_pointer
to address the Bernhard's feedback on stack alignment:
https://lore.kernel.org/xen-devel/179285259082.1706038.15527286146285697701.b4-review@b4/

>Also, the xen_ prefixes are redundant.  Just name the function
>livepatch_trace_caller().

Ok. I'll remove them.

>> + */
>> +FUNC(xen_livepatch_trace_caller)
>> +        pushq   %rbp
>> +        movq    %rsp, %rbp
>> +        pushfq
>> +
>> +        /* Preserve general-purpose registers. */
>> +        pushq   %rax
>> +        pushq   %rcx
>> +        pushq   %rdx
>> +        pushq   %rsi
>> +        pushq   %rdi
>> +        pushq   %r8
>> +        pushq   %r9
>> +        pushq   %r10
>> +        pushq   %r11
>> +
>> +        /*
>> +         * xen_livepatch_trace_dispatcher(ip, parent_ip)
>> +         *
>> +         * ip: Address of the traced function.
>> +         * parent_ip: Address where the traced function was called.
>> +         */
>> +        movq    8(%rbp), %rdi
>> +        subq    $5, %rdi
>> +        movq    16(%rbp), %rsi
>> +        call    xen_livepatch_trace_dispatcher
>> +
>> +        /* Restore the saved state. */
>> +        popq    %r11
>> +        popq    %r10
>> +        popq    %r9
>> +        popq    %r8
>> +        popq    %rdi
>> +        popq    %rsi
>> +        popq    %rdx
>> +        popq    %rcx
>> +        popq    %rax
>> +        popfq
>> +        popq    %rbp
>> +        ret
>> +END(xen_livepatch_trace_caller)
>
>Just in case there's a problem doing this all in C...
>
>No need for pushf or popf at all.  Flags are undefined at function
>boundaries.
>
>Please drop the q suffixes; they're all unnecessary here.
>
>The ret needs to be RET for speculative mitigations.  (It's emitted as
>JMP which will be turned back into a RET on safe system.)

Understood.
I'll get them fixed in case if we need a trampoline.

>> diff --git a/xen/arch/x86/livepatch.c b/xen/arch/x86/livepatch.c
>> index 5158e91f7e..1dfcc3e750 100644
>> --- a/xen/arch/x86/livepatch.c
>> +++ b/xen/arch/x86/livepatch.c
>> @@ -19,6 +19,10 @@
>>  #include <asm/nmi.h>
>>  #include <asm/setup.h>
>>  
>> +#ifdef CONFIG_X86_PATCHABLE_FUNCTION_ENTRY
>> +extern void xen_livepatch_trace_caller(void);
>> +#endif
>
>You don't need ifdefary around declarations.

Ok. I'll remove them.

>> +
>>  static bool has_active_waitqueue(const struct vm_event_domain *ved)
>>  {
>>      /* ved may be xzalloc()'d without INIT_LIST_HEAD() yet. */
>> @@ -365,6 +369,35 @@ int arch_livepatch_secure(const void *va, unsigned int 
>> pages, enum va_type type)
>>      return modify_xen_mappings(start, start + pages * PAGE_SIZE, flag);
>>  }
>>  
>> +#ifdef CONFIG_X86_PATCHABLE_FUNCTION_ENTRY
>> +unsigned long arch_livepatch_trace_entry(unsigned long addr)
>> +{
>> +    if ( (is_endbr64((const void *)addr) || is_endbr64_poison((const void 
>> *)addr)) )
>> +        addr += ENDBR64_LEN;
>> +
>> +    return addr;
>> +}
>> +
>> +void noinline arch_livepatch_apply_trace(const struct livepatch_func *trace)
>> +{
>> +    void *site = (void *)arch_livepatch_trace_entry((unsigned 
>> long)trace->old_addr);
>> +    const void *new_addr = xen_livepatch_trace_caller;
>> +    uint8_t insn[ARCH_PATCH_INSN_SIZE];
>> +    int32_t val = new_addr - (site + ARCH_PATCH_INSN_SIZE);
>> +
>> +    insn[0] = 0xe8; /* CALL rel32. */
>> +    memcpy(&insn[1], &val, sizeof(val));
>> +    memcpy(site, insn, sizeof(insn));
>> +}
>
>Why noinline?  These are out-of-line anyway by being cross-TU, but in a
>theoretical world where we had working LTO, I don't see any problem with
>them being inlined.

I see. Thanks for explaining.
Here I added noinline following arch_livepatch_apply().
I'll remove them.

>> +
>> +void noinline arch_livepatch_revert_trace(const struct livepatch_func 
>> *trace)
>> +{
>> +    void *site = (void *)arch_livepatch_trace_entry((unsigned 
>> long)trace->old_addr);
>> +
>> +    memset(site, 0x90, ARCH_PATCH_INSN_SIZE);
>> +}
>> +#endif
>
>This wants to be a 5 byte NOP, not 5x 1-byte NOPs.
>
>I see that GCC is still doing the slow thing.  Clang is doing it's code
>generation more sensibly.
>
>Use the add_nops() function.

Understood. I'll use add_nops() in the next version.

Sincerely,
Ryo Takakura



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.