All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: Andy Lutomirski <luto@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>,
	LKML <linux-kernel@vger.kernel.org>, X86 ML <x86@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Will Deacon <will@kernel.org>,
	Paolo Bonzini <pbonzini@redhat.com>,
	kvm list <kvm@vger.kernel.org>,
	linux-arch <linux-arch@vger.kernel.org>,
	Mike Rapoport <rppt@linux.ibm.com>,
	Miroslav Benes <mbenes@suse.cz>
Subject: Re: [patch V2 07/17] x86/entry/64: Remove redundant interrupt disable
Date: Thu, 24 Oct 2019 22:52:59 +0200 (CEST)	[thread overview]
Message-ID: <alpine.DEB.2.21.1910242032080.1783@nanos.tec.linutronix.de> (raw)
In-Reply-To: <CALCETrX+N_cR-HAmQyHxqUo0LPCk4GmqbzizXk-gq9qp00-RdA@mail.gmail.com>

On Thu, 24 Oct 2019, Andy Lutomirski wrote:
> On Wed, Oct 23, 2019 at 4:52 PM Thomas Gleixner <tglx@linutronix.de> wrote:
> > On Wed, 23 Oct 2019, Josh Poimboeuf wrote:
> > > What happens if somebody accidentally leaves irqs enabled?  How do we
> > > know you found all the leaks?
> >
> > For the DO_ERROR() ones that's trivial:
> >
> >  #define DO_ERROR(trapnr, signr, sicode, addr, str, name)                  \
> >  dotraplinkage void do_##name(struct pt_regs *regs, long error_code)       \
> >  {                                                                         \
> >         do_error_trap(regs, error_code, str, trapnr, signr, sicode, addr); \
> > +       lockdep_assert_irqs_disabled();                                    \
> >  }
> >
> >  DO_ERROR(X86_TRAP_DE,     SIGFPE,  FPE_INTDIV,   IP, "divide error",        divide_error)
> >
> > Now for the rest we surely could do:
> >
> > dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
> > {
> >         __do_bounds(regs, error_code);
> >         lockdep_assert_irqs_disabled();
> > }
> >
> > and move the existing body into a static function so independent of any
> > (future) return path there the lockdep assert will be invoked.
> >
> 
> If we do this, can we macro-ize it:
> 
> DEFINE_IDTENTRY_HANDLER(do_bounds)
> {
>  ...
> }
>  
> If you do this, please don't worry about the weird ones that take cr2
> as a third argument.  Once your series lands, I will send a follow-up
> to get rid of it.  It's 2/3 written already.

I spent quite some time digging deeper into this. Finding all corner cases
which eventually enable interrupts from an exception handler is not as
trivial as it looked in the first place. Especially the fault handler is a
nightmare. Also PeterZ's approach of doing

	   if (regs->eflags & IF)
	   	local_irq_disable();

is doomed due to sys_iopl(). See below.

I'm tempted to do pretty much the same thing as the syscall rework did
as a first step:

  - Move the actual handler invocation to C

  - Do the irq tracing on entry in C

  - Move irq disable before return to ASM

Peter gave me some half finished patches which pretty much do that by
copying half of the linux/syscalls.h macro maze into the entry code. That's
one possible solution, but TBH it sucks big times.

We have the following variants:

do_divide_error(struct pt_regs *regs, long error_code);
do_debug(struct pt_regs *regs, long error_code);
do_nmi(struct pt_regs *regs, long error_code);
do_int3(struct pt_regs *regs, long error_code);
do_overflow(struct pt_regs *regs, long error_code);
do_bounds(struct pt_regs *regs, long error_code);
do_invalid_op(struct pt_regs *regs, long error_code);
do_device_not_available(struct pt_regs *regs, long error_code);
do_coprocessor_segment_overrun(struct pt_regs *regs, long error_code);
do_invalid_TSS(struct pt_regs *regs, long error_code);
do_segment_not_present(struct pt_regs *regs, long error_code);
do_stack_segment(struct pt_regs *regs, long error_code);
do_general_protection(struct pt_regs *regs, long error_code);
do_spurious_interrupt_bug(struct pt_regs *regs, long error_code);
do_coprocessor_error(struct pt_regs *regs, long error_code);
do_alignment_check(struct pt_regs *regs, long error_code);
do_machine_check(struct pt_regs *regs, long error_code);
do_simd_coprocessor_error(struct pt_regs *regs, long error_code);
do_iret_error(struct pt_regs *regs, long error_code);
do_mce(struct pt_regs *regs, long error_code);

do_async_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);
do_double_fault(struct pt_regs *regs, long error_code, unsigned long address);
do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);

So if we can remove the third argument then we can spare most of the macro
maze and just have one common function without bells and whistels. The
other option would be to extend all handlers to have three arguments,
i.e. add 'long unused', which is not pretty either.

What's your plan with cr2? Stash it in pt_regs or something else?

Once we have the interesting parts in C then we can revisit the elimination
of the unconditional irq disable because in C it's way simpler to do
diagnostics, but I'm not entirely sure whether it's worth it.

A related issue is the inconsistency of the irq disabled tracing in the
return to user path. As I pointed out in the other mail, the various
syscall implementations do that differently. The exception handlers do it
always conditional, regular interrupts as well. For regular interrupts that
does not make sense as they can by all means never return to an interrupt
disabled context.

The interesting bells and whistels result from sys_iopl(). If user space
has been granted iopl(level = 3) it gains cli/sti priviledges. When the
application has interrupts disabled in userspace:

  - invocation of a syscall

  - any exception (aside of NMI/MCE) which conditionally enables interrupts
    depending on user_mode(regs) and therefor can be preempted and
    schedule

is just undefined behaviour and I personally consider it to be a plain bug.

Just for the record: This results in running a resulting or even completely
unrelated signal handler with interrupts disabled as well.

Whatever we decide it is, leaving it completely inconsistent is not a
solution at all. The options are:

  1)  Always do conditional tracing depending on the user_regs->eflags.IF
      state.

  2)  #1 + warn once when syscalls and exceptions (except NMI/MCE) happen
      and user_regs->eflags.IF is cleared.

  3a) #2 + enforce signal handling to run with interrupts enabled.

  3b) #2 + set regs->eflags.IF. So the state is always correct from the
      kernel POV. Of course that changes existing behaviour, but its
      changing undefined and inconsistent behaviour.
  
  4) Let iopl(level) return -EPERM if level == 3.

     Yeah, I know it's not possible due to regressions (DPKD uses iopl(3)),
     but TBH that'd be the sanest option of all.

     Of course the infinite wisdom of hardware designers tied IN, INS, OUT,
     OUTS and CLI/STI together on IOPL so we cannot even distangle them in
     any way.

     The only way out would be to actually use a full 8K sized I/O bitmap,
     but that's a massive pain as it has to be copied on every context
     switch. 

Really pretty options to chose from ...

Thanks,

	tglx

  reply	other threads:[~2019-10-24 20:53 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-23 12:27 [patch V2 00/17] entry: Provide generic implementation for host and guest entry/exit work Thomas Gleixner
2019-10-23 12:27 ` [patch V2 01/17] x86/entry/32: Remove unused resume_userspace label Thomas Gleixner
2019-10-23 13:43   ` Sean Christopherson
2019-11-06 15:26   ` Alexandre Chartre
2019-11-16 12:02   ` [tip: x86/asm] " tip-bot2 for Thomas Gleixner
2019-10-23 12:27 ` [patch V2 02/17] x86/entry/64: Remove pointless jump in paranoid_exit Thomas Gleixner
2019-10-23 13:45   ` Sean Christopherson
2019-11-06 15:29   ` Alexandre Chartre
2019-11-16 12:02   ` [tip: x86/asm] " tip-bot2 for Thomas Gleixner
2019-10-23 12:27 ` [patch V2 03/17] x86/traps: Remove pointless irq enable from do_spurious_interrupt_bug() Thomas Gleixner
2019-10-23 13:52   ` Sean Christopherson
2019-10-23 21:31   ` Josh Poimboeuf
2019-10-23 22:35     ` Thomas Gleixner
2019-10-23 22:49       ` Josh Poimboeuf
2019-10-23 23:18         ` Thomas Gleixner
2019-11-06 15:33   ` Alexandre Chartre
2020-02-27 14:15   ` [tip: x86/entry] " tip-bot2 for Thomas Gleixner
2019-10-23 12:27 ` [patch V2 04/17] x86/entry: Make DEBUG_ENTRY_ASSERT_IRQS_OFF available for 32bit Thomas Gleixner
2019-10-23 14:16   ` Sean Christopherson
2019-11-06 15:50   ` Alexandre Chartre
2019-10-23 12:27 ` [patch V2 05/17] x86/traps: Make interrupt enable/disable symmetric in C code Thomas Gleixner
2019-10-23 14:16   ` Sean Christopherson
2019-10-23 22:01   ` Josh Poimboeuf
2019-10-23 23:23     ` Thomas Gleixner
2019-11-06 16:19   ` Alexandre Chartre
2019-10-23 12:27 ` [patch V2 06/17] x86/entry/32: Remove redundant interrupt disable Thomas Gleixner
2019-10-23 14:17   ` Sean Christopherson
2019-11-08 10:41   ` Alexandre Chartre
2019-10-23 12:27 ` [patch V2 07/17] x86/entry/64: " Thomas Gleixner
2019-10-23 14:20   ` Sean Christopherson
2019-10-23 22:06   ` Josh Poimboeuf
2019-10-23 23:52     ` Thomas Gleixner
2019-10-24 16:18       ` Andy Lutomirski
2019-10-24 20:52         ` Thomas Gleixner [this message]
2019-10-24 20:59           ` Thomas Gleixner
2019-10-24 21:21           ` Peter Zijlstra
2019-10-24 21:24           ` Andy Lutomirski
2019-10-24 22:33             ` Thomas Gleixner
2019-11-08 11:07   ` Alexandre Chartre
2019-10-23 12:27 ` [patch V2 08/17] x86/entry: Move syscall irq tracing to C code Thomas Gleixner
2019-10-23 21:30   ` Andy Lutomirski
2019-10-23 21:35     ` Andy Lutomirski
2019-10-23 23:31       ` Thomas Gleixner
2019-10-23 23:16     ` Thomas Gleixner
2019-10-24 16:24     ` Andy Lutomirski
2019-10-24 17:40       ` Peter Zijlstra
2019-10-24 20:54         ` Thomas Gleixner
2019-10-23 12:27 ` [patch V2 09/17] x86/entry: Remove _TIF_NOHZ from _TIF_WORK_SYSCALL_ENTRY Thomas Gleixner
2020-01-06  4:11   ` Frederic Weisbecker
2019-10-23 12:27 ` [patch V2 10/17] entry: Provide generic syscall entry functionality Thomas Gleixner
2019-10-23 12:27 ` [patch V2 11/17] x86/entry: Use generic syscall entry function Thomas Gleixner
2019-10-23 12:27 ` [patch V2 12/17] entry: Provide generic syscall exit function Thomas Gleixner
2019-10-23 12:27 ` [patch V2 13/17] x86/entry: Use generic syscall exit functionality Thomas Gleixner
2019-10-23 12:27 ` [patch V2 14/17] entry: Provide generic exit to usermode functionality Thomas Gleixner
2019-10-23 21:34   ` Andy Lutomirski
2019-10-23 23:20     ` Thomas Gleixner
2019-10-23 12:27 ` [patch V2 15/17] x86/entry: Use generic exit to usermode Thomas Gleixner
2019-10-23 12:27 ` [patch V2 16/17] kvm/workpending: Provide infrastructure for work before entering a guest Thomas Gleixner
2019-10-23 14:55   ` Sean Christopherson
2019-10-23 12:27 ` [patch V2 17/17] x86/kvm: Use generic exit to guest work function Thomas Gleixner
2019-10-23 14:48   ` Sean Christopherson
2019-10-23 14:37 ` [patch V2 00/17] entry: Provide generic implementation for host and guest entry/exit work Peter Zijlstra
2019-10-23 21:20 ` Josh Poimboeuf
2019-10-29 11:28 ` Will Deacon

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=alpine.DEB.2.21.1910242032080.1783@nanos.tec.linutronix.de \
    --to=tglx@linutronix.de \
    --cc=jpoimboe@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mbenes@suse.cz \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rppt@linux.ibm.com \
    --cc=will@kernel.org \
    --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.