All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Zijlstra <peterz@infradead.org>
To: Borislav Petkov <bp@alien8.de>
Cc: X86 ML <x86@kernel.org>, LKML <linux-kernel@vger.kernel.org>,
	Richard Narron <richard@aaazen.com>
Subject: Re: [PATCH] x86/alternative: Optimize single-byte NOPs at an arbitrary position
Date: Wed, 2 Jun 2021 10:14:58 +0200	[thread overview]
Message-ID: <YLc+AniWgFBdMbX6@hirez.programming.kicks-ass.net> (raw)
In-Reply-To: <20210601212125.17145-1-bp@alien8.de>

On Tue, Jun 01, 2021 at 11:21:25PM +0200, Borislav Petkov wrote:
> From: Borislav Petkov <bp@suse.de>
> 
> Up until now the assumption was that an alternative patching site would
> have some instructions at the beginning and trailing single-byte NOPs
> (0x90) padding. Therefore, the patching machinery would go and optimize
> those single-byte NOPs into longer ones.
> 
> However, this assumption is broken on 32-bit when code like
> hv_do_hypercall() in hyperv_init() would use the ratpoline speculation
> killer CALL_NOSPEC. The 32-bit version of that macro would align certain
> insns to 16 bytes, leading to the compiler issuing a one or more
> single-byte NOPs, depending on the holes it needs to fill for alignment.

Who again insisted that wouldn't happen? :-)

> diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> index 6974b5174495..7baf13b11952 100644
> --- a/arch/x86/kernel/alternative.c
> +++ b/arch/x86/kernel/alternative.c
> @@ -182,42 +182,68 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insn_buff)
>  		n_dspl, (unsigned long)orig_insn + n_dspl + repl_len);
>  }
>  
> +/*
> + * @instr: instruction byte stream
> + * @instrlen: length of the above
> + * @off: offset within @instr where the first NOP has been detected
> + */

That's almost a proper comment, might as well finish it

/*
 * optimize_nops_range() - Optimize a sequence of single byte NOPs (0x90)
 * @instr: instruction byte stream
 * @instrlen: length of the above
 * @off: offset within @instr where the first NOP has been detected
 *
 * Return: number of NOPs found (and replaced)
 */
> +static __always_inline int optimize_nops_range(u8 *instr, u8 instrlen, int off)
> +{
> +	unsigned long flags;
> +	int i = off, nnops;
> +
> +	while (i < instrlen) {
> +		if (instr[i] != 0x90)
> +			break;
> +
> +		i++;
> +	}

	for (; i < instrlen && instr[i] == 0x90; i++)
		;

perhaps? (possibly too dense, up to you)

> +
> +	nnops = i - off;
> +
> +	if (nnops <= 1)
> +		return nnops;

!nnops would be an error, no?

> +
> +	local_irq_save(flags);
> +	add_nops(instr + off, nnops);
> +	local_irq_restore(flags);
> +
> +	DUMP_BYTES(instr, instrlen, "%px: [%d:%d) optimized NOPs: ",
> +		   instr, off, i);
> +
> +	return nnops;
> +}
> +
> +

We really needs that extra line?

>  /*
>   * "noinline" to cause control flow change and thus invalidate I$ and
>   * cause refetch after modification.
>   */
>  static void __init_or_module noinline optimize_nops(struct alt_instr *a, u8 *instr)
>  {
>  	struct insn insn;
> +	int i = 0;
>  
>  	/*
> +	 * Jump over the non-NOP insns and optimize single-byte NOPs into bigger
> +	 * ones.
>  	 */
>  	for (;;) {
>  		if (insn_decode_kernel(&insn, &instr[i]))
>  			return;
>  
> +		/*
> +		 * See if this and any potentially following NOPs can be
> +		 * optimized.
> +		 */
>  		if (insn.length == 1 && insn.opcode.bytes[0] == 0x90)
> +			i += optimize_nops_range(instr, a->instrlen, i);
> +		else
> +			i += insn.length;
>  
> +		if (i >= a->instrlen)
>  			return;
>  	}
>  }

Anyway, irrespective of nits:

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>

  reply	other threads:[~2021-06-02  8:15 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-01 21:21 [PATCH] x86/alternative: Optimize single-byte NOPs at an arbitrary position Borislav Petkov
2021-06-02  8:14 ` Peter Zijlstra [this message]
2021-06-02 10:37   ` Borislav Petkov
2021-06-02 19:49 ` [tip: x86/urgent] " tip-bot2 for Borislav Petkov
2021-06-03 14:38 ` tip-bot2 for Borislav Petkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YLc+AniWgFBdMbX6@hirez.programming.kicks-ass.net \
    --to=peterz@infradead.org \
    --cc=bp@alien8.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=richard@aaazen.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.