From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
To: Andy Lutomirski <luto@amacapital.net>
Cc: Ingo Molnar <mingo@redhat.com>,
Thomas Gleixner <tglx@linutronix.de>,
Borislav Petkov <bp@suse.de>, Andy Lutomirski <luto@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
X86 ML <x86@kernel.org>,
linux-msdos@vger.kernel.org, wine-devel@winehq.org,
Andrew Morton <akpm@linux-foundation.org>,
"H . Peter Anvin" <hpa@zytor.com>,
Brian Gerst <brgerst@gmail.com>, Chen Yucong <slaoub@gmail.com>,
Chris Metcalf <cmetcalf@mellanox.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Fenghua Yu <fenghua.yu@intel.com>, Huang Rui <ray.huang@amd.com>,
Jiri Slaby <jslaby@suse.cz>, Jonathan Corbet <corbet@lwn.net>,
"Michael S . Tsirkin" <mst@redhat.com>,
Paul Gortmaker <paul.gortmaker@windriver.com>,
Ravi
Subject: Re: [v2 5/7] x86: Add emulation code for UMIP instructions
Date: Thu, 29 Dec 2016 21:23:32 -0800 [thread overview]
Message-ID: <1483075412.106950.86.camel@ranerica-desktop> (raw)
In-Reply-To: <CALCETrUZsCGSyd3sf1O7-Sb90w7hewRWunwQXU1x2kZog_aFcA@mail.gmail.com>
On Tue, 2016-12-27 at 16:48 -0800, Andy Lutomirski wrote:
> On Tue, Dec 27, 2016 at 4:39 PM, Ricardo Neri
> <ricardo.neri-calderon@linux.intel.com> wrote:
> > On Fri, 2016-12-23 at 18:11 -0800, Andy Lutomirski wrote:
> >> On Fri, Dec 23, 2016 at 5:37 PM, Ricardo Neri
> >> <ricardo.neri-calderon@linux.intel.com> wrote:
> >> > The feature User-Mode Instruction Prevention present in recent Intel
> >> > processor prevents a group of instructions from being executed with
> >> > CPL > 0. Otherwise, a general protection fault is issued.
> >> >
> >> > Rather than relaying this fault to the user space (in the form of a SIGSEGV
> >> > signal), the instructions protected by UMIP can be emulated to provide
> >> > dummy results. This allows to conserve the current kernel behavior and not
> >> > reveal the system resources that UMIP intends to protect (the global
> >> > descriptor and interrupt descriptor tables, the segment selectors of the
> >> > local descriptor table and the task state and the machine status word).
> >> >
> >> > This emulation is needed because certain applications (e.g., WineHQ) rely
> >> > on this subset of instructions to function.
> >> >
> >> > The instructions protected by UMIP can be split in two groups. Those who
> >> > return a kernel memory address (sgdt and sidt) and those who return a
> >> > value (sldt, str and smsw).
> >> >
> >> > For the instructions that return a kernel memory address, the result is
> >> > emulated as the location of a dummy variable in the kernel memory space.
> >> > This is needed as applications such as WineHQ rely on the result being
> >> > located in the kernel memory space function. The limit for the GDT and the
> >> > IDT are set to zero.
> >>
> >> Nak. This is a trivial KASLR bypass. Just give them hardcoded
> >> values. For x86_64, I would suggest 0xfffffffffffe0000 and
> >> 0xffffffffffff0000.
> >
> > I see. I assume you are suggesting these values for x86_64 because they
> > lie in an unused hole. That makes sense to me.
> >
> > For the case of x86_32, I have trouble finding a suitable place as there
> > are not many available holes. It could be put before VMALLOC_START or
> > after VMALLOC_END but this would reveal the position of the vmalloc
> > area. Although, to my knowledge, randomized memory is not available for
> > x86_32. Without randomization, does it hurt to make sidt/sgdt return the
> > address of a kernel static variable?
>
> I would just use the same addresses, truncated. There's no reason
> that the address needs to be truly not present -- it just needs to be
> inaccessible to user code. Anything near the top of the address space
> should work.
Right. Then I will reuse the same addresses.
>
> >
> >>
> >> >
> >> > The instructions sldt and str return a segment selector relative to the
> >> > base address of the global descriptor table. Since the actual address of
> >> > such table is not revealed, it makes sense to emulate the result as zero.
> >>
> >> Hmm, now I wonder if anything uses SLDT to see if there is an LDT. If
> >> so, we could emulate it better, but I doubt this matters.
> >
> > So you are saying that the emulated sldt should return a different value
> > based on the presence/absence of a LDT? This could reveal this very
> > fact.
>
> User code knows whether the LDT exists because an LDT only exists if
> the program called modify_ldt(). But I doubt this matters in
> practice.
In such a case sldt would return a non-null segment selector. I will
keep giving the null segment selector in all cases and make a note in
the code.
>
> >> > +static int __emulate_umip_insn(struct insn *insn, enum umip_insn umip_inst,
> >> > + unsigned char *data, int *data_size)
> >> > +{
> >> > + unsigned long const *dummy_base_addr;
> >> > + unsigned short dummy_limit = 0;
> >> > + unsigned short dummy_value = 0;
> >> > +
> >> > + switch (umip_inst) {
> >> > + /*
> >> > + * These two instructions return the base address and limit of the
> >> > + * global and interrupt descriptor table. The base address can be
> >> > + * 32-bit or 64-bit. Limit is always 16-bit.
> >> > + */
> >> > + case UMIP_SGDT:
> >> > + case UMIP_SIDT:
> >> > + if (umip_inst == UMIP_SGDT)
> >> > + dummy_base_addr = &umip_dummy_gdt_base;
> >> > + else
> >> > + dummy_base_addr = &umip_dummy_idt_base;
> >> > + if (X86_MODRM_MOD(insn->modrm.value) == 3) {
> >> > + WARN_ONCE(1, "SGDT cannot take register as argument!\n");
> >>
> >> No warnings please.
> >
> > I'll. Remove it.
>
> Thanks. In general, WARN_ONCE, etc are supposed to indicate kernel
> bugs, not user bugs.
Agreed. Your statement makes it very clear. I didn't have it that clear
in my mind.
>
> >> > + int not_copied, nr_copied, reg_offset, dummy_data_size;
> >> > + void __user *uaddr;
> >> > + unsigned long *reg_addr;
> >> > + enum umip_insn umip_inst;
> >> > +
> >> > + not_copied = copy_from_user(buf, (void __user *)regs->ip, sizeof(buf));
> >>
> >> This is slightly wrong due to PKRU. I doubt we care.
> >
> > I see. If I am not mistaken, if the memory is protected by a protection
> > key this would cause a page fault. I'll make a note of it.
>
> Exactly. This is correct behavior unless the key happens to be set up
> so it can be executed but not read, in which case emulation will fail.
If we can't read we can't emulate anyways. I will add another note.
>
> >>
> >> > + nr_copied = sizeof(buf) - not_copied;
> >> > + /*
> >> > + * The decoder _should_ fail nicely if we pass it a short buffer.
> >> > + * But, let's not depend on that implementation detail. If we
> >> > + * did not get anything, just error out now.
> >> > + */
> >> > + if (!nr_copied)
> >> > + return -EFAULT;
> >>
> >> If the caller cares about EINVAL vs EFAULT, it cares because it is
> >> considering changing the signal to a fake page fault. If so, then
> >> this should be EINVAL -- failure to read the text should just prevent
> >> emulation.
> >
> > I see. The caller in this case do_general_protection, which will issue a
> > SIGSEGV to the user space anyways. I don't think it cares about the
> > EINVAL vs EFAULT. It does care about whether the emulation was
> > successful.
>
> Maybe just make it return bool then? But fixing up the return codes
> would be fine, too. I just think that, if it returns int, the value
> should be meaningful.
Right. I have a small query/proposal related to this below.
>
> >> > + if (nr_copied > 0)
> >> > + return -EFAULT;
> >>
> >> This should be the only EFAULT case.
> > Should this be EFAULT event if the caller cares only about successful
> > (return 0) vs failed (return non-0) emulation?
>
> In theory this particular error would be a page fault not a general
> protection fault (in the UMIP off case). If you were emulating it
> extra carefully, you could change the signal accordingly. But, as I
> said, I really doubt this matters.
If simple enough and for the sake of accuracy, I could try to issue the
page fault. It seems to me that this entitles calling
force_sig_info_fault in this particular case as opposed to the
force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk) that do_general_protection
calls.
Thanks and BR,
Ricardo
next prev parent reply other threads:[~2016-12-30 5:23 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-24 1:37 [v2 0/7] x86: enable User-Mode Instruction Prevention Ricardo Neri
2016-12-24 1:37 ` [v2 1/7] x86/mpx: Do not use SIB index if index points to R/ESP Ricardo Neri
2016-12-24 1:57 ` Andy Lutomirski
2016-12-27 22:29 ` Ricardo Neri
2016-12-24 1:37 ` [v2 2/7] x86/mpx: Fail when implicit zero-displacement is used along with R/EBP Ricardo Neri
2016-12-24 1:58 ` Andy Lutomirski
2016-12-27 22:33 ` Ricardo Neri
2017-01-03 16:41 ` Dave Hansen
2017-01-04 1:31 ` Ricardo Neri
2016-12-24 1:37 ` [v2 3/7] x86/mpx, x86/insn: Relocate insn util functions to a new insn-utils Ricardo Neri
2016-12-24 2:34 ` kbuild test robot
2016-12-25 6:17 ` Masami Hiramatsu
2016-12-27 22:36 ` Ricardo Neri
2017-01-03 16:44 ` Dave Hansen
2017-01-04 1:31 ` Ricardo Neri
2016-12-24 1:37 ` [v2 4/7] x86/cpufeature: Add User-Mode Instruction Prevention definitions Ricardo Neri
2016-12-24 1:37 ` [v2 5/7] x86: Add emulation code for UMIP instructions Ricardo Neri
2016-12-24 2:11 ` Andy Lutomirski
2016-12-28 0:39 ` Ricardo Neri
2016-12-28 0:48 ` Andy Lutomirski
2016-12-30 5:23 ` Ricardo Neri [this message]
2016-12-31 2:07 ` Andy Lutomirski
2017-01-04 1:30 ` Ricardo Neri
2016-12-25 15:49 ` Masami Hiramatsu
2016-12-28 0:40 ` Ricardo Neri
2016-12-24 1:37 ` [v2 6/7] x86/traps: Fixup general protection faults caused by UMIP Ricardo Neri
2016-12-24 2:11 ` Andy Lutomirski
2016-12-27 22:34 ` Ricardo Neri
2016-12-24 4:22 ` kbuild test robot
2016-12-24 1:37 ` [v2 7/7] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2016-12-24 3:15 ` kbuild test robot
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=1483075412.106950.86.camel@ranerica-desktop \
--to=ricardo.neri-calderon@linux.intel.com \
--cc=akpm@linux-foundation.org \
--cc=bp@suse.de \
--cc=brgerst@gmail.com \
--cc=cmetcalf@mellanox.com \
--cc=corbet@lwn.net \
--cc=dave.hansen@linux.intel.com \
--cc=fenghua.yu@intel.com \
--cc=hpa@zytor.com \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-msdos@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=luto@kernel.org \
--cc=mingo@redhat.com \
--cc=mst@redhat.com \
--cc=paul.gortmaker@windriver.com \
--cc=peterz@infradead.org \
--cc=ray.huang@amd.com \
--cc=slaoub@gmail.com \
--cc=tglx@linutronix.de \
--cc=wine-devel@winehq.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox