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;