Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 4122

kernel-2.6.18-194.11.1.el5.src.rpm

From: Larry Woodman <lwoodman@redhat.com>
Date: Wed, 23 Jul 2008 13:30:10 -0400
Subject: [x86_64] ia32: increase stack size
Message-id: 1216834210.13996.22.camel@localhost.localdomain
O-Subject: [RHEL5-U3 patch] Prevent SEGFLT in gethostbyname() when application is compiled as 32-bits.
Bugzilla: 442331
RH-Acked-by: Rik van Riel <riel@redhat.com>

In RHEL5 a 32-bit application that starts out as root, calls
mlockall(MCL_CURRENT), does a setuid() to user then calls
gethostbyname() segfaults with a bad user stack.  This works fine
upstream(since 2.6.23).

The cause of the RHEL5 failure is ia32_setup_arg_pages() creates a 2
page user stack directly by assigning the stack's vma->vm_start and
vma->vm_end.  When the 32-bit process is mlock()'d only 2 stack pages
get wired/locked and the vma gets marked VM_LOCKED so when a dynamic
stack extention occurs after the setuid() it fails because the process
is over the max locked memory(only 32KB) and a SEGFLT occurs.

The 32-bit application works on the upstream kernel because that version
of ia32_setup_arg_pages() calls the generic setup_arg_pages() which
creates a 21 page user stack so the dynamic stack extension never
happens.  The upstream change occurred in 2.6.23 as part of combining
the i386 and x86_64 architectures into a common x86 arch and
distinguishing the two code paths with "#ifdef CONFIG_X86_64".

Since back-porting that whole mess into RHEL5 is far too complicated and
risky the attached patch fixes this problem by simply allocating a
larger stack(21 pages) in ia32_setup_arg_pages() just like
setup_arg_pages() does upstream.  All of the gory details are in BZ
442331.

Fixes BZ 442331.

diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index b7695d8..8197ed8 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -286,6 +286,8 @@ static void elf32_init(struct pt_regs *regs)
 	me->thread.es = __USER_DS;
 }
 
+#define EXTRA_STACK_VM_PAGES    20      /* random */
+
 int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top,
 			 int executable_stack)
 {
@@ -312,6 +314,7 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top,
 	{
 		mpnt->vm_mm = mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
+		mpnt->vm_start -= EXTRA_STACK_VM_PAGES * PAGE_SIZE;
 		mpnt->vm_end = stack_top;
 		if (executable_stack == EXSTACK_ENABLE_X)
 			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;