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

Re: [PATCH] xen/x86: Livepatch: support patching CET-enhanced functions


  • To: Bjoern Doebel <doebel@xxxxxxxxx>
  • From: Jan Beulich <jbeulich@xxxxxxxx>
  • Date: Mon, 7 Mar 2022 10:37:38 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; 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=/uHqtRAO9dlYDP5J95RWFP4BjApNFAFlG2TEmino1QM=; b=BrGLVpu0RUBVtISkk69VvFeBDTlJzJ6+uqCVTzEHIT6F3bWpdLWlqxCGLoVy2NOARHTPanN0X4a9a8KFCL/2N+p4abJt1jClCfyxJf7T/gttoGsy/o6lUFQqjKG0KYmPLkjTFmXwmZkBqE4aRuZObOBPHAOlJBRTt7iCirUESkIWPohTaXfJGOZIwsYGzOzyCMI0ggnPRwC1D4YG7SAjBXmh2PbzJZCAH/7A//jcVqfyC1AtH56e3lkSD4vTMwxPzq217a4iAris7pS5yUW4Jh0QjSx8RXFRmxX1rab2EktQLVLYeUrkNEKKx9cocBXSztfYGXn6OTf5GUZyi15BFA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=YL7Th8EZooU594QLeJKC1ka54w/mZMKRpyCI5yKxpfkIlEYG3UNMDSfNz+9bDyurrELLvAYd1IykKi/NdtgdQvPoJwj/P6EDbHOFor8mjgUdW9X+9PpFHPsQBKQj1SOy2c/2jHSjOeChT6s2jIhgNh3frJzI5IVtUzK6Pb+BsQz3eVfyKCpGvy/eepM27K3bIwhD90dTiWAWbpuVACDeYIN7lGGEr5lCf6O5+uLvNSbXA5+0zm5fD2mE15ICiSn4JG6ZXxCVz5iTIlBkJUVLvKZOeCeXBuJktvQWpXBZjKM6M7PMaZAapoQuygY4ll6nQJUhFz3Btbxa8VWo/cIXtQ==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=suse.com;
  • Cc: Michael Kurth <mku@xxxxxxxxx>, Martin Pohlack <mpohlack@xxxxxxxxx>, Roger Pau Monne <roger.pau@xxxxxxxxxx>, Andrew Cooper <Andrew.Cooper3@xxxxxxxxxx>, Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>, Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • Delivery-date: Mon, 07 Mar 2022 09:37:48 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On 07.03.2022 10:17, Bjoern Doebel wrote:
> Xen enabled CET for supporting architectures. The control flow aspect of
> CET expects functions that can be called indirectly (i.e., via function
> pointers) to start with an ENDBR64 instruction. Otherwise a control flow
> exception is raised.
> 
> This expectation breaks livepatching flows because we patch functions by
> overwriting their first 5 bytes with a JMP + <offset>, thus breaking the
> ENDBR64. We fix this by checking the start of a patched function for
> being ENDBR64. In the positive case we move the livepatch JMP to start
> behind the ENDBR64 instruction.
> 
> To avoid having to guess the ENDBR64 offset again on patch reversal
> (which might race with other mechanisms adding/removing ENDBR
> dynamically), use the livepatch metadata to store the computed offset
> along with the saved bytes of the overwritten function.
> 
> Signed-off-by: Bjoern Doebel <doebel@xxxxxxxxx>
> CC: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
> CC: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
> 
> Note that on top of livepatching functions, Xen supports an additional
> mode where we can "remove" a function by overwriting it with NOPs. This
> is only supported for functions up to 31 bytes in size and this patch
> reduces this limit to 27 bytes.

Is this intended to be part of the description (then it should move up)
or a post-commit-message remark (then there should be a --- separator
ahead of it)?

> --- a/xen/arch/x86/livepatch.c
> +++ b/xen/arch/x86/livepatch.c
> @@ -14,11 +14,28 @@
>  #include <xen/vm_event.h>
>  #include <xen/virtual_region.h>
>  
> +#include <asm/endbr.h>
>  #include <asm/fixmap.h>
>  #include <asm/nmi.h>
>  #include <asm/livepatch.h>
>  #include <asm/setup.h>
>  
> +/*
> + * CET hotpatching support: We may have functions starting with an ENDBR64 
> instruction
> + * that MUST remain the first instruction of the function, hence we need to 
> move any
> + * hotpatch trampoline further into the function. For that we need to keep 
> track of the
> + * patching offset used for any loaded hotpatch (to avoid racing against 
> other fixups
> + * adding/removing ENDBR64 or similar instructions).
> + *
> + * We do so by making use of the existing opaque metadata area. We use its 
> first 4 bytes
> + * to track the offset into the function used for patching and the remainder 
> of the data
> + * to store overwritten code bytes.
> + */

Style: Line length (also elsewhere).

> +struct __packed x86_livepatch_meta {
> +    int32_t patch_offset;

I was first going to suggest to use plain int here to comply with
./CODING_STYLE, but it looks like int8_t or uint8_t will do, leaving
more space for the insn. I'm also not convinced you really need the
__packed annotation. Furthermore, to avoid the need for casts,
simply using the ->opaque[] directly would look to be an option then
(with suitable #define-s to identify the two parts).

> @@ -104,11 +121,14 @@ void noinline arch_livepatch_revive(void)
>  
>  int arch_livepatch_verify_func(const struct livepatch_func *func)
>  {
> +    BUILD_BUG_ON(sizeof(struct x86_livepatch_meta) != LIVEPATCH_OPAQUE_SIZE);
> +
>      /* If NOPing.. */
>      if ( !func->new_addr )
>      {
> +        struct x86_livepatch_meta *lp = (struct 
> x86_livepatch_meta*)func->opaque;

_If_ there is to remain a struct, please insert the missing blank before
the star (applicable elsewhere as well), and please separate declaration(s)
from statement(s) by a blank line.

> -        if ( func->new_size > sizeof(func->opaque) )
> +        if ( func->new_size > sizeof(lp->instruction) )

This being the only use of the new variable, I expect compilers to warn
about the variable being actually unused.


> @@ -127,15 +147,20 @@ int arch_livepatch_verify_func(const struct 
> livepatch_func *func)
>  void noinline arch_livepatch_apply(struct livepatch_func *func)
>  {
>      uint8_t *old_ptr;
> -    uint8_t insn[sizeof(func->opaque)];
> +    struct x86_livepatch_meta *lp = (struct x86_livepatch_meta*)func->opaque;
> +    uint8_t insn[sizeof(lp->instruction)];
>      unsigned int len;
>  
> +    lp->patch_offset = 0;
>      old_ptr = func->old_addr;
>      len = livepatch_insn_len(func);
>      if ( !len )
>          return;
>  
> -    memcpy(func->opaque, old_ptr, len);
> +    if ( is_endbr64( old_ptr ) )

Style: No blanks inside the inner parentheses, please.

> @@ -159,7 +184,9 @@ void noinline arch_livepatch_apply(struct livepatch_func 
> *func)
>   */
>  void noinline arch_livepatch_revert(const struct livepatch_func *func)
>  {
> -    memcpy(func->old_addr, func->opaque, livepatch_insn_len(func));
> +    struct x86_livepatch_meta *lp = (struct x86_livepatch_meta*)func->opaque;

const (if the variable was to remain in the first place).

Jan

> +    memcpy(func->old_addr + lp->patch_offset, lp->instruction, 
> livepatch_insn_len(func));
>  }
>  
>  /*




 


Rackspace

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