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

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


  • To: Ryo Takakura <takakura@xxxxxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
  • Date: Mon, 26 Oct 2026 11:42:37 +0000
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; 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=FukvoVM4ETQ9fcfHekUbRmCsHm3zWnmvZr0oaIU+IKE=; b=b98Wz+JYtJMxy10qsGunVaUPiz7dGeacOcq6yRpzbqAX09duCSAyaoNlWtvAbdGu/agVMxpuhnHKqwu3FY9a73K+XY9jH6MbobBDUf2dtG1Iuuf+oazs582LGHBrkL2nWTxUwGvDPMwZPHKQhU93yYOiJOaOWqwVctXf3cwX7zk5XTRWHZPnutC8FO5I7mfSkkzo5AHdm7K8qk2qDG47sA6ZQvrGNKEYaHVJtNmIrxiQwrAlWg7YcrauW5v7M/CGxF2W/VX0DaHvVQvgDxoPgFG3Gc9kGIaaxBUSVxDU6mH3uktizaDy+E6/V0sIQOrQUJF674nGXIp3/W0HUnLu7Q==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=sW7fkIPRyvszBsgYAJJoiLiXx30Jo//QbG2ibJ68RoUToum2rvrBMbH1dqpY1Di9K6PM7RHz5UuI7CJJZLXoFE/0kCWoXwiGqgPSehVxpGxwm+1uXF4FKdLwXGAOLeQsy02/N0fYdoOaQrqnUIE0ZnGpNGa9RpkfuHuJI9C66Ui3y+gcyibWxKCYzYt2q+m4ZqDLXj2oswWWVtMWDxOYUOie3RYyi2asT1FJjJW+yhISD3nEib8s8zN0Xr/zDqm6OtjxBpqNB0vE5Fm3k1pZSleoOTc7q4I3sCFDdsGph1Awh8/JKH05rAJhLSCJ6jaoSYeseLFxRjzCf6+czgXekQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=citrix.com header.i="@citrix.com" 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=citrix.com;
  • Autocrypt: addr=andrew.cooper3@xxxxxxxxxx; keydata= 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 6+ahAA==
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, roger@xxxxxxxxxxxxxx, ross.lagerwall@xxxxxxxxxx, sstabellini@xxxxxxxxxx, julien@xxxxxxx, bertrand.marquis@xxxxxxx, michal.orzel@xxxxxxx, Volodymyr_Babchuk@xxxxxxxx, anthony.perard@xxxxxxxxxx, jbeulich@xxxxxxxx, teddy.astie@xxxxxxxxxx
  • Delivery-date: Mon, 26 Oct 2026 11:42:57 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

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.

> +/*
> + * 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.

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.

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.

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

> + */
> +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.)

> 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.

> +
>  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.

> +
> +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.

~Andrew



 


Rackspace

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