mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Cyrill Gorcunov <gorcunov@gmail.com>
To: Alexander van Heukelum <alexander@mail.messagingengine.com>
Cc: Ingo Molnar <mingo@elte.hu>, "H. Peter Anvin" <hpa@zytor.com>,
	The stable team <stable@kernel.org>,
	LKML <linux-kernel@vger.kernel.org>,
	Andi Kleen <andi@firstfloor.org>,
	Thomas Gleixner <tglx@linutronix.de>
Subject: Re: [PATCH] i386: fix return to 16-bit stack from NMI handler
Date: Tue, 26 May 2009 18:15:17 +0400	[thread overview]
Message-ID: <20090526141517.GA5068@lenovo> (raw)
In-Reply-To: <alpine.DEB.2.00.0905242021460.3810@diotoir>

[Alexander van Heukelum - Sun, May 24, 2009 at 08:24:09PM +0200]
> The nmi handler changes esp on return from the kernel to a process
> with a 16-bit stack. To reproduce, compile and run the following
> program with the nmi watchdog enabled (nmi_watchdog=2 on the command
> line). Using gdb you can see that the high bits of esp contain garbage,
> while the low bits are still correct. This is what the 'espfix' code is
> supposed to fix, but the nmi handler does not include it.
>
> The nmi code cannot call the irqtrace infrastructure. Otherwise, the tail
> of the normal iret-code is correct for the nmi code path too. To be
> able to share this code-path, I moved the TRACE_IRQS_IRET a bit earlier.
> This code-path now includes the espfix code, which explicitly disables
> interrupts. This short interrupts-off section is now not traced anymore.
> The preempt-return-to-kernel path now includes the preliminary test to
> decide if the espfix code should be called. This is never the case, but
> doing it this way keeps the patch simple and the few extra instructions
> should not affect timing in any significant way.
>
> #define _GNU_SOURCE
> #include <stdio.h>
> #include <sys/types.h>
> #include <sys/mman.h>
> #include <unistd.h>
> #include <sys/syscall.h>
> #include <asm/ldt.h>
>
> int modify_ldt(int func, void *ptr, unsigned long bytecount)
> {
> 	return syscall(SYS_modify_ldt, func, ptr, bytecount);
> }
>
> /* this is assumed to be usable */
> #define SEGBASEADDR 0x10000
> #define SEGLIMIT 0xffff
>
> /* 16-bit segment */
> struct user_desc desc = {
> 	.entry_number = 0,
> 	.base_addr = SEGBASEADDR,
> 	.limit = SEGLIMIT,
> 	.seg_32bit = 0,
> 	.contents = 0, /* ??? */
> 	.read_exec_only = 0,
> 	.limit_in_pages = 0,
> 	.seg_not_present = 0,
> 	.useable = 1
> };
>
> int main(void)
> {
> 	setvbuf(stdout, NULL, _IONBF, 0);
>
> 	/* map a 64 kb segment */
> 	char *pointer = mmap((void *)SEGBASEADDR, SEGLIMIT+1,
>                         PROT_EXEC|PROT_READ|PROT_WRITE,
>                         MAP_SHARED|MAP_ANONYMOUS, -1, 0);
> 	if (pointer == NULL) {
> 		printf("could not map space\n");
> 		return 0;
> 	}
>
> 	/* write ldt, new mode */
> 	int err = modify_ldt(0x11, &desc, sizeof(desc));
> 	if (err) {
> 		printf("error modifying ldt: %i\n", err);
> 		return 0;
> 	}
>
> 	for (int i=0; i<1000; i++) {
> 	asm volatile (
> 		"pusha\n\t"
> 		"mov %ss, %eax\n\t" /* preserve ss:esp */
> 		"mov %esp, %ebp\n\t"
> 		"push $7\n\t" /* index 0, ldt, user mode */
> 		"push $61440\n\t" /* esp */
> 		"lss (%esp), %esp\n\t" /* switch to new stack */
> 		"push %eax\n\t" /* save old ss:esp on new stack */
> 		"push %ebp\n\t"
>
> 		"mov %esp, %edx\n\t"
>
> 		/* wait a bit */
> 		"mov $10000000, %ecx\n\t"
> 		"1: loop 1b\n\t"
>
> 		"cmp %esp, %edx\n\t"
> 		"je 1f\n\t"
> 		"ud2\n\t" /* esp changed inexplicably! */
> 		"1:\n\t"
> 		"lss (%esp), %esp\n\t" /* restore old ss:esp */
> 		"popa\n\t");
>
> 		printf("\rx%ix", i);
> 	}
>
> 	return 0;
> }
>
> The bug is present in 2.6.28, and probably even much earlier.
>
> Signed-off-by: Alexander van Heukelum <heukelum@fastmail.fm>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Cyrill Gorcunov <gorcunov@gmail.com>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: The stable team <stable@kernel.org>
>
> ---
>
> Hi Ingo, Peter, Cyrill, ...
>
> Mucking with entry_32.S and trying to exercise all code paths, I found
> the problem described above. Please check this patch carefully for side
> effects I may have overlooked!
>
> Greetings,
> 	Alexander
>

Really good catch, Alexander!

At least at moment I can't imagine more simple/cleaner solution.
I've added Andi and Thomas to CC list as well. Just to be sure...

	-- Cyrill

      reply	other threads:[~2009-05-26 14:15 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-24 18:24 Alexander van Heukelum
2009-05-26 14:15 ` Cyrill Gorcunov [this message]

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=20090526141517.GA5068@lenovo \
    --to=gorcunov@gmail.com \
    --cc=alexander@mail.messagingengine.com \
    --cc=andi@firstfloor.org \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=stable@kernel.org \
    --cc=tglx@linutronix.de \
    /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

all inboxes | Powered by JetHome®