linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>,
	Boqun Feng <boqun.feng@gmail.com>,
	Andy Lutomirski <luto@amacapital.net>,
	Dave Watson <davejwatson@fb.com>,
	linux-kernel <linux-kernel@vger.kernel.org>,
	linux-api <linux-api@vger.kernel.org>,
	Paul Turner <pjt@google.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	Russell King <linux@arm.linux.org.uk>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, "H. Peter Anvin" <hpa@zytor.com>,
	Andrew Hunter <ahh@google.com>, Andi Kleen <andi@firstfloor.org>,
	Chris Lameter <cl@linux.com>, Ben Maurer <bmaurer@fb.com>,
	rostedt <rostedt@goodmis.org>,
	Josh Triplett <josh@joshtriplett.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Catalin Marinas <catalin.marinas@arm.com>, Will Deacon <will>
Subject: Re: [RFC PATCH for 4.17 02/21] rseq: Introduce restartable sequences system call (v12)
Date: Wed, 28 Mar 2018 12:19:05 -0400 (EDT)	[thread overview]
Message-ID: <1976612894.96.1522253945890.JavaMail.zimbra@efficios.com> (raw)
In-Reply-To: <20180328122946.GU4043@hirez.programming.kicks-ass.net>

----- On Mar 28, 2018, at 8:29 AM, Peter Zijlstra peterz@infradead.org wrote:

> On Tue, Mar 27, 2018 at 12:05:23PM -0400, Mathieu Desnoyers wrote:

[...]

>> +	/* Ensure that abort_ip is not in the critical section. */
>> +	if (rseq_cs.abort_ip - rseq_cs.start_ip < rseq_cs.post_commit_offset)
>> +		return -EINVAL;
> 
> The kernel will not crash if userspace messes that up right? So why do
> we care to check?

That's because the kernel clears the TLS @rseq_cs pointer whenever it restarts
a rseq critical section. Therefore, if the abort_ip points somewhere within
the rseq critical section, the kernel will clear the @rseq_cs pointer, move the
instruction pointer to the abort_ip, and return to user-space. At that stage,
user-space will still be running within a rseq critical section, but the
@rseq_cs pointer is NULL. So if the kernel preempts again before that critical
section completes, it will completely miss it.

So having the kernel segfault userspace when this pattern is encountered
is an extra safety net ensuring that if user-space ever implement such
construct, at least it will segfault quickly, and will therefore be easier
to debug, because easier to reproduce.

>> +
>> +	usig = (u32 __user *)(rseq_cs.abort_ip - sizeof(u32));
>> +	ret = get_user(sig, usig);
>> +	if (ret)
>> +		return ret;
>> +
> 
>> +	if (current->rseq_sig != sig) {
>> +		printk_ratelimited(KERN_WARNING
>> +			"Possible attack attempt. Unexpected rseq signature 0x%x, expecting 0x%x
>> (pid=%d, addr=%p).\n",
>> +			sig, current->rseq_sig, current->pid, usig);
>> +		return -EPERM;
>> +	}
> 
> Is there any text that explains the thread model and possible attack
> that this signature prevents? I failed to find any, which raises the
> question, why is it there..

The threat model is an attacker partly controlling a user-space process, trying
to execute his own code by abusing the rseq restart mechanism to make the kernel
jump to a user-space address of his choice, which contains either an injected shell
code or specific library functions, thus escalating to full control of the process
execution.

Where should I document this ?

> 
>> +	int ret;
>> +
>> +	/* Get thread flags. */
>> +	ret = __get_user(flags, &t->rseq->flags);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* Take critical section flags into account. */
>> +	flags |= cs_flags;
>> +
>> +	/*
>> +	 * Restart on signal can only be inhibited when restart on
>> +	 * preempt and restart on migrate are inhibited too. Otherwise,
>> +	 * a preempted signal handler could fail to restart the prior
>> +	 * execution context on sigreturn.
>> +	 */
>> +	if (unlikely(flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL)) {
>> +		if ((flags & (RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE
>> +		    | RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT)) !=
>> +		    (RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE
>> +		     | RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT))
>> +			return -EINVAL;
> 
> Please put operators at the end of the previous line, not at the start
> of the new line when you have to break statements.
> 
> Also, that's unreadable.
> 
> #define RSEQ_CS_FLAGS (RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT |	\
>		       RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL  |	\
>		       RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE)
> 
>	if (unlikely((flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL) &&
>	             (flags & RSEQ_CS_FLAGS) != RSEQ_CS_FLAGS))
>		return -EINVAL;
> 

Based on your suggestion:

#define RSEQ_CS_PREEMPT_MIGRATE_FLAGS (RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE |     \
                                       RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT)

        if (unlikely((flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL) &&
                     (flags & RSEQ_CS_PREEMPT_MIGRATE_FLAGS) !=
                     RSEQ_CS_PREEMPT_MIGRATE_FLAGS))
                return -EINVAL;


>> +}
>> +
>> +static int clear_rseq_cs(struct task_struct *t)
>> +{
>> +	unsigned long ptr = 0;
>> +
>> +	/*
>> +	 * The rseq_cs field is set to NULL on preemption or signal
>> +	 * delivery on top of rseq assembly block, as well as on top
>> +	 * of code outside of the rseq assembly block. This performs
>> +	 * a lazy clear of the rseq_cs field.
>> +	 *
>> +	 * Set rseq_cs to NULL with single-copy atomicity.
>> +	 */
>> +	return __put_user(ptr, &t->rseq->rseq_cs);
> 
>	__put_user(0UL, &t->rseq->rseq_cs); ?

Yes.

> 
>> +}
>> +
>> +static int rseq_ip_fixup(struct pt_regs *regs)
>> +{
>> +	unsigned long ip = instruction_pointer(regs), start_ip = 0,
>> +		post_commit_offset = 0, abort_ip = 0;
> 
> valid C, but yuck. Just have two 'unsigned long' lines.
> 
> Also, why the =0, the below call to rseq_get_rseq_cs() will either
> initialize of fail.

rseq_get_rseq_cs() can return 0 (success) if __get_user finds a
NULL pointer in the @rseq_cs TLS field. I'll use a
struct rseq_cs * parameter instead, and memset to 0 only in that
specific success case within rseq_get_rseq_cs() rather than always
initialize to 0 in its caller.

> 
> 
>> +	if (ret)
>> +		return ret;
>> +
>> +	/*
>> +	 * Handle potentially not being within a critical section.
>> +	 * Unsigned comparison will be true when
>> +	 * ip >= start_ip, and when ip < start_ip + post_commit_offset.
>> +	 */
>> +	if (ip - start_ip < post_commit_offset)
>> +		in_rseq_cs = true;
>> +
>> +	/*
>> +	 * If not nested over a rseq critical section, restart is
>> +	 * useless. Clear the rseq_cs pointer and return.
>> +	 */
>> +	if (!in_rseq_cs)
>> +		return clear_rseq_cs(t);
> 
> 
> That all seems needlessly complicated; isn't:
> 
>	if (ip - start_ip >= post_commit_offset)
>		return clear_rseq_cs();
> 
> equivalent? Nothing seems to use that variable after this.

Yep, Boqun already pointed it out. Fixed.

Thanks!

Mathieu


-- 
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com

  parent reply	other threads:[~2018-03-28 16:19 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-27 16:05 [RFC PATCH for 4.17 00/21] Restartable sequences and CPU op vector Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 01/21] uapi headers: Provide types_32_64.h Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 02/21] rseq: Introduce restartable sequences system call (v12) Mathieu Desnoyers
2018-03-28  6:47   ` Boqun Feng
2018-03-28 14:06     ` Mathieu Desnoyers
2018-03-28 14:31       ` Mathieu Desnoyers
2018-03-28 11:19   ` Peter Zijlstra
2018-03-28 14:19     ` Mathieu Desnoyers
2018-03-28 11:22   ` Peter Zijlstra
2018-03-28 14:26     ` Mathieu Desnoyers
2018-03-28 12:29   ` Peter Zijlstra
2018-03-28 12:52     ` Peter Zijlstra
2018-03-28 15:03       ` Mathieu Desnoyers
2018-03-28 16:19     ` Mathieu Desnoyers [this message]
2018-03-28 12:50   ` Peter Zijlstra
2018-03-28 14:47     ` Mathieu Desnoyers
2018-03-28 14:59       ` Peter Zijlstra
2018-03-28 15:14         ` Mathieu Desnoyers
2018-03-28 15:28           ` Peter Zijlstra
2018-03-28 15:37             ` Mathieu Desnoyers
2018-03-28 17:49               ` Peter Zijlstra
2018-03-28 20:19                 ` Mathieu Desnoyers
2018-03-28 21:25                   ` Thomas Gleixner
2018-03-29 13:54                     ` Mathieu Desnoyers
2018-03-29 14:23                       ` Peter Zijlstra
2018-03-29 15:39                         ` Mathieu Desnoyers
2018-03-29 16:24                           ` Steven Rostedt
2018-03-29 18:02                             ` Mathieu Desnoyers
2018-03-29 18:07                               ` Steven Rostedt
2018-03-29 18:35                                 ` Mathieu Desnoyers
2018-03-29 18:46                                   ` Steven Rostedt
2018-03-29 18:47                                     ` Steven Rostedt
2018-04-01 16:13   ` Alan Cox
2018-04-02 15:03     ` Christopher Lameter
2018-04-02 15:27       ` Paul E. McKenney
2018-04-02 15:33     ` Mathieu Desnoyers
2018-04-03 16:36       ` Mathieu Desnoyers
2018-04-03 20:32         ` Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 03/21] arm: Add restartable sequences support Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 04/21] arm: Wire up restartable sequences system call Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 05/21] x86: Add support for restartable sequences Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 06/21] x86: Wire up restartable sequence system call Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 07/21] powerpc: Add support for restartable sequences Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 08/21] powerpc: Wire up restartable sequences system call Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 09/21] sched: Implement push_task_to_cpu (v2) Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 10/21] cpu_opv: Provide cpu_opv system call (v6) Mathieu Desnoyers
2018-03-28 15:22   ` Peter Zijlstra
2018-03-28 17:54     ` Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 11/21] x86: Wire up cpu_opv system call Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 12/21] powerpc: " Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 13/21] arm: " Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 14/21] selftests: lib.mk: Introduce OVERRIDE_TARGETS Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 15/21] cpu_opv: selftests: Implement selftests (v7) Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 16/21] rseq: selftests: Provide rseq library (v5) Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 17/21] rseq: selftests: Provide percpu_op API Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 18/21] rseq: selftests: Provide basic test Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 19/21] rseq: selftests: Provide basic percpu ops test Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 20/21] rseq: selftests: Provide parametrized tests Mathieu Desnoyers
2018-03-27 16:05 ` [RFC PATCH for 4.17 21/21] rseq: selftests: Provide Makefile, scripts, gitignore Mathieu Desnoyers
2018-03-27 19:09 ` [RFC PATCH for 4.17 00/21] Restartable sequences and CPU op vector Peter Zijlstra

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=1976612894.96.1522253945890.JavaMail.zimbra@efficios.com \
    --to=mathieu.desnoyers@efficios.com \
    --cc=ahh@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=andi@firstfloor.org \
    --cc=bmaurer@fb.com \
    --cc=boqun.feng@gmail.com \
    --cc=catalin.marinas@arm.com \
    --cc=cl@linux.com \
    --cc=davejwatson@fb.com \
    --cc=hpa@zytor.com \
    --cc=josh@joshtriplett.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=luto@amacapital.net \
    --cc=mingo@redhat.com \
    --cc=paulmck@linux.vnet.ibm.com \
    --cc=peterz@infradead.org \
    --cc=pjt@google.com \
    --cc=rostedt@goodmis.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).