linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/3] no MAX_ARG_PAGES -v2
@ 2007-06-13 10:03 Peter Zijlstra
  2007-06-13 10:03 ` [patch 1/3] arch: personality independent stack top Peter Zijlstra
                   ` (4 more replies)
  0 siblings, 5 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-13 10:03 UTC (permalink / raw)
  To: linux-kernel, parisc-linux, linux-mm, linux-arch
  Cc: Ollie Wild, Peter Zijlstra, Andrew Morton, Ingo Molnar, Andi Kleen


This patch-set aims at removing the current limit on argv+env space aka.
MAX_ARG_PAGES.

The new mm is created before the binfmt code runs, the stack is placed at the
highest address supported by that architecture.

The argv+env data is then copied from the old mm into the new mm (which is
inactive at that time - this introduces some cache coherency issues).

Then we run the binfmt code, which will compute the final stack address. The
existing stack will be moved downwards (or upwards on PA-RISC) to the desired
place.

This 'trick' heavily relies on the MMU, so for no-MMU archs we stay with the
old approach.

---

Plenty of changes all around, changes listed in the individual patches. We hope
to have addressed all issues raised.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [patch 1/3] arch: personality independent stack top
  2007-06-13 10:03 [patch 0/3] no MAX_ARG_PAGES -v2 Peter Zijlstra
@ 2007-06-13 10:03 ` Peter Zijlstra
  2007-06-13 10:03 ` [patch 2/3] audit: rework execve audit Peter Zijlstra
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-13 10:03 UTC (permalink / raw)
  To: linux-kernel, parisc-linux, linux-mm, linux-arch
  Cc: Ollie Wild, Peter Zijlstra, Andrew Morton, Ingo Molnar, Andi Kleen

[-- Attachment #1: stack_top_max.patch --]
[-- Type: text/plain, Size: 11425 bytes --]

New arch macro STACK_TOP_MAX it gives the larges valid stack address for
the architecture in question.

It differs from STACK_TOP in that it will not distinguish between personalities
but will always return the largest possible address.

This is used to create the initial stack on execve, which we will move down
to the proper location once the binfmt code has figured out where that is.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ollie Wild <aaw@google.com>
---
Changes
 - small fix to UML

 include/asm-alpha/a.out.h    |    2 ++
 include/asm-arm/a.out.h      |    1 +
 include/asm-arm26/a.out.h    |    1 +
 include/asm-avr32/a.out.h    |    1 +
 include/asm-cris/a.out.h     |    1 +
 include/asm-frv/mem-layout.h |    1 +
 include/asm-h8300/a.out.h    |    1 +
 include/asm-i386/a.out.h     |    1 +
 include/asm-ia64/ustack.h    |    1 +
 include/asm-m32r/a.out.h     |    1 +
 include/asm-m68k/a.out.h     |    1 +
 include/asm-mips/a.out.h     |    1 +
 include/asm-parisc/a.out.h   |    1 +
 include/asm-powerpc/a.out.h  |    3 +++
 include/asm-s390/a.out.h     |    1 +
 include/asm-sh/a.out.h       |    1 +
 include/asm-sh64/a.out.h     |    1 +
 include/asm-sparc/a.out.h    |    1 +
 include/asm-sparc64/a.out.h  |    2 ++
 include/asm-um/a.out.h       |    3 +++
 include/asm-x86_64/a.out.h   |    3 ++-
 include/asm-xtensa/a.out.h   |    1 +
 22 files changed, 29 insertions(+), 1 deletion(-)

Index: linux-2.6-2/include/asm-alpha/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-alpha/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-alpha/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -101,6 +101,8 @@ struct exec
 #define STACK_TOP \
   (current->personality & ADDR_LIMIT_32BIT ? 0x80000000 : 0x00120000000UL)
 
+#define STACK_TOP_MAX	0x00120000000UL
+
 #endif
 
 #endif /* __A_OUT_GNU_H__ */
Index: linux-2.6-2/include/asm-arm/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-arm/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-arm/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -30,6 +30,7 @@ struct exec
 #ifdef __KERNEL__
 #define STACK_TOP	((current->personality == PER_LINUX_32BIT) ? \
 			 TASK_SIZE : TASK_SIZE_26)
+#define STACK_TOP_MAX	TASK_SIZE
 #endif
 
 #ifndef LIBRARY_START_TEXT
Index: linux-2.6-2/include/asm-arm26/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-arm26/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-arm26/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -29,6 +29,7 @@ struct exec
 
 #ifdef __KERNEL__
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 #endif
 
 #ifndef LIBRARY_START_TEXT
Index: linux-2.6-2/include/asm-avr32/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-avr32/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-avr32/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-cris/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-cris/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-cris/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -8,6 +8,7 @@
 
 /* grabbed from the intel stuff  */   
 #define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 
 struct exec
Index: linux-2.6-2/include/asm-frv/mem-layout.h
===================================================================
--- linux-2.6-2.orig/include/asm-frv/mem-layout.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-frv/mem-layout.h	2007-06-08 11:49:53.000000000 +0200
@@ -60,6 +60,7 @@
  */
 #define BRK_BASE			__UL(2 * 1024 * 1024 + PAGE_SIZE)
 #define STACK_TOP			__UL(2 * 1024 * 1024)
+#define STACK_TOP_MAX	STACK_TOP
 
 /* userspace process size */
 #ifdef CONFIG_MMU
Index: linux-2.6-2/include/asm-h8300/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-h8300/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-h8300/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-i386/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-i386/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-i386/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-ia64/ustack.h
===================================================================
--- linux-2.6-2.orig/include/asm-ia64/ustack.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-ia64/ustack.h	2007-06-08 11:49:53.000000000 +0200
@@ -11,6 +11,7 @@
 /* The absolute hard limit for stack size is 1/2 of the mappable space in the region */
 #define MAX_USER_STACK_SIZE	(RGN_MAP_LIMIT/2)
 #define STACK_TOP		(0x6000000000000000UL + RGN_MAP_LIMIT)
+#define STACK_TOP_MAX		STACK_TOP
 #endif
 
 /* Make a default stack size of 2GiB */
Index: linux-2.6-2/include/asm-m32r/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-m32r/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-m32r/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-m68k/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-m68k/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-m68k/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-mips/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-mips/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-mips/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -40,6 +40,7 @@ struct exec
 #ifdef CONFIG_64BIT
 #define STACK_TOP	(current->thread.mflags & MF_32BIT_ADDR ? TASK_SIZE32 : TASK_SIZE)
 #endif
+#define STACK_TOP_MAX	TASK_SIZE
 
 #endif
 
Index: linux-2.6-2/include/asm-parisc/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-parisc/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-parisc/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -23,6 +23,7 @@ struct exec
  * prumpf */
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	DEFAULT_TASK_SIZE
 
 #endif
 
Index: linux-2.6-2/include/asm-powerpc/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-powerpc/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-powerpc/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -26,9 +26,12 @@ struct exec
 #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
 		   STACK_TOP_USER32 : STACK_TOP_USER64)
 
+#define STACK_TOP_MAX STACK_TOP_USER64
+
 #else /* __powerpc64__ */
 
 #define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif /* __powerpc64__ */
 #endif /* __KERNEL__ */
Index: linux-2.6-2/include/asm-s390/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-s390/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-s390/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -32,6 +32,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	DEFAULT_TASK_SIZE
 
 #endif
 
Index: linux-2.6-2/include/asm-sh/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-sh/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-sh/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-sh64/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-sh64/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-sh64/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -31,6 +31,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
Index: linux-2.6-2/include/asm-sparc/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-sparc/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-sparc/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -92,6 +92,7 @@ struct relocation_info /* used when head
 #include <asm/page.h>
 
 #define STACK_TOP	(PAGE_OFFSET - PAGE_SIZE)
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif /* __KERNEL__ */
 
Index: linux-2.6-2/include/asm-sparc64/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-sparc64/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-sparc64/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -101,6 +101,8 @@ struct relocation_info /* used when head
 #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
 		   STACK_TOP32 : STACK_TOP64)
 
+#define STACK_TOP_MAX STACK_TOP64
+
 #endif
 
 #endif /* !(__ASSEMBLY__) */
Index: linux-2.6-2/include/asm-um/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-um/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-um/a.out.h	2007-06-12 21:47:51.000000000 +0200
@@ -5,6 +5,7 @@
 #include "choose-mode.h"
 
 #undef STACK_TOP
+#undef STACK_TOP_MAX
 
 extern unsigned long stacksizelim;
 
@@ -16,4 +17,6 @@ extern int honeypot;
 #define STACK_TOP \
 	CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
 
+#define STACK_TOP_MAX	STACK_TOP
+
 #endif
Index: linux-2.6-2/include/asm-x86_64/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-x86_64/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-x86_64/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -21,7 +21,8 @@ struct exec
 
 #ifdef __KERNEL__
 #include <linux/thread_info.h>
-#define STACK_TOP TASK_SIZE
+#define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	TASK_SIZE64
 #endif
 
 #endif /* __A_OUT_GNU_H__ */
Index: linux-2.6-2/include/asm-xtensa/a.out.h
===================================================================
--- linux-2.6-2.orig/include/asm-xtensa/a.out.h	2007-06-08 11:49:52.000000000 +0200
+++ linux-2.6-2/include/asm-xtensa/a.out.h	2007-06-08 11:49:53.000000000 +0200
@@ -17,6 +17,7 @@
 /* Note: the kernel needs the a.out definitions, even if only ELF is used. */
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 struct exec
 {

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [patch 2/3] audit: rework execve audit
  2007-06-13 10:03 [patch 0/3] no MAX_ARG_PAGES -v2 Peter Zijlstra
  2007-06-13 10:03 ` [patch 1/3] arch: personality independent stack top Peter Zijlstra
@ 2007-06-13 10:03 ` Peter Zijlstra
  2007-06-26 22:55   ` Andrew Morton
  2007-06-13 10:03 ` [patch 3/3] mm: variable length argument support Peter Zijlstra
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-13 10:03 UTC (permalink / raw)
  To: linux-kernel, parisc-linux, linux-mm, linux-arch
  Cc: Ollie Wild, Peter Zijlstra, Andrew Morton, Ingo Molnar,
	Andi Kleen, linux-audit

[-- Attachment #1: execve_audit.patch --]
[-- Type: text/plain, Size: 6644 bytes --]

The purpose of audit_bprm() is to log the argv array to a userspace daemon at
the end of the execve system call. Since user-space hasn't had time to run,
this array is still in pristine state on the process' stack; so no need to copy
it, we can just grab it from there.

In order to minimize the damage to audit_log_*() copy each string into a
temporary kernel buffer first.

Currently the audit code requires that the full argument vector fits in a
single packet. So currently it does clip the argv size to a (sysctl) limit, but
only when execve auditing is enabled.

If the audit protocol gets extended to allow for multiple packets this check
can be removed.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ollie Wild <aaw@google.com>
Cc: linux-audit@redhat.com
---

Changes:
 - changed the BUG_ONs to kill current and print a warning.
 - eradicate tmp
 - extra check on strlen

 fs/exec.c               |    3 +
 include/linux/binfmts.h |    1 
 kernel/auditsc.c        |   84 ++++++++++++++++++++++++++++++++++++------------
 kernel/sysctl.c         |   11 ++++++
 4 files changed, 78 insertions(+), 21 deletions(-)

Index: linux-2.6-2/kernel/auditsc.c
===================================================================
--- linux-2.6-2.orig/kernel/auditsc.c	2007-06-08 11:23:23.000000000 +0200
+++ linux-2.6-2/kernel/auditsc.c	2007-06-08 11:49:47.000000000 +0200
@@ -156,7 +156,7 @@ struct audit_aux_data_execve {
 	struct audit_aux_data	d;
 	int argc;
 	int envc;
-	char mem[0];
+	struct mm_struct *mm;
 };
 
 struct audit_aux_data_socketcall {
@@ -834,6 +834,55 @@ static int audit_log_pid_context(struct 
 	return rc;
 }
 
+static void audit_log_execve_info(struct audit_buffer *ab,
+		struct audit_aux_data_execve *axi)
+{
+	int i;
+	long len, ret;
+	const char __user *p = (const char __user *)axi->mm->arg_start;
+	char *buf;
+
+	if (axi->mm != current->mm)
+		return; /* execve failed, no additional info */
+
+	for (i = 0; i < axi->argc; i++, p += len) {
+		len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
+		/*
+		 * We just created this mm, if we can't find the strings
+		 * we just copied into it something is _very_ wrong. Similar
+		 * for strings that are too long, we should not have created
+		 * any.
+		 */
+		if (!len || len > MAX_ARG_STRLEN) {
+			WARN_ON(1);
+			send_sig(SIGKILL, current, 0);
+		}
+
+		buf = kmalloc(len, GFP_KERNEL);
+		if (!buf) {
+			audit_panic("out of memory for argv string\n");
+			break;
+		}
+
+		ret = copy_from_user(buf, p, len);
+		/*
+		 * There is no reason for this copy to be short. We just
+		 * copied them here, and the mm hasn't been exposed to user-
+		 * space yet.
+		 */
+		if (!ret) {
+			WARN_ON(1);
+			send_sig(SIGKILL, current, 0);
+		}
+
+		audit_log_format(ab, "a%d=", i);
+		audit_log_untrustedstring(ab, buf);
+		audit_log_format(ab, "\n");
+
+		kfree(buf);
+	}
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
 	int i, call_panic = 0;
@@ -974,13 +1023,7 @@ static void audit_log_exit(struct audit_
 
 		case AUDIT_EXECVE: {
 			struct audit_aux_data_execve *axi = (void *)aux;
-			int i;
-			const char *p;
-			for (i = 0, p = axi->mem; i < axi->argc; i++) {
-				audit_log_format(ab, "a%d=", i);
-				p = audit_log_untrustedstring(ab, p);
-				audit_log_format(ab, "\n");
-			}
+			audit_log_execve_info(ab, axi);
 			break; }
 
 		case AUDIT_SOCKETCALL: {
@@ -1824,32 +1867,31 @@ int __audit_ipc_set_perm(unsigned long q
 	return 0;
 }
 
+int audit_argv_kb = 32;
+
 int audit_bprm(struct linux_binprm *bprm)
 {
 	struct audit_aux_data_execve *ax;
 	struct audit_context *context = current->audit_context;
-	unsigned long p, next;
-	void *to;
 
 	if (likely(!audit_enabled || !context || context->dummy))
 		return 0;
 
-	ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p,
-				GFP_KERNEL);
+	/*
+	 * Even though the stack code doesn't limit the arg+env size any more,
+	 * the audit code requires that _all_ arguments be logged in a single
+	 * netlink skb. Hence cap it :-(
+	 */
+	if (bprm->argv_len > (audit_argv_kb << 10))
+		return -E2BIG;
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
 	if (!ax)
 		return -ENOMEM;
 
 	ax->argc = bprm->argc;
 	ax->envc = bprm->envc;
-	for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) {
-		struct page *page = bprm->page[p / PAGE_SIZE];
-		void *kaddr = kmap(page);
-		next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1);
-		memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p);
-		to += next - p;
-		kunmap(page);
-	}
-
+	ax->mm = bprm->mm;
 	ax->d.type = AUDIT_EXECVE;
 	ax->d.next = context->aux;
 	context->aux = (void *)ax;
Index: linux-2.6-2/fs/exec.c
===================================================================
--- linux-2.6-2.orig/fs/exec.c	2007-06-08 11:23:23.000000000 +0200
+++ linux-2.6-2/fs/exec.c	2007-06-08 11:49:47.000000000 +0200
@@ -1154,6 +1154,7 @@ int do_execve(char * filename,
 {
 	struct linux_binprm *bprm;
 	struct file *file;
+	unsigned long env_p;
 	int retval;
 	int i;
 
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,
 	if (retval < 0)
 		goto out;
 
+	env_p = bprm->p;
 	retval = copy_strings(bprm->argc, argv, bprm);
 	if (retval < 0)
 		goto out;
+	bprm->argv_len = env_p - bprm->p;
 
 	retval = search_binary_handler(bprm,regs);
 	if (retval >= 0) {
Index: linux-2.6-2/include/linux/binfmts.h
===================================================================
--- linux-2.6-2.orig/include/linux/binfmts.h	2007-06-08 11:23:23.000000000 +0200
+++ linux-2.6-2/include/linux/binfmts.h	2007-06-08 11:49:47.000000000 +0200
@@ -40,6 +40,7 @@ struct linux_binprm{
 	unsigned interp_flags;
 	unsigned interp_data;
 	unsigned long loader, exec;
+	unsigned long argv_len;
 };
 
 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
Index: linux-2.6-2/kernel/sysctl.c
===================================================================
--- linux-2.6-2.orig/kernel/sysctl.c	2007-06-08 11:23:23.000000000 +0200
+++ linux-2.6-2/kernel/sysctl.c	2007-06-08 11:23:25.000000000 +0200
@@ -81,6 +81,7 @@ extern int percpu_pagelist_fraction;
 extern int compat_log;
 extern int maps_protect;
 extern int sysctl_stat_interval;
+extern int audit_argv_kb;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -711,6 +712,16 @@ static ctl_table kern_table[] = {
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+#ifdef CONFIG_AUDITSYSCALL
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "audit_argv_kb",
+		.data		= &audit_argv_kb,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
 
 	{ .ctl_name = 0 }
 };

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [patch 3/3] mm: variable length argument support
  2007-06-13 10:03 [patch 0/3] no MAX_ARG_PAGES -v2 Peter Zijlstra
  2007-06-13 10:03 ` [patch 1/3] arch: personality independent stack top Peter Zijlstra
  2007-06-13 10:03 ` [patch 2/3] audit: rework execve audit Peter Zijlstra
@ 2007-06-13 10:03 ` Peter Zijlstra
  2007-08-07 19:03   ` Olaf Hering
  2007-08-22  8:48   ` Dan Aloni
  2007-06-13 23:36 ` [patch 0/3] no MAX_ARG_PAGES -v2 Luck, Tony
  2007-06-17 18:32 ` Pavel Machek
  4 siblings, 2 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-13 10:03 UTC (permalink / raw)
  To: linux-kernel, parisc-linux, linux-mm, linux-arch
  Cc: Ollie Wild, Peter Zijlstra, Andrew Morton, Ingo Molnar, Andi Kleen

[-- Attachment #1: no_MAX_ARG_PAGES.patch --]
[-- Type: text/plain, Size: 44245 bytes --]

From: Ollie Wild <aaw@google.com>

Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
from the old mm into the new mm.

We create the new mm before the binfmt code runs, and place the new stack
at the very top of the address space. Once the binfmt code runs and figures
out where the stack should be, we move it downwards.

It is a bit peculiar in that we have one task with two mm's, one of which is
inactive.

Signed-off-by: Ollie Wild <aaw@google.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

Changes:
 - reverted the UML changes, those were no longer needed
 - reworked the no-MMU stuff to reduce #ifdef clutter and enhance compilability
 - removed move_page_tables_up() since it turned out to be unused
 - sprinkled comments

 arch/ia64/ia32/binfmt_elf32.c  |   65 +---
 arch/x86_64/ia32/ia32_aout.c   |    2 
 arch/x86_64/ia32/ia32_binfmt.c |   58 ---
 fs/binfmt_elf.c                |   28 +
 fs/binfmt_elf_fdpic.c          |    8 
 fs/binfmt_misc.c               |    4 
 fs/binfmt_script.c             |    4 
 fs/compat.c                    |  128 +++-----
 fs/exec.c                      |  606 +++++++++++++++++++++++++----------------
 include/linux/binfmts.h        |   18 -
 include/linux/mm.h             |    9 
 kernel/auditsc.c               |    2 
 mm/mmap.c                      |   61 ++--
 mm/mprotect.c                  |    2 
 mm/mremap.c                    |    2 
 15 files changed, 541 insertions(+), 456 deletions(-)

Index: linux-2.6-2/arch/x86_64/ia32/ia32_binfmt.c
===================================================================
--- linux-2.6-2.orig/arch/x86_64/ia32/ia32_binfmt.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/arch/x86_64/ia32/ia32_binfmt.c	2007-06-13 11:52:46.000000000 +0200
@@ -233,9 +233,6 @@ do {							\
 #define load_elf_binary load_elf32_binary
 
 #define ELF_PLAT_INIT(r, load_addr)	elf32_init(r)
-#define setup_arg_pages(bprm, stack_top, exec_stack) \
-	ia32_setup_arg_pages(bprm, stack_top, exec_stack)
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack);
 
 #undef start_thread
 #define start_thread(regs,new_rip,new_rsp) do { \
@@ -287,61 +284,6 @@ static void elf32_init(struct pt_regs *r
 	me->thread.es = __USER_DS;
 }
 
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top,
-			 int executable_stack)
-{
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
-	struct mm_struct *mm = current->mm;
-	int i, ret;
-
-	stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE;
-	mm->arg_start = bprm->p + stack_base;
-
-	bprm->p += stack_base;
-	if (bprm->loader)
-		bprm->loader += stack_base;
-	bprm->exec += stack_base;
-
-	mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	if (!mpnt) 
-		return -ENOMEM; 
-
-	down_write(&mm->mmap_sem);
-	{
-		mpnt->vm_mm = mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = stack_top;
-		if (executable_stack == EXSTACK_ENABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-		else if (executable_stack == EXSTACK_DISABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-		else
-			mpnt->vm_flags = VM_STACK_FLAGS;
- 		mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? 
- 			PAGE_COPY_EXEC : PAGE_COPY;
-		if ((ret = insert_vm_struct(mm, mpnt))) {
-			up_write(&mm->mmap_sem);
-			kmem_cache_free(vm_area_cachep, mpnt);
-			return ret;
-		}
-		mm->stack_vm = mm->total_vm = vma_pages(mpnt);
-	} 
-
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page *page = bprm->page[i];
-		if (page) {
-			bprm->page[i] = NULL;
-			install_arg_page(mpnt, page, stack_base);
-		}
-		stack_base += PAGE_SIZE;
-	}
-	up_write(&mm->mmap_sem);
-	
-	return 0;
-}
-EXPORT_SYMBOL(ia32_setup_arg_pages);
-
 #ifdef CONFIG_SYSCTL
 /* Register vsyscall32 into the ABI table */
 #include <linux/sysctl.h>
Index: linux-2.6-2/fs/binfmt_elf.c
===================================================================
--- linux-2.6-2.orig/fs/binfmt_elf.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/fs/binfmt_elf.c	2007-06-13 11:52:46.000000000 +0200
@@ -148,6 +148,7 @@ create_elf_tables(struct linux_binprm *b
 	elf_addr_t *elf_info;
 	int ei_index = 0;
 	struct task_struct *tsk = current;
+	struct vm_area_struct *vma;
 
 	/*
 	 * If this architecture has a platform capability string, copy it
@@ -234,6 +235,15 @@ create_elf_tables(struct linux_binprm *b
 	sp = (elf_addr_t __user *)bprm->p;
 #endif
 
+
+	/*
+	 * Grow the stack manually; some architectures have a limit on how
+	 * far ahead a user-space access may be in order to grow the stack.
+	 */
+	vma = find_extend_vma(current->mm, bprm->p);
+	if (!vma)
+		return -EFAULT;
+
 	/* Now, let's put argc (and argv, envp if appropriate) on the stack */
 	if (__put_user(argc, sp++))
 		return -EFAULT;
@@ -254,8 +264,8 @@ create_elf_tables(struct linux_binprm *b
 		size_t len;
 		if (__put_user((elf_addr_t)p, argv++))
 			return -EFAULT;
-		len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+		len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+		if (!len || len > MAX_ARG_STRLEN)
 			return 0;
 		p += len;
 	}
@@ -266,8 +276,8 @@ create_elf_tables(struct linux_binprm *b
 		size_t len;
 		if (__put_user((elf_addr_t)p, envp++))
 			return -EFAULT;
-		len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+		len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+		if (!len || len > MAX_ARG_STRLEN)
 			return 0;
 		p += len;
 	}
@@ -826,10 +836,6 @@ static int load_elf_binary(struct linux_
 	}
 
 	/* OK, This is the point of no return */
-	current->mm->start_data = 0;
-	current->mm->end_data = 0;
-	current->mm->end_code = 0;
-	current->mm->mmap = NULL;
 	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
 
@@ -1051,9 +1057,13 @@ static int load_elf_binary(struct linux_
 
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
-	create_elf_tables(bprm, &loc->elf_ex,
+	retval = create_elf_tables(bprm, &loc->elf_ex,
 			  (interpreter_type == INTERPRETER_AOUT),
 			  load_addr, interp_load_addr);
+	if (retval < 0) {
+		send_sig(SIGKILL, current, 0);
+		goto out;
+	}
 	/* N.B. passed_fileno might not be initialized? */
 	if (interpreter_type == INTERPRETER_AOUT)
 		current->mm->arg_start += strlen(passed_fileno) + 1;
Index: linux-2.6-2/fs/binfmt_elf_fdpic.c
===================================================================
--- linux-2.6-2.orig/fs/binfmt_elf_fdpic.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/fs/binfmt_elf_fdpic.c	2007-06-13 11:52:46.000000000 +0200
@@ -621,8 +621,8 @@ static int create_elf_fdpic_tables(struc
 	p = (char __user *) current->mm->arg_start;
 	for (loop = bprm->argc; loop > 0; loop--) {
 		__put_user((elf_caddr_t) p, argv++);
-		len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
-		if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
+		len = strnlen_user(p, MAX_ARG_STRLEN);
+		if (!len || len > MAX_ARG_STRLEN)
 			return -EINVAL;
 		p += len;
 	}
@@ -633,8 +633,8 @@ static int create_elf_fdpic_tables(struc
 	current->mm->env_start = (unsigned long) p;
 	for (loop = bprm->envc; loop > 0; loop--) {
 		__put_user((elf_caddr_t)(unsigned long) p, envp++);
-		len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
-		if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
+		len = strnlen_user(p, MAX_ARG_STRLEN);
+		if (!len || len > MAX_ARG_STRLEN)
 			return -EINVAL;
 		p += len;
 	}
Index: linux-2.6-2/fs/binfmt_misc.c
===================================================================
--- linux-2.6-2.orig/fs/binfmt_misc.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/fs/binfmt_misc.c	2007-06-13 11:52:46.000000000 +0200
@@ -126,7 +126,9 @@ static int load_misc_binary(struct linux
 		goto _ret;
 
 	if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
-		remove_arg_zero(bprm);
+		retval = remove_arg_zero(bprm);
+		if (retval)
+			goto _ret;
 	}
 
 	if (fmt->flags & MISC_FMT_OPEN_BINARY) {
Index: linux-2.6-2/fs/binfmt_script.c
===================================================================
--- linux-2.6-2.orig/fs/binfmt_script.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/fs/binfmt_script.c	2007-06-13 11:52:46.000000000 +0200
@@ -67,7 +67,9 @@ static int load_script(struct linux_binp
 	 * This is done in reverse order, because of how the
 	 * user environment and arguments are stored.
 	 */
-	remove_arg_zero(bprm);
+	retval = remove_arg_zero(bprm);
+	if (retval)
+		return retval;
 	retval = copy_strings_kernel(1, &bprm->interp, bprm);
 	if (retval < 0) return retval; 
 	bprm->argc++;
Index: linux-2.6-2/fs/compat.c
===================================================================
--- linux-2.6-2.orig/fs/compat.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/fs/compat.c	2007-06-13 11:52:46.000000000 +0200
@@ -1257,6 +1257,7 @@ static int compat_copy_strings(int argc,
 {
 	struct page *kmapped_page = NULL;
 	char *kaddr = NULL;
+	unsigned long kpos = 0;
 	int ret;
 
 	while (argc-- > 0) {
@@ -1265,92 +1266,84 @@ static int compat_copy_strings(int argc,
 		unsigned long pos;
 
 		if (get_user(str, argv+argc) ||
-			!(len = strnlen_user(compat_ptr(str), bprm->p))) {
+		    !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
 			ret = -EFAULT;
 			goto out;
 		}
 
-		if (bprm->p < len)  {
+		if (len > MAX_ARG_STRLEN) {
 			ret = -E2BIG;
 			goto out;
 		}
 
-		bprm->p -= len;
-		/* XXX: add architecture specific overflow check here. */
+		/* We're going to work our way backwords. */
 		pos = bprm->p;
+		str += len;
+		bprm->p -= len;
 
 		while (len > 0) {
-			int i, new, err;
 			int offset, bytes_to_copy;
-			struct page *page;
 
 			offset = pos % PAGE_SIZE;
-			i = pos/PAGE_SIZE;
-			page = bprm->page[i];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_HIGHUSER);
-				bprm->page[i] = page;
-				if (!page) {
-					ret = -ENOMEM;
+			if (offset == 0)
+				offset = PAGE_SIZE;
+
+			bytes_to_copy = offset;
+			if (bytes_to_copy > len)
+				bytes_to_copy = len;
+
+			offset -= bytes_to_copy;
+			pos -= bytes_to_copy;
+			str -= bytes_to_copy;
+			len -= bytes_to_copy;
+
+			if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+				struct page *page;
+
+#ifdef CONFIG_STACK_GROWSUP
+				ret = expand_stack_downwards(bprm->vma, pos);
+				if (ret < 0) {
+					/* We've exceed the stack rlimit. */
+					ret = -E2BIG;
+					goto out;
+				}
+#endif
+				ret = get_user_pages(current, bprm->mm, pos,
+						     1, 1, 1, &page, NULL);
+				if (ret <= 0) {
+					/* We've exceed the stack rlimit. */
+					ret = -E2BIG;
 					goto out;
 				}
-				new = 1;
-			}
 
-			if (page != kmapped_page) {
-				if (kmapped_page)
+				if (kmapped_page) {
+					flush_kernel_dcache_page(kmapped_page);
 					kunmap(kmapped_page);
+					put_page(kmapped_page);
+				}
 				kmapped_page = page;
 				kaddr = kmap(kmapped_page);
+				kpos = pos & PAGE_MASK;
+				flush_cache_page(bprm->vma, kpos,
+						 page_to_pfn(kmapped_page));
 			}
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0,
-						PAGE_SIZE-offset-len);
-			}
-			err = copy_from_user(kaddr+offset, compat_ptr(str),
-						bytes_to_copy);
-			if (err) {
+			if (copy_from_user(kaddr+offset, compat_ptr(str),
+						bytes_to_copy)) {
 				ret = -EFAULT;
 				goto out;
 			}
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
 		}
 	}
 	ret = 0;
 out:
-	if (kmapped_page)
+	if (kmapped_page) {
+		flush_kernel_dcache_page(kmapped_page);
 		kunmap(kmapped_page);
-	return ret;
-}
-
-#ifdef CONFIG_MMU
-
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
-	int i;
-
-	for (i = 0; i < MAX_ARG_PAGES; i++) {
-		if (bprm->page[i])
-			__free_page(bprm->page[i]);
-		bprm->page[i] = NULL;
+		put_page(kmapped_page);
 	}
+	return ret;
 }
 
-#endif /* CONFIG_MMU */
-
 /*
  * compat_do_execve() is mostly a copy of do_execve(), with the exception
  * that it processes 32 bit argv and envp pointers.
@@ -1363,7 +1356,6 @@ int compat_do_execve(char * filename,
 	struct linux_binprm *bprm;
 	struct file *file;
 	int retval;
-	int i;
 
 	retval = -ENOMEM;
 	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1377,24 +1369,19 @@ int compat_do_execve(char * filename,
 
 	sched_exec();
 
-	bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 	bprm->file = file;
 	bprm->filename = filename;
 	bprm->interp = filename;
-	bprm->mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm->mm)
-		goto out_file;
 
-	retval = init_new_context(current, bprm->mm);
-	if (retval < 0)
-		goto out_mm;
+	retval = bprm_mm_init(bprm);
+	if (retval)
+		goto out_file;
 
-	bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t));
+	bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
 	if ((retval = bprm->argc) < 0)
 		goto out_mm;
 
-	bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t));
+	bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
 	if ((retval = bprm->envc) < 0)
 		goto out_mm;
 
@@ -1421,8 +1408,6 @@ int compat_do_execve(char * filename,
 
 	retval = search_binary_handler(bprm, regs);
 	if (retval >= 0) {
-		free_arg_pages(bprm);
-
 		/* execve success */
 		security_bprm_free(bprm);
 		acct_update_integrals(current);
@@ -1431,19 +1416,12 @@ int compat_do_execve(char * filename,
 	}
 
 out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page * page = bprm->page[i];
-		if (page)
-			__free_page(page);
-	}
-
 	if (bprm->security)
 		security_bprm_free(bprm);
 
 out_mm:
 	if (bprm->mm)
-		mmdrop(bprm->mm);
+		mmput(bprm->mm);
 
 out_file:
 	if (bprm->file) {
Index: linux-2.6-2/fs/exec.c
===================================================================
--- linux-2.6-2.orig/fs/exec.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/fs/exec.c	2007-06-13 11:52:46.000000000 +0200
@@ -54,6 +54,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -178,6 +179,191 @@ exit:
 	goto out;
 }
 
+#ifdef CONFIG_MMU
+
+static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+		int write)
+{
+	struct page *page;
+	int ret;
+
+#ifdef CONFIG_STACK_GROWSUP
+	if (write) {
+		ret = expand_stack_downwards(bprm->vma, pos);
+		if (ret < 0)
+			return NULL;
+	}
+#endif
+	ret = get_user_pages(current, bprm->mm, pos,
+			1, write, 1, &page, NULL);
+	if (ret <= 0)
+		return NULL;
+
+	return page;
+}
+
+static void put_arg_page(struct page *page)
+{
+	put_page(page);
+}
+
+static void free_arg_page(struct linux_binprm *bprm, int i)
+{
+}
+
+static void free_arg_pages(struct linux_binprm *bprm)
+{
+}
+
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+		struct page *page)
+{
+	flush_cache_page(bprm->vma, pos, page_to_pfn(page));
+}
+
+static int __bprm_mm_init(struct linux_binprm *bprm)
+{
+	int err = -ENOMEM;
+	struct vm_area_struct *vma = NULL;
+	struct mm_struct *mm = bprm->mm;
+
+	bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+	if (!vma)
+		goto err;
+
+	down_write(&mm->mmap_sem);
+	vma->vm_mm = mm;
+
+	/*
+	 * Place the stack at the largest stack address the architecture
+	 * supports. Later, we'll move this to an appropriate place. We don't
+	 * use STACK_TOP because that can depend on attributes which aren't
+	 * configured yet.
+	 */
+	vma->vm_end = STACK_TOP_MAX;
+	vma->vm_start = vma->vm_end - PAGE_SIZE;
+
+	vma->vm_flags = VM_STACK_FLAGS;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
+	err = insert_vm_struct(mm, vma);
+	if (err) {
+		up_write(&mm->mmap_sem);
+		goto err;
+	}
+
+	mm->stack_vm = mm->total_vm = 1;
+	up_write(&mm->mmap_sem);
+
+	bprm->p = vma->vm_end - sizeof(void *);
+
+	return 0;
+
+err:
+	if (vma) {
+		bprm->vma = NULL;
+		kmem_cache_free(vm_area_cachep, vma);
+	}
+
+	return err;
+}
+
+static bool valid_arg_len(struct linux_binprm *bprm, long len)
+{
+	return len <= MAX_ARG_STRLEN;
+}
+
+#else
+
+static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+		int write)
+{
+	struct page *page;
+
+	page = bprm->page[pos / PAGE_SIZE];
+	if (!page && write) {
+		page = alloc_page(GFP_HIGHUSER|__GFP_ZERO);
+		if (!page)
+			return NULL;
+		bprm->page[pos / PAGE_SIZE] = page;
+	}
+
+	return page;
+}
+
+static void put_arg_page(struct page *page)
+{
+}
+
+static void free_arg_page(struct linux_binprm *bprm, int i)
+{
+	if (bprm->page[i]) {
+		__free_page(bprm->page[i]);
+		bprm->page[i] = NULL;
+	}
+}
+
+static void free_arg_pages(struct linux_binprm *bprm)
+{
+	int i;
+
+	for (i = 0; i < MAX_ARG_PAGES; i++)
+		free_arg_page(bprm, i);
+}
+
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+		struct page *page)
+{
+}
+
+static int __bprm_mm_init(struct linux_binprm *bprm)
+{
+	bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *);
+	return 0;
+}
+
+static bool valid_arg_len(struct linux_binprm *bprm, long len)
+{
+	return len <= bprm->p;
+}
+
+#endif /* CONFIG_MMU */
+
+/*
+ * Create a new mm_struct and populate it with a temporary stack
+ * vm_area_struct.  We don't have enough context at this point to set the stack
+ * flags, permissions, and offset, so we use temporary values.  We'll update
+ * them later in setup_arg_pages().
+ */
+int bprm_mm_init(struct linux_binprm *bprm)
+{
+	int err;
+	struct mm_struct *mm = NULL;
+
+	bprm->mm = mm = mm_alloc();
+	err = -ENOMEM;
+	if (!mm)
+		goto err;
+
+	err = init_new_context(current, mm);
+	if (err)
+		goto err;
+
+	err = __bprm_mm_init(bprm);
+	if (err)
+		goto err;
+
+	return 0;
+
+err:
+	if (mm) {
+		bprm->mm = NULL;
+		mmdrop(mm);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(bprm_mm_init);
+
 /*
  * count() counts the number of strings in array ARGV.
  */
@@ -203,15 +389,16 @@ static int count(char __user * __user * 
 }
 
 /*
- * 'copy_strings()' copies argument/environment strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
+ * 'copy_strings()' copies argument/environment strings from the old
+ * processes's memory to the new process's stack.  The call to get_user_pages()
+ * ensures the destination page is created and not swapped out.
  */
 static int copy_strings(int argc, char __user * __user * argv,
 			struct linux_binprm *bprm)
 {
 	struct page *kmapped_page = NULL;
 	char *kaddr = NULL;
+	unsigned long kpos = 0;
 	int ret;
 
 	while (argc-- > 0) {
@@ -220,69 +407,69 @@ static int copy_strings(int argc, char _
 		unsigned long pos;
 
 		if (get_user(str, argv+argc) ||
-				!(len = strnlen_user(str, bprm->p))) {
+				!(len = strnlen_user(str, MAX_ARG_STRLEN))) {
 			ret = -EFAULT;
 			goto out;
 		}
 
-		if (bprm->p < len)  {
+		if (!valid_arg_len(bprm, len)) {
 			ret = -E2BIG;
 			goto out;
 		}
 
-		bprm->p -= len;
-		/* XXX: add architecture specific overflow check here. */
+		/* We're going to work our way backwords. */
 		pos = bprm->p;
+		str += len;
+		bprm->p -= len;
 
 		while (len > 0) {
-			int i, new, err;
 			int offset, bytes_to_copy;
-			struct page *page;
 
 			offset = pos % PAGE_SIZE;
-			i = pos/PAGE_SIZE;
-			page = bprm->page[i];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_HIGHUSER);
-				bprm->page[i] = page;
+			if (offset == 0)
+				offset = PAGE_SIZE;
+
+			bytes_to_copy = offset;
+			if (bytes_to_copy > len)
+				bytes_to_copy = len;
+
+			offset -= bytes_to_copy;
+			pos -= bytes_to_copy;
+			str -= bytes_to_copy;
+			len -= bytes_to_copy;
+
+			if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+				struct page *page;
+
+				page = get_arg_page(bprm, pos, 1);
 				if (!page) {
-					ret = -ENOMEM;
+					ret = -E2BIG;
 					goto out;
 				}
-				new = 1;
-			}
 
-			if (page != kmapped_page) {
-				if (kmapped_page)
+				if (kmapped_page) {
+					flush_kernel_dcache_page(kmapped_page);
 					kunmap(kmapped_page);
+					put_arg_page(kmapped_page);
+				}
 				kmapped_page = page;
 				kaddr = kmap(kmapped_page);
+				kpos = pos & PAGE_MASK;
+				flush_arg_page(bprm, kpos, kmapped_page);
 			}
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0,
-						PAGE_SIZE-offset-len);
-			}
-			err = copy_from_user(kaddr+offset, str, bytes_to_copy);
-			if (err) {
+			if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
 				ret = -EFAULT;
 				goto out;
 			}
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
 		}
 	}
 	ret = 0;
 out:
-	if (kmapped_page)
+	if (kmapped_page) {
+		flush_kernel_dcache_page(kmapped_page);
 		kunmap(kmapped_page);
+		put_arg_page(kmapped_page);
+	}
 	return ret;
 }
 
@@ -298,181 +485,172 @@ int copy_strings_kernel(int argc,char **
 	set_fs(oldfs);
 	return r;
 }
-
 EXPORT_SYMBOL(copy_strings_kernel);
 
 #ifdef CONFIG_MMU
+
 /*
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
+ * During bprm_mm_init(), we create a temporary stack at STACK_TOP_MAX.  Once
+ * the binfmt code determines where the new stack should reside, we shift it to
+ * its final location.  The process proceeds as follows:
  *
- * vma->vm_mm->mmap_sem is held for writing.
+ * 1) Use shift to calculate the new vma endpoints.
+ * 2) Extend vma to cover both the old and new ranges.  This ensures the
+ *    arguments passed to subsequent functions are consistent.
+ * 3) Move vma's page tables to the new range.
+ * 4) Free up any cleared pgd range.
+ * 5) Shrink the vma to cover only the new range.
  */
-void install_arg_page(struct vm_area_struct *vma,
-			struct page *page, unsigned long address)
+static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	pte_t * pte;
-	spinlock_t *ptl;
+	unsigned long old_start = vma->vm_start;
+	unsigned long old_end = vma->vm_end;
+	unsigned long length = old_end - old_start;
+	unsigned long new_start = old_start - shift;
+	unsigned long new_end = old_end - shift;
+	struct mmu_gather *tlb;
 
-	if (unlikely(anon_vma_prepare(vma)))
-		goto out;
+	BUG_ON(new_start > new_end);
 
-	flush_dcache_page(page);
-	pte = get_locked_pte(mm, address, &ptl);
-	if (!pte)
-		goto out;
-	if (!pte_none(*pte)) {
-		pte_unmap_unlock(pte, ptl);
-		goto out;
+	/*
+	 * ensure there are no vmas between where we want to go
+	 * and where we are
+	 */
+	if (vma != find_vma(mm, new_start))
+		return -EFAULT;
+
+	/*
+	 * cover the whole range: [new_start, old_end)
+	 */
+	vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL);
+
+	/*
+	 * move the page tables downwards, on failure we rely on
+	 * process cleanup to remove whatever mess we made.
+	 */
+	if (length != move_page_tables(vma, old_start,
+				       vma, new_start, length))
+		return -ENOMEM;
+
+	lru_add_drain();
+	tlb = tlb_gather_mmu(mm, 0);
+	if (new_end > old_start) {
+		/*
+		 * when the old and new regions overlap clear from new_end.
+		 */
+		free_pgd_range(&tlb, new_end, old_end, new_end,
+			vma->vm_next ? vma->vm_next->vm_start : 0);
+	} else {
+		/*
+		 * otherwise, clean from old_start; this is done to not touch
+		 * the address space in [new_end, old_start) some architectures
+		 * have constraints on va-space that make this illegal (IA64) -
+		 * for the others its just a little faster.
+		 */
+		free_pgd_range(&tlb, old_start, old_end, new_end,
+			vma->vm_next ? vma->vm_next->vm_start : 0);
 	}
-	inc_mm_counter(mm, anon_rss);
-	lru_cache_add_active(page);
-	set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte(
-					page, vma->vm_page_prot))));
-	page_add_new_anon_rmap(page, vma, address);
-	pte_unmap_unlock(pte, ptl);
+	tlb_finish_mmu(tlb, new_end, old_end);
 
-	/* no need for flush_tlb */
-	return;
-out:
-	__free_page(page);
-	force_sig(SIGKILL, current);
+	/*
+	 * shrink the vma to just the new range.
+	 */
+	vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL);
+
+	return 0;
 }
 
 #define EXTRA_STACK_VM_PAGES	20	/* random */
 
+/*
+ * Finalizes the stack vm_area_struct. The flags and permissions are updated,
+ * the stack is optionally relocated, and some extra space is added.
+ */
 int setup_arg_pages(struct linux_binprm *bprm,
 		    unsigned long stack_top,
 		    int executable_stack)
 {
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
+	unsigned long ret;
+	unsigned long stack_shift;
 	struct mm_struct *mm = current->mm;
-	int i, ret;
-	long arg_size;
+	struct vm_area_struct *vma = bprm->vma;
+	struct vm_area_struct *prev = NULL;
+	unsigned long vm_flags;
+	unsigned long stack_base;
 
 #ifdef CONFIG_STACK_GROWSUP
-	/* Move the argument and environment strings to the bottom of the
-	 * stack space.
-	 */
-	int offset, j;
-	char *to, *from;
-
-	/* Start by shifting all the pages down */
-	i = 0;
-	for (j = 0; j < MAX_ARG_PAGES; j++) {
-		struct page *page = bprm->page[j];
-		if (!page)
-			continue;
-		bprm->page[i++] = page;
-	}
-
-	/* Now move them within their pages */
-	offset = bprm->p % PAGE_SIZE;
-	to = kmap(bprm->page[0]);
-	for (j = 1; j < i; j++) {
-		memmove(to, to + offset, PAGE_SIZE - offset);
-		from = kmap(bprm->page[j]);
-		memcpy(to + PAGE_SIZE - offset, from, offset);
-		kunmap(bprm->page[j - 1]);
-		to = from;
-	}
-	memmove(to, to + offset, PAGE_SIZE - offset);
-	kunmap(bprm->page[j - 1]);
-
 	/* Limit stack size to 1GB */
 	stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max;
 	if (stack_base > (1 << 30))
 		stack_base = 1 << 30;
-	stack_base = PAGE_ALIGN(stack_top - stack_base);
 
-	/* Adjust bprm->p to point to the end of the strings. */
-	bprm->p = stack_base + PAGE_SIZE * i - offset;
+	/* Make sure we didn't let the argument array grow too large. */
+	if (vma->vm_end - vma->vm_start > stack_base)
+		return -ENOMEM;
 
-	mm->arg_start = stack_base;
-	arg_size = i << PAGE_SHIFT;
+	stack_base = PAGE_ALIGN(stack_top - stack_base);
 
-	/* zero pages that were copied above */
-	while (i < MAX_ARG_PAGES)
-		bprm->page[i++] = NULL;
+	stack_shift = vma->vm_start - stack_base;
+	mm->arg_start = bprm->p - stack_shift;
+	bprm->p = vma->vm_end - stack_shift;
 #else
-	stack_base = arch_align_stack(stack_top - MAX_ARG_PAGES*PAGE_SIZE);
-	stack_base = PAGE_ALIGN(stack_base);
-	bprm->p += stack_base;
+	stack_top = arch_align_stack(stack_top);
+	stack_top = PAGE_ALIGN(stack_top);
+	stack_shift = vma->vm_end - stack_top;
+
+	bprm->p -= stack_shift;
 	mm->arg_start = bprm->p;
-	arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start);
 #endif
 
-	arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE;
-
 	if (bprm->loader)
-		bprm->loader += stack_base;
-	bprm->exec += stack_base;
-
-	mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	if (!mpnt)
-		return -ENOMEM;
+		bprm->loader -= stack_shift;
+	bprm->exec -= stack_shift;
 
 	down_write(&mm->mmap_sem);
-	{
-		mpnt->vm_mm = mm;
-#ifdef CONFIG_STACK_GROWSUP
-		mpnt->vm_start = stack_base;
-		mpnt->vm_end = stack_base + arg_size;
-#else
-		mpnt->vm_end = stack_top;
-		mpnt->vm_start = mpnt->vm_end - arg_size;
-#endif
-		/* Adjust stack execute permissions; explicitly enable
-		 * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X
-		 * and leave alone (arch default) otherwise. */
-		if (unlikely(executable_stack == EXSTACK_ENABLE_X))
-			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-		else if (executable_stack == EXSTACK_DISABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-		else
-			mpnt->vm_flags = VM_STACK_FLAGS;
-		mpnt->vm_flags |= mm->def_flags;
-		mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7];
-		if ((ret = insert_vm_struct(mm, mpnt))) {
+	vm_flags = vma->vm_flags;
+
+	/*
+	 * Adjust stack execute permissions; explicitly enable for
+	 * EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X and leave alone
+	 * (arch default) otherwise.
+	 */
+	if (unlikely(executable_stack == EXSTACK_ENABLE_X))
+		vm_flags |= VM_EXEC;
+	else if (executable_stack == EXSTACK_DISABLE_X)
+		vm_flags &= ~VM_EXEC;
+	vm_flags |= mm->def_flags;
+
+	ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
+			vm_flags);
+	if (ret)
+		goto out_unlock;
+	BUG_ON(prev != vma);
+
+	/* Move stack pages down in memory. */
+	if (stack_shift) {
+		ret = shift_arg_pages(vma, stack_shift);
+		if (ret) {
 			up_write(&mm->mmap_sem);
-			kmem_cache_free(vm_area_cachep, mpnt);
 			return ret;
 		}
-		mm->stack_vm = mm->total_vm = vma_pages(mpnt);
 	}
 
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page *page = bprm->page[i];
-		if (page) {
-			bprm->page[i] = NULL;
-			install_arg_page(mpnt, page, stack_base);
-		}
-		stack_base += PAGE_SIZE;
-	}
+#ifdef CONFIG_STACK_GROWSUP
+	stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+#else
+	stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+#endif
+	ret = expand_stack(vma, stack_base);
+	if (ret)
+		ret = -EFAULT;
+
+out_unlock:
 	up_write(&mm->mmap_sem);
-	
 	return 0;
 }
-
 EXPORT_SYMBOL(setup_arg_pages);
 
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
-	int i;
-
-	for (i = 0; i < MAX_ARG_PAGES; i++) {
-		if (bprm->page[i])
-			__free_page(bprm->page[i]);
-		bprm->page[i] = NULL;
-	}
-}
-
 #endif /* CONFIG_MMU */
 
 struct file *open_exec(const char *name)
@@ -1000,43 +1178,42 @@ EXPORT_SYMBOL(compute_creds);
  * points to; chop off the first by relocating brpm->p to right after
  * the first '\0' encountered.
  */
-void remove_arg_zero(struct linux_binprm *bprm)
+int remove_arg_zero(struct linux_binprm *bprm)
 {
-	if (bprm->argc) {
-		char ch;
+	int ret = 0;
+	unsigned long offset;
+	char *kaddr;
+	struct page *page;
 
-		do {
-			unsigned long offset;
-			unsigned long index;
-			char *kaddr;
-			struct page *page;
-
-			offset = bprm->p & ~PAGE_MASK;
-			index = bprm->p >> PAGE_SHIFT;
-
-			page = bprm->page[index];
-			kaddr = kmap_atomic(page, KM_USER0);
-
-			/* run through page until we reach end or find NUL */
-			do {
-				ch = *(kaddr + offset);
-
-				/* discard that character... */
-				bprm->p++;
-				offset++;
-			} while (offset < PAGE_SIZE && ch != '\0');
-
-			kunmap_atomic(kaddr, KM_USER0);
-
-			/* free the old page */
-			if (offset == PAGE_SIZE) {
-				__free_page(page);
-				bprm->page[index] = NULL;
-			}
-		} while (ch != '\0');
+	if (!bprm->argc)
+		return 0;
 
-		bprm->argc--;
-	}
+	do {
+		offset = bprm->p & ~PAGE_MASK;
+		page = get_arg_page(bprm, bprm->p, 0);
+		if (!page) {
+			ret = -EFAULT;
+			goto out;
+		}
+		kaddr = kmap_atomic(page, KM_USER0);
+
+		for (; offset < PAGE_SIZE && kaddr[offset];
+				offset++, bprm->p++)
+			;
+
+		kunmap_atomic(kaddr, KM_USER0);
+		put_arg_page(page);
+
+		if (offset == PAGE_SIZE)
+			free_arg_page(bprm, (bprm->p >> PAGE_SHIFT) - 1);
+	} while (offset == PAGE_SIZE);
+
+	bprm->p++;
+	bprm->argc--;
+	ret = 0;
+
+out:
+	return ret;
 }
 EXPORT_SYMBOL(remove_arg_zero);
 
@@ -1062,7 +1239,7 @@ int search_binary_handler(struct linux_b
 		fput(bprm->file);
 		bprm->file = NULL;
 
-	        loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+		loader = bprm->vma->vm_end - sizeof(void *);
 
 		file = open_exec("/sbin/loader");
 		retval = PTR_ERR(file);
@@ -1156,7 +1333,6 @@ int do_execve(char * filename,
 	struct file *file;
 	unsigned long env_p;
 	int retval;
-	int i;
 
 	retval = -ENOMEM;
 	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1170,25 +1346,19 @@ int do_execve(char * filename,
 
 	sched_exec();
 
-	bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-
 	bprm->file = file;
 	bprm->filename = filename;
 	bprm->interp = filename;
-	bprm->mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm->mm)
-		goto out_file;
 
-	retval = init_new_context(current, bprm->mm);
-	if (retval < 0)
-		goto out_mm;
+	retval = bprm_mm_init(bprm);
+	if (retval)
+		goto out_file;
 
-	bprm->argc = count(argv, bprm->p / sizeof(void *));
+	bprm->argc = count(argv, MAX_ARG_STRINGS);
 	if ((retval = bprm->argc) < 0)
 		goto out_mm;
 
-	bprm->envc = count(envp, bprm->p / sizeof(void *));
+	bprm->envc = count(envp, MAX_ARG_STRINGS);
 	if ((retval = bprm->envc) < 0)
 		goto out_mm;
 
@@ -1217,9 +1387,8 @@ int do_execve(char * filename,
 
 	retval = search_binary_handler(bprm,regs);
 	if (retval >= 0) {
-		free_arg_pages(bprm);
-
 		/* execve success */
+		free_arg_pages(bprm);
 		security_bprm_free(bprm);
 		acct_update_integrals(current);
 		kfree(bprm);
@@ -1227,26 +1396,19 @@ int do_execve(char * filename,
 	}
 
 out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page * page = bprm->page[i];
-		if (page)
-			__free_page(page);
-	}
-
+	free_arg_pages(bprm);
 	if (bprm->security)
 		security_bprm_free(bprm);
 
 out_mm:
 	if (bprm->mm)
-		mmdrop(bprm->mm);
+		mmput (bprm->mm);
 
 out_file:
 	if (bprm->file) {
 		allow_write_access(bprm->file);
 		fput(bprm->file);
 	}
-
 out_kfree:
 	kfree(bprm);
 
Index: linux-2.6-2/include/linux/binfmts.h
===================================================================
--- linux-2.6-2.orig/include/linux/binfmts.h	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/include/linux/binfmts.h	2007-06-13 11:52:46.000000000 +0200
@@ -6,11 +6,13 @@
 struct pt_regs;
 
 /*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
+ * These are the maximum length and maximum number of strings passed to the
+ * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
+ * prevent the kernel from being unduly impacted by misaddressed pointers.
+ * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
  */
-#define MAX_ARG_PAGES 32
+#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF
 
 /* sizeof(linux_binprm->buf) */
 #define BINPRM_BUF_SIZE 128
@@ -24,7 +26,12 @@ struct pt_regs;
  */
 struct linux_binprm{
 	char buf[BINPRM_BUF_SIZE];
+#ifdef CONFIG_MMU
+	struct vm_area_struct *vma;
+#else
+# define MAX_ARG_PAGES	32
 	struct page *page[MAX_ARG_PAGES];
+#endif
 	struct mm_struct *mm;
 	unsigned long p; /* current top of mem */
 	int sh_bang;
@@ -69,7 +76,7 @@ extern int register_binfmt(struct linux_
 extern int unregister_binfmt(struct linux_binfmt *);
 
 extern int prepare_binprm(struct linux_binprm *);
-extern void remove_arg_zero(struct linux_binprm *);
+extern int __must_check remove_arg_zero(struct linux_binprm *);
 extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
 extern int flush_old_exec(struct linux_binprm * bprm);
 
@@ -86,6 +93,7 @@ extern int suid_dumpable;
 extern int setup_arg_pages(struct linux_binprm * bprm,
 			   unsigned long stack_top,
 			   int executable_stack);
+extern int bprm_mm_init(struct linux_binprm *bprm);
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
 extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
Index: linux-2.6-2/include/linux/mm.h
===================================================================
--- linux-2.6-2.orig/include/linux/mm.h	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/include/linux/mm.h	2007-06-13 11:52:46.000000000 +0200
@@ -815,7 +815,6 @@ static inline int handle_mm_fault(struct
 
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
-void install_arg_page(struct vm_area_struct *, struct page *, unsigned long);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
@@ -832,9 +831,15 @@ int FASTCALL(set_page_dirty(struct page 
 int set_page_dirty_lock(struct page *page);
 int clear_page_dirty_for_io(struct page *page);
 
+extern unsigned long move_page_tables(struct vm_area_struct *vma,
+		unsigned long old_addr, struct vm_area_struct *new_vma,
+		unsigned long new_addr, unsigned long len);
 extern unsigned long do_mremap(unsigned long addr,
 			       unsigned long old_len, unsigned long new_len,
 			       unsigned long flags, unsigned long new_addr);
+extern int mprotect_fixup(struct vm_area_struct *vma,
+			  struct vm_area_struct **pprev, unsigned long start,
+			  unsigned long end, unsigned long newflags);
 
 /*
  * A callback you can register to apply pressure to ageable caches.
@@ -1159,6 +1164,8 @@ extern int expand_stack(struct vm_area_s
 #ifdef CONFIG_IA64
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #endif
+extern int expand_stack_downwards(struct vm_area_struct *vma,
+				  unsigned long address);
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
Index: linux-2.6-2/mm/mmap.c
===================================================================
--- linux-2.6-2.orig/mm/mmap.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/mm/mmap.c	2007-06-13 11:52:46.000000000 +0200
@@ -1581,33 +1581,11 @@ int expand_upwards(struct vm_area_struct
 }
 #endif /* CONFIG_STACK_GROWSUP || CONFIG_IA64 */
 
-#ifdef CONFIG_STACK_GROWSUP
-int expand_stack(struct vm_area_struct *vma, unsigned long address)
-{
-	return expand_upwards(vma, address);
-}
-
-struct vm_area_struct *
-find_extend_vma(struct mm_struct *mm, unsigned long addr)
-{
-	struct vm_area_struct *vma, *prev;
-
-	addr &= PAGE_MASK;
-	vma = find_vma_prev(mm, addr, &prev);
-	if (vma && (vma->vm_start <= addr))
-		return vma;
-	if (!prev || expand_stack(prev, addr))
-		return NULL;
-	if (prev->vm_flags & VM_LOCKED) {
-		make_pages_present(addr, prev->vm_end);
-	}
-	return prev;
-}
-#else
 /*
  * vma is the first one with address < vma->vm_start.  Have to extend vma.
  */
-int expand_stack(struct vm_area_struct *vma, unsigned long address)
+static inline int expand_downwards(struct vm_area_struct *vma,
+				   unsigned long address)
 {
 	int error;
 
@@ -1644,6 +1622,38 @@ int expand_stack(struct vm_area_struct *
 	return error;
 }
 
+int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address)
+{
+	return expand_downwards(vma, address);
+}
+
+#ifdef CONFIG_STACK_GROWSUP
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+	return expand_upwards(vma, address);
+}
+
+struct vm_area_struct *
+find_extend_vma(struct mm_struct *mm, unsigned long addr)
+{
+	struct vm_area_struct *vma, *prev;
+
+	addr &= PAGE_MASK;
+	vma = find_vma_prev(mm, addr, &prev);
+	if (vma && (vma->vm_start <= addr))
+		return vma;
+	if (!prev || expand_stack(prev, addr))
+		return NULL;
+	if (prev->vm_flags & VM_LOCKED)
+		make_pages_present(addr, prev->vm_end);
+	return prev;
+}
+#else
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+	return expand_downwards(vma, address);
+}
+
 struct vm_area_struct *
 find_extend_vma(struct mm_struct * mm, unsigned long addr)
 {
@@ -1661,9 +1671,8 @@ find_extend_vma(struct mm_struct * mm, u
 	start = vma->vm_start;
 	if (expand_stack(vma, addr))
 		return NULL;
-	if (vma->vm_flags & VM_LOCKED) {
+	if (vma->vm_flags & VM_LOCKED)
 		make_pages_present(addr, start);
-	}
 	return vma;
 }
 #endif
Index: linux-2.6-2/mm/mprotect.c
===================================================================
--- linux-2.6-2.orig/mm/mprotect.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/mm/mprotect.c	2007-06-13 11:52:46.000000000 +0200
@@ -128,7 +128,7 @@ static void change_protection(struct vm_
 	flush_tlb_range(vma, start, end);
 }
 
-static int
+int
 mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
 	unsigned long start, unsigned long end, unsigned long newflags)
 {
Index: linux-2.6-2/arch/ia64/ia32/binfmt_elf32.c
===================================================================
--- linux-2.6-2.orig/arch/ia64/ia32/binfmt_elf32.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/arch/ia64/ia32/binfmt_elf32.c	2007-06-13 11:52:46.000000000 +0200
@@ -195,62 +195,27 @@ ia64_elf32_init (struct pt_regs *regs)
 	ia32_load_state(current);
 }
 
+/*
+ * Undo the override of setup_arg_pages() without this ia32_setup_arg_pages()
+ * will suffer infinite self recursion.
+ */
+#undef setup_arg_pages
+
 int
 ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
 {
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
-	struct mm_struct *mm = current->mm;
-	int i, ret;
-
-	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
-	mm->arg_start = bprm->p + stack_base;
-
-	bprm->p += stack_base;
-	if (bprm->loader)
-		bprm->loader += stack_base;
-	bprm->exec += stack_base;
-
-	mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	if (!mpnt)
-		return -ENOMEM;
-
-	down_write(&current->mm->mmap_sem);
-	{
-		mpnt->vm_mm = current->mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = IA32_STACK_TOP;
-		if (executable_stack == EXSTACK_ENABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-		else if (executable_stack == EXSTACK_DISABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-		else
-			mpnt->vm_flags = VM_STACK_FLAGS;
-		mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)?
-					PAGE_COPY_EXEC: PAGE_COPY;
-		if ((ret = insert_vm_struct(current->mm, mpnt))) {
-			up_write(&current->mm->mmap_sem);
-			kmem_cache_free(vm_area_cachep, mpnt);
-			return ret;
-		}
-		current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt);
-	}
+	int ret;
 
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page *page = bprm->page[i];
-		if (page) {
-			bprm->page[i] = NULL;
-			install_arg_page(mpnt, page, stack_base);
-		}
-		stack_base += PAGE_SIZE;
+	ret = setup_arg_pages(bprm, IA32_STACK_TOP, executable_stack);
+	if (!ret) {
+		/*
+		 * Can't do it in ia64_elf32_init(). Needs to be done before
+		 * calls to elf32_map()
+		 */
+		current->thread.ppl = ia32_init_pp_list();
 	}
-	up_write(&current->mm->mmap_sem);
 
-	/* Can't do it in ia64_elf32_init(). Needs to be done before calls to
-	   elf32_map() */
-	current->thread.ppl = ia32_init_pp_list();
-
-	return 0;
+	return ret;
 }
 
 static void
Index: linux-2.6-2/arch/x86_64/ia32/ia32_aout.c
===================================================================
--- linux-2.6-2.orig/arch/x86_64/ia32/ia32_aout.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/arch/x86_64/ia32/ia32_aout.c	2007-06-13 11:52:46.000000000 +0200
@@ -404,7 +404,7 @@ beyond_if:
 
 	set_brk(current->mm->start_brk, current->mm->brk);
 
-	retval = ia32_setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
+	retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
 	if (retval < 0) { 
 		/* Someone check-me: is this error path enough? */ 
 		send_sig(SIGKILL, current, 0); 
Index: linux-2.6-2/kernel/auditsc.c
===================================================================
--- linux-2.6-2.orig/kernel/auditsc.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/kernel/auditsc.c	2007-06-13 11:52:46.000000000 +0200
@@ -846,7 +846,7 @@ static void audit_log_execve_info(struct
 		return; /* execve failed, no additional info */
 
 	for (i = 0; i < axi->argc; i++, p += len) {
-		len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
+		len = strnlen_user(p, MAX_ARG_STRLEN);
 		/*
 		 * We just created this mm, if we can't find the strings
 		 * we just copied into it something is _very_ wrong. Similar
Index: linux-2.6-2/mm/mremap.c
===================================================================
--- linux-2.6-2.orig/mm/mremap.c	2007-06-13 11:52:44.000000000 +0200
+++ linux-2.6-2/mm/mremap.c	2007-06-13 11:52:46.000000000 +0200
@@ -120,7 +120,7 @@ static void move_ptes(struct vm_area_str
 
 #define LATENCY_LIMIT	(64 * PAGE_SIZE)
 
-static unsigned long move_page_tables(struct vm_area_struct *vma,
+unsigned long move_page_tables(struct vm_area_struct *vma,
 		unsigned long old_addr, struct vm_area_struct *new_vma,
 		unsigned long new_addr, unsigned long len)
 {

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-13 10:03 [patch 0/3] no MAX_ARG_PAGES -v2 Peter Zijlstra
                   ` (2 preceding siblings ...)
  2007-06-13 10:03 ` [patch 3/3] mm: variable length argument support Peter Zijlstra
@ 2007-06-13 23:36 ` Luck, Tony
  2007-06-14  6:23   ` Ollie Wild
  2007-06-17 18:32 ` Pavel Machek
  4 siblings, 1 reply; 26+ messages in thread
From: Luck, Tony @ 2007-06-13 23:36 UTC (permalink / raw)
  To: Peter Zijlstra, linux-kernel, parisc-linux, linux-mm, linux-arch
  Cc: Ollie Wild, Andrew Morton, Ingo Molnar, Andi Kleen

> This patch-set aims at removing the current limit on argv+env space aka.
> MAX_ARG_PAGES.

Running with this patch shows that /bin/bash has some unpleasant
O(n^2) performance issues with long argument lists.  I made a
1Mbyte file full of pathnames, then timed the execution of:

$ /bin/echo `cat megabyte` | wc
$ /bin/echo `cat megabyte megabyte` | wc
   etc. ...

System time was pretty much linear as the arglist grew
(and only got up to 0.144 seconds at 5Mbytes).

But user time ~= real time (in seconds) looks like:

1 5.318
2 18.871
3 40.620
4 70.819
5 108.911

Above 5Mbytes, I started seeing problems.  The line/word/char
counts from "wc" started being "0 0 0".  Not sure if this is
a problem in "wc" dealing with a single line >5MBytes, or some
other problem (possibly I was exceeding the per-process stack
limit which is only 8MB on that machine).

-Tony

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-13 23:36 ` [patch 0/3] no MAX_ARG_PAGES -v2 Luck, Tony
@ 2007-06-14  6:23   ` Ollie Wild
  2007-06-14  8:38     ` Peter Zijlstra
  0 siblings, 1 reply; 26+ messages in thread
From: Ollie Wild @ 2007-06-14  6:23 UTC (permalink / raw)
  To: Luck, Tony
  Cc: Peter Zijlstra, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

On 6/13/07, Luck, Tony <tony.luck@intel.com> wrote:
> Above 5Mbytes, I started seeing problems.  The line/word/char
> counts from "wc" started being "0 0 0".  Not sure if this is
> a problem in "wc" dealing with a single line >5MBytes, or some
> other problem (possibly I was exceeding the per-process stack
> limit which is only 8MB on that machine).

Interesting.  If you're exceeding your stack ulimit, you should be
seeing either an "argument list too long" message or getting a
SIGSEGV.  Have you tried bypassing wc and piping the output straight
to a file?

Ollie

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-14  6:23   ` Ollie Wild
@ 2007-06-14  8:38     ` Peter Zijlstra
  2007-06-14 18:22       ` Luck, Tony
  2007-06-14 20:58       ` Ollie Wild
  0 siblings, 2 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-14  8:38 UTC (permalink / raw)
  To: Ollie Wild
  Cc: Luck, Tony, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

On Wed, 2007-06-13 at 23:23 -0700, Ollie Wild wrote:
> On 6/13/07, Luck, Tony <tony.luck@intel.com> wrote:
> > Above 5Mbytes, I started seeing problems.  The line/word/char
> > counts from "wc" started being "0 0 0".  Not sure if this is
> > a problem in "wc" dealing with a single line >5MBytes, or some
> > other problem (possibly I was exceeding the per-process stack
> > limit which is only 8MB on that machine).
> 
> Interesting.  If you're exceeding your stack ulimit, you should be
> seeing either an "argument list too long" message or getting a
> SIGSEGV.  Have you tried bypassing wc and piping the output straight
> to a file?

I think it sends SIGKILL on failure paths.

I've been thinking of moving this large stack alloc in
create_elf_tables() before the point of no return.

something like this, it should do the largest part of the alloc
beforehand. Just have to see if all binfmts need this much, and if not,
what the ramifications are of overgrowing the stack (perhaps we need to
shrink it again to wherever bprm->p ends up?)


Index: linux-2.6-2/fs/exec.c
===================================================================
--- linux-2.6-2.orig/fs/exec.c	2007-06-14 10:29:22.000000000 +0200
+++ linux-2.6-2/fs/exec.c	2007-06-14 10:28:45.000000000 +0200
@@ -272,6 +272,17 @@ static bool valid_arg_len(struct linux_b
 	return len <= MAX_ARG_STRLEN;
 }
 
+static int expand_arg_vma(struct linux_binprm *bprm)
+{
+	long size = (bprm->argc + bprm->envc + 2) * sizeof(void *);
+
+#ifdef CONFIG_STACK_GROWSUP
+#error I broke it
+#else
+	return expand_stack(bprm->vma, bprm->p - size);
+#endif
+}
+
 #else
 
 static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
@@ -326,6 +337,11 @@ static bool valid_arg_len(struct linux_b
 	return len <= bprm->p;
 }
 
+static int expand_arg_vma(struct linux_binprm *bprm)
+{
+	return 0;
+}
+
 #endif /* CONFIG_MMU */
 
 /*
@@ -1385,6 +1401,10 @@ int do_execve(char * filename,
 		goto out;
 	bprm->argv_len = env_p - bprm->p;
 
+	retval = expand_arg_vma(bprm);
+	if (retval < 0)
+		goto out;
+
 	retval = search_binary_handler(bprm,regs);
 	if (retval >= 0) {
 		/* execve success */



^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-14  8:38     ` Peter Zijlstra
@ 2007-06-14 18:22       ` Luck, Tony
  2007-06-14 18:32         ` Peter Zijlstra
  2007-06-14 20:58       ` Ollie Wild
  1 sibling, 1 reply; 26+ messages in thread
From: Luck, Tony @ 2007-06-14 18:22 UTC (permalink / raw)
  To: Peter Zijlstra, Ollie Wild
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Andrew Morton,
	Ingo Molnar, Andi Kleen

> > Interesting.  If you're exceeding your stack ulimit, you should be
> > seeing either an "argument list too long" message or getting a
> > SIGSEGV.  Have you tried bypassing wc and piping the output straight
> > to a file?
>
> I think it sends SIGKILL on failure paths.

Setting stack limit to unlimited I managed to exec with 10MB, and
"wc" produced the correct output when it (finally) ran, so no
odd limits being hit in there.

Setting a lower (4MB) stack limit, and then increasing the
amount of args in 100K steps I saw this:

Up to an including 32 * 100K => works fine.

33:40 * 100K => no errors from the script, but wc reports "0 0 0"

>40 * 100K => "/bin/echo: Argument list too long".


All this might be connected to ia64's confusing implementation
of stack limit (since we have *two* stacks ... the regular one
and the upward growing one for the h/w register stack engine).

Ah ... running the 34*100K case direct from my shell prompt, I
do see a "Killed" that must get lost when I run this in the
shell script loop.

-Tony

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-14 18:22       ` Luck, Tony
@ 2007-06-14 18:32         ` Peter Zijlstra
  0 siblings, 0 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-14 18:32 UTC (permalink / raw)
  To: Luck, Tony
  Cc: Ollie Wild, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

On Thu, 2007-06-14 at 11:22 -0700, Luck, Tony wrote:
> > > Interesting.  If you're exceeding your stack ulimit, you should be
> > > seeing either an "argument list too long" message or getting a
> > > SIGSEGV.  Have you tried bypassing wc and piping the output straight
> > > to a file?
> >
> > I think it sends SIGKILL on failure paths.
> 
> Setting stack limit to unlimited I managed to exec with 10MB, and
> "wc" produced the correct output when it (finally) ran, so no
> odd limits being hit in there.

Ah, good :-)

> Ah ... running the 34*100K case direct from my shell prompt, I
> do see a "Killed" that must get lost when I run this in the
> shell script loop.

Yes, so it seems we just trip the stack limit after we cross the point
of no return.

I started looking into growing the stack beforehand and perhaps
shrinking the stack after we're done. That would get most if not all
these failures before the point of no return.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-14  8:38     ` Peter Zijlstra
  2007-06-14 18:22       ` Luck, Tony
@ 2007-06-14 20:58       ` Ollie Wild
  2007-06-14 21:18         ` Peter Zijlstra
  2007-06-15  9:24         ` Peter Zijlstra
  1 sibling, 2 replies; 26+ messages in thread
From: Ollie Wild @ 2007-06-14 20:58 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Luck, Tony, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

> @@ -1385,6 +1401,10 @@ int do_execve(char * filename,
>                 goto out;
>         bprm->argv_len = env_p - bprm->p;
>
> +       retval = expand_arg_vma(bprm);
> +       if (retval < 0)
> +               goto out;
> +
>         retval = search_binary_handler(bprm,regs);
>         if (retval >= 0) {
>                 /* execve success */

At this point bprm->argc hasn't been finalized yet.  For example, the
script binfmt reads the script header and adds additional arguments.
The flush_old_exec() function is a better place to call this.

I'm not 100% sure this is the right way to handle this, though.  The
problem isn't as simple as ensuring the stack doesn't overflow during
argument allocation.  We also need to ensure the program has
sufficient stack space to run subsequently.  Otherwise, the observable
behavior is identical.  Since we can't realistically predict
acceptable stack availability requirements, some amount of uncertainty
is always going to exist.  A good heuristic, though, might be to limit
argument size to a percentage (say 25%) of maximum stack size and
validate this inside copy_strings().

Ollie

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-14 20:58       ` Ollie Wild
@ 2007-06-14 21:18         ` Peter Zijlstra
  2007-06-15  9:24         ` Peter Zijlstra
  1 sibling, 0 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-14 21:18 UTC (permalink / raw)
  To: Ollie Wild
  Cc: Luck, Tony, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

On Thu, 2007-06-14 at 13:58 -0700, Ollie Wild wrote:
> > @@ -1385,6 +1401,10 @@ int do_execve(char * filename,
> >                 goto out;
> >         bprm->argv_len = env_p - bprm->p;
> >
> > +       retval = expand_arg_vma(bprm);
> > +       if (retval < 0)
> > +               goto out;
> > +
> >         retval = search_binary_handler(bprm,regs);
> >         if (retval >= 0) {
> >                 /* execve success */
> 
> At this point bprm->argc hasn't been finalized yet.  For example, the
> script binfmt reads the script header and adds additional arguments.
> The flush_old_exec() function is a better place to call this.

Sure, but at this time most of it is there, so when there are many, this
allocates the most of it.

> I'm not 100% sure this is the right way to handle this, though.  The
> problem isn't as simple as ensuring the stack doesn't overflow during
> argument allocation.  We also need to ensure the program has
> sufficient stack space to run subsequently.  Otherwise, the observable
> behavior is identical. 

Well, not identical, but similar indeed.

>  Since we can't realistically predict
> acceptable stack availability requirements, some amount of uncertainty
> is always going to exist.  

> A good heuristic, though, might be to limit
> argument size to a percentage (say 25%) of maximum stack size and
> validate this inside copy_strings().

Right, this seems a much simpler approach. I like it.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-14 20:58       ` Ollie Wild
  2007-06-14 21:18         ` Peter Zijlstra
@ 2007-06-15  9:24         ` Peter Zijlstra
  2007-06-15 18:07           ` Ollie Wild
  1 sibling, 1 reply; 26+ messages in thread
From: Peter Zijlstra @ 2007-06-15  9:24 UTC (permalink / raw)
  To: Ollie Wild
  Cc: Luck, Tony, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

On Thu, 2007-06-14 at 13:58 -0700, Ollie Wild wrote:

>   A good heuristic, though, might be to limit
> argument size to a percentage (say 25%) of maximum stack size and
> validate this inside copy_strings().

This seems to do:


Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
 fs/exec.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

Index: linux-2.6-2/fs/exec.c
===================================================================
--- linux-2.6-2.orig/fs/exec.c	2007-06-15 11:05:09.000000000 +0200
+++ linux-2.6-2/fs/exec.c	2007-06-15 11:05:18.000000000 +0200
@@ -199,6 +199,23 @@ static struct page *get_arg_page(struct 
 	if (ret <= 0)
 		return NULL;
 
+	if (write) {
+		struct rlimit *rlim = current->signal->rlim;
+		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+
+		/*
+		 * Limit to 1/4-th the stack size for the argv+env strings.
+		 * This ensures that:
+		 *  - the remaining binfmt code will not run out of stack space,
+		 *  - the program will have a reasonable amount of stack left
+		 *    to work from.
+		 */
+		if (size > rlim[RLIMIT_STACK].rlim_cur / 4) {
+			put_page(page);
+			return NULL;
+		}
+	}
+
 	return page;
 }
 



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-15  9:24         ` Peter Zijlstra
@ 2007-06-15 18:07           ` Ollie Wild
  2007-06-15 18:49             ` Luck, Tony
  0 siblings, 1 reply; 26+ messages in thread
From: Ollie Wild @ 2007-06-15 18:07 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Luck, Tony, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Andrew Morton, Ingo Molnar, Andi Kleen

On 6/15/07, Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> On Thu, 2007-06-14 at 13:58 -0700, Ollie Wild wrote:
>
> >   A good heuristic, though, might be to limit
> > argument size to a percentage (say 25%) of maximum stack size and
> > validate this inside copy_strings().
>
> This seems to do:

Looks good.

Ollie

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-15 18:07           ` Ollie Wild
@ 2007-06-15 18:49             ` Luck, Tony
  0 siblings, 0 replies; 26+ messages in thread
From: Luck, Tony @ 2007-06-15 18:49 UTC (permalink / raw)
  To: Ollie Wild, Peter Zijlstra
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Andrew Morton,
	Ingo Molnar, Andi Kleen

> > >   A good heuristic, though, might be to limit
> > > argument size to a percentage (say 25%) of maximum stack size and
> > > validate this inside copy_strings().
> >
> > This seems to do:
>
> Looks good.

Me too.  As I increase the number of arguments, I now have
a smooth cutover from "works" to "Arg list too long", without
the in between zone where the process is killed.

The IA-32 compatability exec path is now working too (I didn't
stress it too hard, but I did try argument lists up to a megabyte).

Acked-by: Tony Luck <tony.luck@intel.com>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-13 10:03 [patch 0/3] no MAX_ARG_PAGES -v2 Peter Zijlstra
                   ` (3 preceding siblings ...)
  2007-06-13 23:36 ` [patch 0/3] no MAX_ARG_PAGES -v2 Luck, Tony
@ 2007-06-17 18:32 ` Pavel Machek
  2007-06-17 19:07   ` Ingo Molnar
  4 siblings, 1 reply; 26+ messages in thread
From: Pavel Machek @ 2007-06-17 18:32 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Ollie Wild,
	Andrew Morton, Ingo Molnar, Andi Kleen

Hi!

> This patch-set aims at removing the current limit on argv+env space aka.
> MAX_ARG_PAGES.

Thanks a lot for solving this properly. I have been upping current limits to some
insane ammounts to work around this.
							Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 0/3] no MAX_ARG_PAGES -v2
  2007-06-17 18:32 ` Pavel Machek
@ 2007-06-17 19:07   ` Ingo Molnar
  0 siblings, 0 replies; 26+ messages in thread
From: Ingo Molnar @ 2007-06-17 19:07 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Peter Zijlstra, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Ollie Wild, Andrew Morton, Andi Kleen


* Pavel Machek <pavel@ucw.cz> wrote:

> Hi!
> 
> > This patch-set aims at removing the current limit on argv+env space 
> > aka. MAX_ARG_PAGES.
> 
> Thanks a lot for solving this properly. I have been upping current 
> limits to some insane ammounts to work around this.

seconded! I have tried the patchset and it works great for me. This 
limitation of Linux has bothered me almost since i started using Linux 
more than a decade ago (i remember having run into it when running a 
script on an overly large directory), and it's perhaps the oldest still 
existing userspace-visible limitations of Linux. It was also a really 
hard nut to crack. Kudos Peter! I really cant wait to see this in 2.6.23
:-)

Acked-by: Ingo Molnar <mingo@elte.hu>

	Ingo

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 2/3] audit: rework execve audit
  2007-06-13 10:03 ` [patch 2/3] audit: rework execve audit Peter Zijlstra
@ 2007-06-26 22:55   ` Andrew Morton
  2007-07-03 15:00     ` Peter Zijlstra
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Morton @ 2007-06-26 22:55 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Ollie Wild,
	Ingo Molnar, Andi Kleen, linux-audit

On Wed, 13 Jun 2007 12:03:36 +0200
Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:

> +#ifdef CONFIG_AUDITSYSCALL
> +	{
> +		.ctl_name	= CTL_UNNUMBERED,
> +		.procname	= "audit_argv_kb",
> +		.data		= &audit_argv_kb,
> +		.maxlen		= sizeof(int),
> +		.mode		= 0644,
> +		.proc_handler	= &proc_dointvec,
> +	},
> +#endif

Please document /proc entries in Documentation/filesystems/proc.txt

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 2/3] audit: rework execve audit
  2007-06-26 22:55   ` Andrew Morton
@ 2007-07-03 15:00     ` Peter Zijlstra
  0 siblings, 0 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-07-03 15:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Ollie Wild,
	Ingo Molnar, Andi Kleen, linux-audit

On Tue, 2007-06-26 at 15:55 -0700, Andrew Morton wrote:
> On Wed, 13 Jun 2007 12:03:36 +0200
> Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> 
> > +#ifdef CONFIG_AUDITSYSCALL
> > +	{
> > +		.ctl_name	= CTL_UNNUMBERED,
> > +		.procname	= "audit_argv_kb",
> > +		.data		= &audit_argv_kb,
> > +		.maxlen		= sizeof(int),
> > +		.mode		= 0644,
> > +		.proc_handler	= &proc_dointvec,
> > +	},
> > +#endif
> 
> Please document /proc entries in Documentation/filesystems/proc.txt



Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
 Documentation/filesystems/proc.txt |    7 +++++++
 1 file changed, 7 insertions(+)

Index: linux-2.6/Documentation/filesystems/proc.txt
===================================================================
--- linux-2.6.orig/Documentation/filesystems/proc.txt
+++ linux-2.6/Documentation/filesystems/proc.txt
@@ -1075,6 +1075,13 @@ check the amount of free space (value is
 resume it  if we have a value of 3 or more percent; consider information about
 the amount of free space valid for 30 seconds
 
+audit_argv_kb
+-------------
+
+The file contains a single value denoting the limit on the argv array size
+for execve (in KiB). This limit is only applied when system call auditing for
+execve is enabled, otherwise the value is ignored.
+
 ctrl-alt-del
 ------------
 



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-06-13 10:03 ` [patch 3/3] mm: variable length argument support Peter Zijlstra
@ 2007-08-07 19:03   ` Olaf Hering
  2007-08-07 19:20     ` Andrew Morton
  2007-08-22  8:48   ` Dan Aloni
  1 sibling, 1 reply; 26+ messages in thread
From: Olaf Hering @ 2007-08-07 19:03 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Ollie Wild,
	Andrew Morton, Ingo Molnar, Andi Kleen

On Wed, Jun 13, Peter Zijlstra wrote:

> From: Ollie Wild <aaw@google.com>
> 
> Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
> from the old mm into the new mm.

> +++ linux-2.6-2/include/linux/binfmts.h	2007-06-13 11:52:46.000000000 +0200
> @@ -6,11 +6,13 @@
>  struct pt_regs;
>  
>  /*
> - * MAX_ARG_PAGES defines the number of pages allocated for arguments
> - * and envelope for the new program. 32 should suffice, this gives
> - * a maximum env+arg of 128kB w/4KB pages!
> + * These are the maximum length and maximum number of strings passed to the
> + * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
> + * prevent the kernel from being unduly impacted by misaddressed pointers.
> + * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
>   */
> -#define MAX_ARG_PAGES 32
> +#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
> +#define MAX_ARG_STRINGS 0x7FFFFFFF

This adds a new usage of PAGE_SIZE to an exported header.
How can this be fixed for 2.6.23?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-08-07 19:03   ` Olaf Hering
@ 2007-08-07 19:20     ` Andrew Morton
  2007-08-07 19:26       ` Peter Zijlstra
  2007-08-07 20:10       ` Olaf Hering
  0 siblings, 2 replies; 26+ messages in thread
From: Andrew Morton @ 2007-08-07 19:20 UTC (permalink / raw)
  To: Olaf Hering
  Cc: Peter Zijlstra, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Ollie Wild, Ingo Molnar, Andi Kleen

On Tue, 7 Aug 2007 21:03:57 +0200
Olaf Hering <olaf@aepfle.de> wrote:

> On Wed, Jun 13, Peter Zijlstra wrote:
> 
> > From: Ollie Wild <aaw@google.com>
> > 
> > Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
> > from the old mm into the new mm.
> 
> > +++ linux-2.6-2/include/linux/binfmts.h	2007-06-13 11:52:46.000000000 +0200
> > @@ -6,11 +6,13 @@
> >  struct pt_regs;
> >  
> >  /*
> > - * MAX_ARG_PAGES defines the number of pages allocated for arguments
> > - * and envelope for the new program. 32 should suffice, this gives
> > - * a maximum env+arg of 128kB w/4KB pages!
> > + * These are the maximum length and maximum number of strings passed to the
> > + * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
> > + * prevent the kernel from being unduly impacted by misaddressed pointers.
> > + * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
> >   */
> > -#define MAX_ARG_PAGES 32
> > +#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
> > +#define MAX_ARG_STRINGS 0x7FFFFFFF
> 
> This adds a new usage of PAGE_SIZE to an exported header.
> How can this be fixed for 2.6.23?

Put #ifdef __KERNEL__ around it?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-08-07 19:20     ` Andrew Morton
@ 2007-08-07 19:26       ` Peter Zijlstra
  2007-08-07 20:10       ` Olaf Hering
  1 sibling, 0 replies; 26+ messages in thread
From: Peter Zijlstra @ 2007-08-07 19:26 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Olaf Hering, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Ollie Wild, Ingo Molnar, Andi Kleen

On Tue, 2007-08-07 at 12:20 -0700, Andrew Morton wrote:
> On Tue, 7 Aug 2007 21:03:57 +0200
> Olaf Hering <olaf@aepfle.de> wrote:
> 
> > On Wed, Jun 13, Peter Zijlstra wrote:
> > 
> > > From: Ollie Wild <aaw@google.com>
> > > 
> > > Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
> > > from the old mm into the new mm.
> > 
> > > +++ linux-2.6-2/include/linux/binfmts.h	2007-06-13 11:52:46.000000000 +0200
> > > @@ -6,11 +6,13 @@
> > >  struct pt_regs;
> > >  
> > >  /*
> > > - * MAX_ARG_PAGES defines the number of pages allocated for arguments
> > > - * and envelope for the new program. 32 should suffice, this gives
> > > - * a maximum env+arg of 128kB w/4KB pages!
> > > + * These are the maximum length and maximum number of strings passed to the
> > > + * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
> > > + * prevent the kernel from being unduly impacted by misaddressed pointers.
> > > + * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
> > >   */
> > > -#define MAX_ARG_PAGES 32
> > > +#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
> > > +#define MAX_ARG_STRINGS 0x7FFFFFFF
> > 
> > This adds a new usage of PAGE_SIZE to an exported header.
> > How can this be fixed for 2.6.23?
> 
> Put #ifdef __KERNEL__ around it?

Sounds like a good idea, since its new there should not yet be anybody
using it.

If anything, someone used to use MAX_ARG_PAGES in userspace, which we
just now broke. Olaf said he'd grep a distro source base to find out :-)


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-08-07 19:20     ` Andrew Morton
  2007-08-07 19:26       ` Peter Zijlstra
@ 2007-08-07 20:10       ` Olaf Hering
  1 sibling, 0 replies; 26+ messages in thread
From: Olaf Hering @ 2007-08-07 20:10 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Peter Zijlstra, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Ollie Wild, Ingo Molnar, Andi Kleen

On Tue, Aug 07, Andrew Morton wrote:

> > > +++ linux-2.6-2/include/linux/binfmts.h	2007-06-13 11:52:46.000000000 +0200

> > > -#define MAX_ARG_PAGES 32
> > > +#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
> > > +#define MAX_ARG_STRINGS 0x7FFFFFFF
> > 
> > This adds a new usage of PAGE_SIZE to an exported header.
> > How can this be fixed for 2.6.23?
> 
> Put #ifdef __KERNEL__ around it?

No package uses linux/binfmts.h, will send a Kbuild patch to unexport
it.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-06-13 10:03 ` [patch 3/3] mm: variable length argument support Peter Zijlstra
  2007-08-07 19:03   ` Olaf Hering
@ 2007-08-22  8:48   ` Dan Aloni
  2007-08-22  8:54     ` Peter Zijlstra
       [not found]     ` <20070822090251.GA7038@mail.ustc.edu.cn>
  1 sibling, 2 replies; 26+ messages in thread
From: Dan Aloni @ 2007-08-22  8:48 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Ollie Wild,
	Andrew Morton, Ingo Molnar, Andi Kleen

On Wed, Jun 13, 2007 at 12:03:37PM +0200, Peter Zijlstra wrote:
> From: Ollie Wild <aaw@google.com>
> 
> Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
> from the old mm into the new mm.
> 
[...]
> +static int __bprm_mm_init(struct linux_binprm *bprm)
> +{
[...]
> +	vma->vm_flags = VM_STACK_FLAGS;
> +	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
> +	err = insert_vm_struct(mm, vma);
> +	if (err) {
> +		up_write(&mm->mmap_sem);
> +		goto err;
> +	}
> +

That change causes a crash in khelper when overcommit_memory = 2 
under 2.6.23-rc3.

When a khelper execs, at __bprm_mm_init() current->mm is still NULL.
insert_vm_struct() calls security_vm_enough_memory(), which calls 
__vm_enough_memory(), and that's where current->mm->total_vm gets 
dereferenced.


Signed-off-by: Dan Aloni <da-x@monatomic.org>

diff --git a/mm/mmap.c b/mm/mmap.c
index 906ed40..6e021df 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -163,10 +163,12 @@ int __vm_enough_memory(long pages, int cap_sys_admin)
 	if (!cap_sys_admin)
 		allowed -= allowed / 32;
 	allowed += total_swap_pages;
-
-	/* Don't let a single process grow too big:
-	   leave 3% of the size of this process for other processes */
-	allowed -= current->mm->total_vm / 32;
+
+	if (current->mm) {
+		/* Don't let a single process grow too big:
+		   leave 3% of the size of this process for other processes */
+		allowed -= current->mm->total_vm / 32;
+	}
 
 	/*
 	 * cast `allowed' as a signed long because vm_committed_space


-- 
Dan Aloni
XIV LTD, http://www.xivstorage.com
da-x (at) monatomic.org, dan (at) xiv.co.il

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-08-22  8:48   ` Dan Aloni
@ 2007-08-22  8:54     ` Peter Zijlstra
  2007-08-22  9:05       ` Andrew Morton
       [not found]     ` <20070822090251.GA7038@mail.ustc.edu.cn>
  1 sibling, 1 reply; 26+ messages in thread
From: Peter Zijlstra @ 2007-08-22  8:54 UTC (permalink / raw)
  To: Dan Aloni
  Cc: linux-kernel, parisc-linux, linux-mm, linux-arch, Ollie Wild,
	Andrew Morton, Ingo Molnar, Andi Kleen, Alan Cox

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

On Wed, 2007-08-22 at 11:48 +0300, Dan Aloni wrote:
> On Wed, Jun 13, 2007 at 12:03:37PM +0200, Peter Zijlstra wrote:
> > From: Ollie Wild <aaw@google.com>
> > 
> > Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
> > from the old mm into the new mm.
> > 
> [...]
> > +static int __bprm_mm_init(struct linux_binprm *bprm)
> > +{
> [...]
> > +	vma->vm_flags = VM_STACK_FLAGS;
> > +	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
> > +	err = insert_vm_struct(mm, vma);
> > +	if (err) {
> > +		up_write(&mm->mmap_sem);
> > +		goto err;
> > +	}
> > +
> 
> That change causes a crash in khelper when overcommit_memory = 2 
> under 2.6.23-rc3.
> 
> When a khelper execs, at __bprm_mm_init() current->mm is still NULL.
> insert_vm_struct() calls security_vm_enough_memory(), which calls 
> __vm_enough_memory(), and that's where current->mm->total_vm gets 
> dereferenced.

Alan proposed this patch:

http://lkml.org/lkml/2007/8/13/782


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
       [not found]     ` <20070822090251.GA7038@mail.ustc.edu.cn>
@ 2007-08-22  9:02       ` Fengguang Wu
  0 siblings, 0 replies; 26+ messages in thread
From: Fengguang Wu @ 2007-08-22  9:02 UTC (permalink / raw)
  To: Dan Aloni
  Cc: Peter Zijlstra, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Ollie Wild, Andrew Morton, Ingo Molnar, Andi Kleen

On Wed, Aug 22, 2007 at 11:48:52AM +0300, Dan Aloni wrote:
> On Wed, Jun 13, 2007 at 12:03:37PM +0200, Peter Zijlstra wrote:
> > From: Ollie Wild <aaw@google.com>
> > 
> > Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly
> > from the old mm into the new mm.
> > 
> [...]
> > +static int __bprm_mm_init(struct linux_binprm *bprm)
> > +{
> [...]
> > +	vma->vm_flags = VM_STACK_FLAGS;
> > +	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
> > +	err = insert_vm_struct(mm, vma);
> > +	if (err) {
> > +		up_write(&mm->mmap_sem);
> > +		goto err;
> > +	}
> > +
> 
> That change causes a crash in khelper when overcommit_memory = 2 
> under 2.6.23-rc3.
> 
> When a khelper execs, at __bprm_mm_init() current->mm is still NULL.
> insert_vm_struct() calls security_vm_enough_memory(), which calls 
> __vm_enough_memory(), and that's where current->mm->total_vm gets 
> dereferenced.
> 
> 
> Signed-off-by: Dan Aloni <da-x@monatomic.org>
> 
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 906ed40..6e021df 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -163,10 +163,12 @@ int __vm_enough_memory(long pages, int cap_sys_admin)
>  	if (!cap_sys_admin)
>  		allowed -= allowed / 32;
>  	allowed += total_swap_pages;
> -
> -	/* Don't let a single process grow too big:
> -	   leave 3% of the size of this process for other processes */
> -	allowed -= current->mm->total_vm / 32;
> +
> +	if (current->mm) {
> +		/* Don't let a single process grow too big:
> +		   leave 3% of the size of this process for other processes */
> +		allowed -= current->mm->total_vm / 32;
> +	}
>  
>  	/*
>  	 * cast `allowed' as a signed long because vm_committed_space
> 

FYI: This bug has been fixed by Alan Cox: http://lkml.org/lkml/2007/8/13/782.

But thanks anyway~


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [patch 3/3] mm: variable length argument support
  2007-08-22  8:54     ` Peter Zijlstra
@ 2007-08-22  9:05       ` Andrew Morton
  0 siblings, 0 replies; 26+ messages in thread
From: Andrew Morton @ 2007-08-22  9:05 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Dan Aloni, linux-kernel, parisc-linux, linux-mm, linux-arch,
	Ollie Wild, Ingo Molnar, Andi Kleen, Alan Cox

On Wed, 22 Aug 2007 10:54:02 +0200 Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:

> Alan proposed this patch:

yeah, I have a great pile of stuff queued for Linus.  I'm bad.  Tomorrow.

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2007-08-22  9:16 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-06-13 10:03 [patch 0/3] no MAX_ARG_PAGES -v2 Peter Zijlstra
2007-06-13 10:03 ` [patch 1/3] arch: personality independent stack top Peter Zijlstra
2007-06-13 10:03 ` [patch 2/3] audit: rework execve audit Peter Zijlstra
2007-06-26 22:55   ` Andrew Morton
2007-07-03 15:00     ` Peter Zijlstra
2007-06-13 10:03 ` [patch 3/3] mm: variable length argument support Peter Zijlstra
2007-08-07 19:03   ` Olaf Hering
2007-08-07 19:20     ` Andrew Morton
2007-08-07 19:26       ` Peter Zijlstra
2007-08-07 20:10       ` Olaf Hering
2007-08-22  8:48   ` Dan Aloni
2007-08-22  8:54     ` Peter Zijlstra
2007-08-22  9:05       ` Andrew Morton
     [not found]     ` <20070822090251.GA7038@mail.ustc.edu.cn>
2007-08-22  9:02       ` Fengguang Wu
2007-06-13 23:36 ` [patch 0/3] no MAX_ARG_PAGES -v2 Luck, Tony
2007-06-14  6:23   ` Ollie Wild
2007-06-14  8:38     ` Peter Zijlstra
2007-06-14 18:22       ` Luck, Tony
2007-06-14 18:32         ` Peter Zijlstra
2007-06-14 20:58       ` Ollie Wild
2007-06-14 21:18         ` Peter Zijlstra
2007-06-15  9:24         ` Peter Zijlstra
2007-06-15 18:07           ` Ollie Wild
2007-06-15 18:49             ` Luck, Tony
2007-06-17 18:32 ` Pavel Machek
2007-06-17 19:07   ` Ingo Molnar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).