Skip to contentSkip to conversation

no MAX_ARG_PAGES

PATCH In review Peter Zijlstra 7 participants 30 messages Jun 5, 2007 – Jun 6, 2007

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

cover no MAX_ARG_PAGES

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.

Tested-on: i386, ia64, frv, parisc, ppc64, um, x86_64

Patches against: .22-rc4

Signature · 20 lines
Changes since last time:

 - fixed ia64
     ( va-space constraints )

 - fixed ia64 CONFIG_IA32_SUPPORT
     ( brown paper bags and more va-space constraints)

 - fixed powerpc
     ( address limit on stack extention )

 - removed audit_kill() in favour of audit_panic()

 - nicely spit out the patches

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#1 lore raw

PATCH 1/4 arch: personality independent stack top

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.

---
 fs/exec.c                    |    2 +-
 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       |    2 ++
 include/asm-x86_64/a.out.h   |    3 ++-
 include/asm-xtensa/a.out.h   |    1 +
 23 files changed, 29 insertions(+), 2 deletions(-)
include/asm-alpha/a.out.h +2 -0
Index: linux-2.6-2/include/asm-alpha/a.out.h
===================================================================
@@ -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__ */
include/asm-arm/a.out.h +1 -0
Index: linux-2.6-2/include/asm-arm/a.out.h
===================================================================
@@ -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
include/asm-arm26/a.out.h +1 -0
Index: linux-2.6-2/include/asm-arm26/a.out.h
===================================================================
@@ -29,6 +29,7 @@ struct exec
 
 #ifdef __KERNEL__
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 #endif
 
 #ifndef LIBRARY_START_TEXT
include/asm-avr32/a.out.h +1 -0
Index: linux-2.6-2/include/asm-avr32/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-cris/a.out.h +1 -0
Index: linux-2.6-2/include/asm-cris/a.out.h
===================================================================
@@ -8,6 +8,7 @@
 
 /* grabbed from the intel stuff  */   
 #define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 
 struct exec
include/asm-frv/mem-layout.h +1 -0
Index: linux-2.6-2/include/asm-frv/mem-layout.h
===================================================================
@@ -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
include/asm-h8300/a.out.h +1 -0
Index: linux-2.6-2/include/asm-h8300/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-i386/a.out.h +1 -0
Index: linux-2.6-2/include/asm-i386/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-ia64/ustack.h +1 -0
Index: linux-2.6-2/include/asm-ia64/ustack.h
===================================================================
@@ -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 */
include/asm-m32r/a.out.h +1 -0
Index: linux-2.6-2/include/asm-m32r/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-m68k/a.out.h +1 -0
Index: linux-2.6-2/include/asm-m68k/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-mips/a.out.h +1 -0
Index: linux-2.6-2/include/asm-mips/a.out.h
===================================================================
@@ -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
 
include/asm-parisc/a.out.h +1 -0
Index: linux-2.6-2/include/asm-parisc/a.out.h
===================================================================
@@ -23,6 +23,7 @@ struct exec
  * prumpf */
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	DEFAULT_TASK_SIZE
 
 #endif
 
include/asm-powerpc/a.out.h +3 -0
Index: linux-2.6-2/include/asm-powerpc/a.out.h
===================================================================
@@ -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__ */
include/asm-s390/a.out.h +1 -0
Index: linux-2.6-2/include/asm-s390/a.out.h
===================================================================
@@ -32,6 +32,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	DEFAULT_TASK_SIZE
 
 #endif
 
include/asm-sh/a.out.h +1 -0
Index: linux-2.6-2/include/asm-sh/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-sh64/a.out.h +1 -0
Index: linux-2.6-2/include/asm-sh64/a.out.h
===================================================================
@@ -31,6 +31,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-sparc/a.out.h +1 -0
Index: linux-2.6-2/include/asm-sparc/a.out.h
===================================================================
@@ -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__ */
 
include/asm-sparc64/a.out.h +2 -0
Index: linux-2.6-2/include/asm-sparc64/a.out.h
===================================================================
@@ -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__) */
include/asm-um/a.out.h +2 -0
Index: linux-2.6-2/include/asm-um/a.out.h
===================================================================
@@ -16,4 +16,6 @@ extern int honeypot;
 #define STACK_TOP \
 	CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
 
+#define STACK_TOP_MAX	STACK_TOP
+
 #endif
include/asm-x86_64/a.out.h +2 -1
Index: linux-2.6-2/include/asm-x86_64/a.out.h
===================================================================
@@ -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__ */
include/asm-xtensa/a.out.h +1 -0
Index: linux-2.6-2/include/asm-xtensa/a.out.h
===================================================================
@@ -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
 {
Signature · 5 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#2 lore raw

PATCH 1/4 arch: personality independent stack top

In reply to Peter Zijlstra

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.

---
 fs/exec.c                    |    2 +-
 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       |    2 ++
 include/asm-x86_64/a.out.h   |    3 ++-
 include/asm-xtensa/a.out.h   |    1 +
 23 files changed, 29 insertions(+), 2 deletions(-)
include/asm-alpha/a.out.h +2 -0
Index: linux-2.6-2/include/asm-alpha/a.out.h
===================================================================
@@ -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__ */
include/asm-arm/a.out.h +1 -0
Index: linux-2.6-2/include/asm-arm/a.out.h
===================================================================
@@ -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
include/asm-arm26/a.out.h +1 -0
Index: linux-2.6-2/include/asm-arm26/a.out.h
===================================================================
@@ -29,6 +29,7 @@ struct exec
 
 #ifdef __KERNEL__
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 #endif
 
 #ifndef LIBRARY_START_TEXT
include/asm-avr32/a.out.h +1 -0
Index: linux-2.6-2/include/asm-avr32/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-cris/a.out.h +1 -0
Index: linux-2.6-2/include/asm-cris/a.out.h
===================================================================
@@ -8,6 +8,7 @@
 
 /* grabbed from the intel stuff  */   
 #define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 
 struct exec
include/asm-frv/mem-layout.h +1 -0
Index: linux-2.6-2/include/asm-frv/mem-layout.h
===================================================================
@@ -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
include/asm-h8300/a.out.h +1 -0
Index: linux-2.6-2/include/asm-h8300/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-i386/a.out.h +1 -0
Index: linux-2.6-2/include/asm-i386/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-ia64/ustack.h +1 -0
Index: linux-2.6-2/include/asm-ia64/ustack.h
===================================================================
@@ -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 */
include/asm-m32r/a.out.h +1 -0
Index: linux-2.6-2/include/asm-m32r/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-m68k/a.out.h +1 -0
Index: linux-2.6-2/include/asm-m68k/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-mips/a.out.h +1 -0
Index: linux-2.6-2/include/asm-mips/a.out.h
===================================================================
@@ -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
 
include/asm-parisc/a.out.h +1 -0
Index: linux-2.6-2/include/asm-parisc/a.out.h
===================================================================
@@ -23,6 +23,7 @@ struct exec
  * prumpf */
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	DEFAULT_TASK_SIZE
 
 #endif
 
include/asm-powerpc/a.out.h +3 -0
Index: linux-2.6-2/include/asm-powerpc/a.out.h
===================================================================
@@ -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__ */
include/asm-s390/a.out.h +1 -0
Index: linux-2.6-2/include/asm-s390/a.out.h
===================================================================
@@ -32,6 +32,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	DEFAULT_TASK_SIZE
 
 #endif
 
include/asm-sh/a.out.h +1 -0
Index: linux-2.6-2/include/asm-sh/a.out.h
===================================================================
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-sh64/a.out.h +1 -0
Index: linux-2.6-2/include/asm-sh64/a.out.h
===================================================================
@@ -31,6 +31,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP	TASK_SIZE
+#define STACK_TOP_MAX	STACK_TOP
 
 #endif
 
include/asm-sparc/a.out.h +1 -0
Index: linux-2.6-2/include/asm-sparc/a.out.h
===================================================================
@@ -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__ */
 
include/asm-sparc64/a.out.h +2 -0
Index: linux-2.6-2/include/asm-sparc64/a.out.h
===================================================================
@@ -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__) */
include/asm-um/a.out.h +2 -0
Index: linux-2.6-2/include/asm-um/a.out.h
===================================================================
@@ -16,4 +16,6 @@ extern int honeypot;
 #define STACK_TOP \
 	CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
 
+#define STACK_TOP_MAX	STACK_TOP
+
 #endif
include/asm-x86_64/a.out.h +2 -1
Index: linux-2.6-2/include/asm-x86_64/a.out.h
===================================================================
@@ -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__ */
include/asm-xtensa/a.out.h +1 -0
Index: linux-2.6-2/include/asm-xtensa/a.out.h
===================================================================
@@ -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
 {
Signature · 4 lines
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#3 lore raw

PATCH 2/4 audit: rework execve audit

In reply to Peter Zijlstra

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.

---
 fs/exec.c               |    3 +
 include/linux/binfmts.h |    1 
 include/linux/sysctl.h  |    1 
 kernel/audit.c          |   16 +++++++++
 kernel/audit.h          |    1 
 kernel/auditsc.c        |   82 ++++++++++++++++++++++++++++++++----------------
 kernel/sysctl.c         |   11 ++++++
 7 files changed, 89 insertions(+), 26 deletions(-)
kernel/auditsc.c +55 -21
Index: linux-2.6-2/kernel/auditsc.c
===================================================================
@@ -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,47 @@ 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;
+	const char __user *p = (const char __user *)axi->mm->arg_start;
+
+	if (axi->mm != current->mm)
+		return; /* execve failed, no additional info */
+
+	for (i = 0; i < axi->argc; i++, p += len) {
+		long ret;
+		char *tmp;
+
+		len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
+		/*
+		 * We just created this mm, if we can't find the strings
+		 * we just copied in something is _very_ wrong.
+		 */
+		BUG_ON(!len);
+
+		tmp = kmalloc(len, GFP_KERNEL);
+		if (!tmp) {
+			audit_panic("out of memory for argv string\n");
+			break;
+		}
+
+		ret = copy_from_user(tmp, p, len);
+		/*
+		 * There is no reason for this copy to be short.
+		 */
+		BUG_ON(ret);
+
+		audit_log_format(ab, "a%d=", i);
+		audit_log_untrustedstring(ab, tmp);
+		audit_log_format(ab, "\n");
+
+		kfree(tmp);
+	}
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
 	int i, call_panic = 0;
@@ -974,13 +1016,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 +1860,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;
fs/exec.c +3 -0
Index: linux-2.6-2/fs/exec.c
===================================================================
@@ -1154,6 +1154,7 @@ int do_execve(char * filename,
 {
 	struct linux_binprm *bprm;
 	struct file *file;
+	unsigned long tmp;
 	int retval;
 	int i;
 
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,
 	if (retval < 0)
 		goto out;
 
+	tmp = bprm->p;
 	retval = copy_strings(bprm->argc, argv, bprm);
 	if (retval < 0)
 		goto out;
+	bprm->argv_len = tmp - bprm->p;
 
 	retval = search_binary_handler(bprm,regs);
 	if (retval >= 0) {
include/linux/binfmts.h +1 -0
Index: linux-2.6-2/include/linux/binfmts.h
===================================================================
@@ -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
kernel/sysctl.c +11 -0
Index: linux-2.6-2/kernel/sysctl.c
===================================================================
@@ -78,6 +78,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;
@@ -615,6 +616,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 }
 };
maintainer
#4 lore raw

Re: [PATCH 2/4] audit: rework execve audit

Quoted 8 lines · On Tue, 05 Jun 2007 17:05:25 +0200 Peter Zijlstra <[email protected]>…

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.

Quoted 9 lines

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.

...

Please try to avoid trigger-happiness with the BUG_ON()s..

Quoted 27 lines

struct audit_aux_data_socketcall {

(quoted diff) +22 -0
@@ -834,6 +834,47 @@ 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;
+	const char __user *p = (const char __user *)axi->mm->arg_start;
+
+	if (axi->mm != current->mm)
+		return; /* execve failed, no additional info */
+
+	for (i = 0; i < axi->argc; i++, p += len) {
+		long ret;
+		char *tmp;
+
+		len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
+		/*
+		 * We just created this mm, if we can't find the strings
+		 * we just copied in something is _very_ wrong.
+		 */
+		BUG_ON(!len);
+
+		tmp = kmalloc(len, GFP_KERNEL);

Review static int audit_log_pid_context(struct · line 868

Quoted 10 lines
(quoted diff) +10 -0
+		if (!tmp) {
+			audit_panic("out of memory for argv string\n");
+			break;
+		}
+
+		ret = copy_from_user(tmp, p, len);
+		/*
+		 * There is no reason for this copy to be short.
+		 */
+		BUG_ON(ret);

You sure? What happens if another thread does munmap() in parallel?

I think I'll make this WARN_ON just out of principle.

Quoted 23 lines
(quoted diff) +8 -0
+		audit_log_format(ab, "a%d=", i);
+		audit_log_untrustedstring(ab, tmp);
+		audit_log_format(ab, "\n");
+
+		kfree(tmp);
+	}
+}
+
 
...

===================================================================

fs/exec.c +1 -0
@@ -1154,6 +1154,7 @@ int do_execve(char * filename,
 {
 	struct linux_binprm *bprm;
 	struct file *file;
+	unsigned long tmp;
 	int retval;
 	int i;
 

fs/exec.c int do_execve(char * filename, · line 1216

Quoted 8 lines
fs/exec.c +2 -0
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,
 	if (retval < 0)
 		goto out;
 
+	tmp = bprm->p;
 	retval = copy_strings(bprm->argc, argv, bprm);
 	if (retval < 0)
 		goto out;
+	bprm->argv_len = tmp - bprm->p;
include/linux/kernel.h renamed from include/linux/kernel.h~a +2 -0
@@ -5,6 +5,8 @@
  * 'kernel.h' contains some often-used function prototypes etc
  */
 
+#define tmp don't call your variables tmp!
+
 #ifdef __KERNEL__
 
 #include <stdarg.h>

_

#5 lore raw

Re: [PATCH 2/4] audit: rework execve audit

Quoted 63 lines · Andrew Morton
Quoted 8 lines · On Tue, 05 Jun 2007 17:05:25 +0200 Peter Zijlstra <[email protected]>…

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.

Quoted 9 lines

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.

...

Please try to avoid trigger-happiness with the BUG_ON()s..

Quoted 27 lines

struct audit_aux_data_socketcall {

(quoted diff) +22 -0
@@ -834,6 +834,47 @@ 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;
+	const char __user *p = (const char __user *)axi->mm->arg_start;
+
+	if (axi->mm != current->mm)
+		return; /* execve failed, no additional info */
+
+	for (i = 0; i < axi->argc; i++, p += len) {
+		long ret;
+		char *tmp;
+
+		len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
+		/*
+		 * We just created this mm, if we can't find the strings
+		 * we just copied in something is _very_ wrong.
+		 */
+		BUG_ON(!len);
+
+		tmp = kmalloc(len, GFP_KERNEL);

Review static int audit_log_pid_context(struct · line 868

Quoted 10 lines
(quoted diff) +10 -0
+		if (!tmp) {
+			audit_panic("out of memory for argv string\n");
+			break;
+		}
+
+		ret = copy_from_user(tmp, p, len);
+		/*
+		 * There is no reason for this copy to be short.
+		 */
+		BUG_ON(ret);

You sure? What happens if another thread does munmap() in parallel?

Quoted 1 line

I think I'll make this WARN_ON just out of principle.

This is right after the execve call, and before we've hit userspace, so at this time there is no runnable context with access to the memory (except this one).

Quoted 17 lines
Quoted 9 lines
(quoted diff) +2 -0
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,
 	if (retval < 0)
 		goto out;
 
+	tmp = bprm->p;
 	retval = copy_strings(bprm->argc, argv, bprm);
 	if (retval < 0)
 		goto out;
+	bprm->argv_len = tmp - bprm->p;

include/linux/kernel.h line 12

Quoted 8 lines
include/linux/kernel.h renamed from include/linux/kernel.h~a +2 -0
@@ -5,6 +5,8 @@
  * 'kernel.h' contains some often-used function prototypes etc
  */
 
+#define tmp don't call your variables tmp!
+
 #ifdef __KERNEL__
 
 #include <stdarg.h>

Fair enough. :-/

#6 lore raw

PATCH 2/4 audit: rework execve audit

In reply to Peter Zijlstra

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.

---
 fs/exec.c               |    3 +
 include/linux/binfmts.h |    1 
 include/linux/sysctl.h  |    1 
 kernel/audit.c          |   16 +++++++++
 kernel/audit.h          |    1 
 kernel/auditsc.c        |   82 ++++++++++++++++++++++++++++++++----------------
 kernel/sysctl.c         |   11 ++++++
 7 files changed, 89 insertions(+), 26 deletions(-)
kernel/auditsc.c +55 -21
Index: linux-2.6-2/kernel/auditsc.c
===================================================================
@@ -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,47 @@ 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;
+	const char __user *p = (const char __user *)axi->mm->arg_start;
+
+	if (axi->mm != current->mm)
+		return; /* execve failed, no additional info */
+
+	for (i = 0; i < axi->argc; i++, p += len) {
+		long ret;
+		char *tmp;
+
+		len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
+		/*
+		 * We just created this mm, if we can't find the strings
+		 * we just copied in something is _very_ wrong.
+		 */
+		BUG_ON(!len);
+
+		tmp = kmalloc(len, GFP_KERNEL);
+		if (!tmp) {
+			audit_panic("out of memory for argv string\n");
+			break;
+		}
+
+		ret = copy_from_user(tmp, p, len);
+		/*
+		 * There is no reason for this copy to be short.
+		 */
+		BUG_ON(ret);
+
+		audit_log_format(ab, "a%d=", i);
+		audit_log_untrustedstring(ab, tmp);
+		audit_log_format(ab, "\n");
+
+		kfree(tmp);
+	}
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
 	int i, call_panic = 0;
@@ -974,13 +1016,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 +1860,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;
fs/exec.c +3 -0
Index: linux-2.6-2/fs/exec.c
===================================================================
@@ -1154,6 +1154,7 @@ int do_execve(char * filename,
 {
 	struct linux_binprm *bprm;
 	struct file *file;
+	unsigned long tmp;
 	int retval;
 	int i;
 
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,
 	if (retval < 0)
 		goto out;
 
+	tmp = bprm->p;
 	retval = copy_strings(bprm->argc, argv, bprm);
 	if (retval < 0)
 		goto out;
+	bprm->argv_len = tmp - bprm->p;
 
 	retval = search_binary_handler(bprm,regs);
 	if (retval >= 0) {
include/linux/binfmts.h +1 -0
Index: linux-2.6-2/include/linux/binfmts.h
===================================================================
@@ -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
kernel/sysctl.c +11 -0
Index: linux-2.6-2/kernel/sysctl.c
===================================================================
@@ -78,6 +78,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;
@@ -615,6 +616,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 }
 };
Signature · 4 lines
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#7 lore raw

PATCH 3/4 mm: move_page_tables{,_up}

In reply to Peter Zijlstra

Provide functions for moving page tables upwards.

---
 include/linux/mm.h |    7 +++
 mm/mremap.c        |  105 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 110 insertions(+), 2 deletions(-)
include/linux/mm.h +6 -0
Index: linux-2.6-2/include/linux/mm.h
===================================================================
@@ -788,6 +787,12 @@ 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 move_page_tables_up(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);
mm/mremap.c +104 -1

140 lines not on this page · raw message

Signature · 5 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#8 lore raw

Re: [PATCH 3/4] mm: move_page_tables{,_up}

Quoted 1 line · Peter Zijlstra

Provide functions for moving page tables upwards.

Could you make this more general so that it allows arbitrary page table pages moving? That would be useful for Mel's memory defragmentation since it increases the types of pages that can be moved.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#9 lore raw

Re: [PATCH 3/4] mm: move_page_tables{,_up}

In reply to Peter Zijlstra

include/linux/mm.h int FASTCALL(set_page_dirty(struct page · line 798

Quoted 13 lines · On Tue, 05 Jun 2007 17:05:26 +0200 Peter Zijlstra <[email protected]>…

Provide functions for moving page tables upwards.

...

include/linux/mm.h +6 -0
+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 move_page_tables_up(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);

They become kernel-wide

mm/mremap.c static void move_ptes(struct vm_area_str · line 124

Quoted 4 lines
mm/mremap.c +4 -0
+static void move_ptes_up(struct vm_area_struct *vma, pmd_t *old_pmd,
+		unsigned long old_addr, unsigned long old_end,
+		struct vm_area_struct *new_vma, pmd_t *new_pmd,
+		unsigned long new_addr)

So some documentation might be in order...

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#10 lore raw

Re: [PATCH 3/4] mm: move_page_tables{,_up}

In reply to Peter Zijlstra
Quoted 1 line · Peter Zijlstra

Provide functions for moving page tables upwards.

Now that we're initializing the temporary stack location to STACK_TOP_MAX, do we still need move_page_tables_up() for variable length argument support? I originally added it into shift_arg_pages() to support 32-bit apps exec'ing 64-bit apps when we were using TASK_SIZE as our temporary location.

Maybe we should decouple this patch from the others and submit it as an enhancement to support memory defragmentation.

Ollie

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#11 lore raw

Re: [PATCH 3/4] mm: move_page_tables{,_up}

Quoted 11 lines · Ollie Wild
Quoted 1 line · Peter Zijlstra

Provide functions for moving page tables upwards.

Now that we're initializing the temporary stack location to STACK_TOP_MAX, do we still need move_page_tables_up() for variable length argument support? I originally added it into shift_arg_pages() to support 32-bit apps exec'ing 64-bit apps when we were using TASK_SIZE as our temporary location.

Maybe we should decouple this patch from the others and submit it as an enhancement to support memory defragmentation.

PA-RISC will still need it, right?

On the defrag thingy, I talked with Mel today, and neither of us can see a usefull application of these functions to his defrag work.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#12 lore raw

Re: [PATCH 3/4] mm: move_page_tables{,_up}

Quoted 1 line · Peter Zijlstra

PA-RISC will still need it, right?

Originally, I thought since the PA-RISC stack grows up, we'd want to place the stack at the bottom of memory and have copy_strings() and friends work in the opposite direction. It turns out, though, that this ends up being way more headache than it's worth, so I just manually grow the stack down with expand_downwards().

Ollie

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#13 lore raw

Re: [PATCH 3/4] mm: move_page_tables{,_up}

Quoted 8 lines · Ollie Wild
Quoted 1 line · Peter Zijlstra

PA-RISC will still need it, right?

Originally, I thought since the PA-RISC stack grows up, we'd want to place the stack at the bottom of memory and have copy_strings() and friends work in the opposite direction. It turns out, though, that this ends up being way more headache than it's worth, so I just manually grow the stack down with expand_downwards().

Ah, ok. I'll drop this whole patch then.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#14 lore raw

PATCH 3/4 mm: move_page_tables{,_up}

In reply to Peter Zijlstra

Provide functions for moving page tables upwards.

---
 include/linux/mm.h |    7 +++
 mm/mremap.c        |  105 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 110 insertions(+), 2 deletions(-)
include/linux/mm.h +6 -0
Index: linux-2.6-2/include/linux/mm.h
===================================================================
@@ -788,6 +787,12 @@ 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 move_page_tables_up(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);
mm/mremap.c +104 -1

140 lines not on this page · raw message

Signature · 4 lines
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#15 lore raw

PATCH 4/4 mm: variable length argument support

In reply to Peter Zijlstra

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.

---
 arch/ia64/ia32/binfmt_elf32.c     |   61 ----
 arch/um/kernel/trap.c             |    2 
 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                       |  130 +++-----
 fs/exec.c                         |  566 +++++++++++++++++++++++---------------
 include/asm-um/processor-i386.h   |    3 
 include/asm-um/processor-x86_64.h |    3 
 include/linux/binfmts.h           |   17 -
 include/linux/mm.h                |    7 
 kernel/auditsc.c                  |    2 
 mm/mmap.c                         |   56 ++-
 mm/mprotect.c                     |    2 
 17 files changed, 495 insertions(+), 458 deletions(-)
arch/um/kernel/trap.c +0 -2
Index: linux-2.6-2/arch/um/kernel/trap.c
===================================================================
@@ -61,8 +61,6 @@ int handle_page_fault(unsigned long addr
 		goto good_area;
 	else if(!(vma->vm_flags & VM_GROWSDOWN))
 		goto out;
-	else if(is_user && !ARCH_IS_STACKGROW(address))
-		goto out;
 	else if(expand_stack(vma, address))
 		goto out;
 
arch/x86_64/ia32/ia32_binfmt.c +0 -58

70 lines not on this page · raw message

fs/binfmt_elf.c +19 -9
Index: linux-2.6-2/fs/binfmt_elf.c
===================================================================
@@ -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;
 	}
@@ -777,10 +787,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;
 
@@ -988,9 +994,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;
fs/binfmt_elf_fdpic.c +4 -4
Index: linux-2.6-2/fs/binfmt_elf_fdpic.c
===================================================================
@@ -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;
 	}
fs/binfmt_misc.c +3 -1
Index: linux-2.6-2/fs/binfmt_misc.c
===================================================================
@@ -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) {
fs/binfmt_script.c +3 -1
Index: linux-2.6-2/fs/binfmt_script.c
===================================================================
@@ -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++;
fs/compat.c +54 -76

212 lines not on this page · raw message

fs/exec.c +350 -216

739 lines not on this page · raw message

include/asm-um/processor-i386.h +0 -3
Index: linux-2.6-2/include/asm-um/processor-i386.h
===================================================================
@@ -67,9 +67,6 @@ static inline void rep_nop(void)
 #define current_text_addr() \
 	({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
 
-#define ARCH_IS_STACKGROW(address) \
-       (address + 32 >= UPT_SP(&current->thread.regs.regs))
-
 #define KSTK_EIP(tsk) KSTK_REG(tsk, EIP)
 #define KSTK_ESP(tsk) KSTK_REG(tsk, UESP)
 #define KSTK_EBP(tsk) KSTK_REG(tsk, EBP)
include/asm-um/processor-x86_64.h +0 -3
Index: linux-2.6-2/include/asm-um/processor-x86_64.h
===================================================================
@@ -44,9 +44,6 @@ static inline void arch_copy_thread(stru
 #define current_text_addr() \
 	({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; })
 
-#define ARCH_IS_STACKGROW(address) \
-        (address + 128 >= UPT_SP(&current->thread.regs.regs))
-
 #define KSTK_EIP(tsk) KSTK_REG(tsk, RIP)
 #define KSTK_ESP(tsk) KSTK_REG(tsk, RSP)
 
include/linux/binfmts.h +10 -7
Index: linux-2.6-2/include/linux/binfmts.h
===================================================================
@@ -5,12 +5,9 @@
 
 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!
- */
-#define MAX_ARG_PAGES 32
+/* FIXME: Find real limits, or none. */
+#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF
 
 /* sizeof(linux_binprm->buf) */
 #define BINPRM_BUF_SIZE 128
@@ -24,7 +21,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 +71,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 +88,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);
include/linux/mm.h +6 -1
Index: linux-2.6-2/include/linux/mm.h
===================================================================
@@ -786,7 +786,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);
@@ -812,6 +811,9 @@ extern unsigned long move_page_tables_up
 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);
 
 /*
  * Prototype to add a shrinker callback for ageable caches.
@@ -1130,6 +1132,9 @@ extern int expand_stack(struct vm_area_s
 #ifdef CONFIG_IA64
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #endif
+#ifdef CONFIG_STACK_GROWSUP
+extern int expand_downwards(struct vm_area_struct *vma, unsigned long address);
+#endif
 
 /* 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);
mm/mmap.c +32 -24

71 lines not on this page · raw message

mm/mprotect.c +1 -1
Index: linux-2.6-2/mm/mprotect.c
===================================================================
@@ -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)
 {
arch/ia64/ia32/binfmt_elf32.c +11 -50

73 lines not on this page · raw message

arch/x86_64/ia32/ia32_aout.c +1 -1
Index: linux-2.6-2/arch/x86_64/ia32/ia32_aout.c
===================================================================
@@ -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); 
kernel/auditsc.c +1 -1
Index: linux-2.6-2/kernel/auditsc.c
===================================================================
@@ -848,7 +848,7 @@ static void audit_log_execve_info(struct
 		long ret;
 		char *tmp;
 
-		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 in something is _very_ wrong.
Signature · 5 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
maintainer
#16 lore raw

Re: [PATCH 4/4] mm: variable length argument support

Quoted 44 lines · On Tue, 05 Jun 2007 17:05:27 +0200 Peter Zijlstra <[email protected]>…

From: Ollie Wild <[email protected]>

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.

..

Index: linux-2.6-2/fs/binfmt_elf.c
===================================================================

fs/binfmt_elf.c +10 -0
@@ -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;

fs/binfmt_elf.c create_elf_tables(struct linux_binprm *b · line 268

Quoted 7 lines
fs/binfmt_elf.c +2 -2
@@ -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)

strnlen_user() is a scary function. Please do remember that if the memory we just strlen'ed is writeable by any user thread then that thread can at any time invalidate the number which the kernel now holds.

Quoted 34 lines
fs/binfmt_elf.c +2 -2
 			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;
 	}
 
...

Index: linux-2.6-2/fs/compat.c
===================================================================

fs/compat.c +1 -1
@@ -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))) {

fs/compat.c static int compat_copy_strings(int argc, · line 1277

Quoted 10 lines
fs/compat.c +2 -1
+		    !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
 			ret = -EFAULT;
 			goto out;
 		}
 
-		if (bprm->p < len)  {
+		if (MAX_ARG_STRLEN < len) {
 			ret = -E2BIG;
 			goto out;
 		}

Do we have an off-by-one here? Should it be <=?

If not, then this code is relying upon the string's terminating \0 coming from userspace? If so, that's buggy: userspace can overwrite the \0 after we ran the strnlen_user(), perhaps, and confound the kernel?

I could be complete crap, but please check all this very closely.

Quoted 9 lines
fs/compat.c +9 -0
+/*
+ * 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;

fs/compat.c static int compat_copy_strings(int argc, · line 1296

Quoted 10 lines
fs/compat.c +10 -0
+	struct mm_struct *mm = NULL;
+	struct vm_area_struct *vma = NULL;
+
+	bprm->mm = mm = mm_alloc();
+	err = -ENOMEM;
+	if (!mm)
+		goto err;
+
+	if ((err = init_new_context(current, mm)))
+		goto err;
	err = init_new_context(current, mm));
	if (err)
		goto err;

fs/compat.c static int compat_copy_strings(int argc, · line 1305

Quoted 9 lines
fs/compat.c +9 -0
+#ifdef CONFIG_MMU
+	bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+	err = -ENOMEM;
+	if (!vma)
+		goto err;
+
+	down_write(&mm->mmap_sem);
+	{
+		vma->vm_mm = mm;

Let's lose the unneeded brace and indent here?

Quoted 34 lines
fs/compat.c +34 -0
+		/*
+		 * Place the stack at the top of user memory.  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];
+		if ((err = insert_vm_struct(mm, vma))) {
+			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 *);
+#else
+	bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *);
+#endif
+
+	return 0;
+
+err:
+#ifdef CONFIG_MMU
+	if (vma) {
+		bprm->vma = NULL;
+		kmem_cache_free(vm_area_cachep, vma);
+	}
+#endif

fs/compat.c static int compat_copy_strings(int argc, · line 1349

Quoted 10 lines
fs/compat.c +10 -0
+
+	if (mm) {
+		bprm->mm = NULL;
+		mmdrop(mm);
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL(bprm_mm_init);

Preferred style is to have zero blank lines between the ^}$ and the EXPORT_SYMBOL().

Quoted 23 lines
fs/compat.c +5 -4
 /*
- * '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 +373,77 @@ 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))) {

fs/compat.c static int copy_strings(int argc, char _ · line 385

Quoted 10 lines
fs/compat.c +5 -1
 			ret = -EFAULT;
 			goto out;
 		}
 
-		if (bprm->p < len)  {
+#ifdef CONFIG_MMU
+		if (MAX_ARG_STRLEN < len) {
+			ret = -E2BIG;
+			goto out;
+		}

strnlen_user() scariness. Please check for off-by-ones.

Quoted 13 lines
fs/compat.c +3 -1
+#else
+		if (bprm->p < len) {
 			ret = -E2BIG;
 			goto out;
 		}
+#endif
 
...
 
 EXPORT_SYMBOL(copy_strings_kernel);
 
 #ifdef CONFIG_MMU
-/*

fs/compat.c static int copy_strings(int argc, char _

Quoted 10 lines
fs/compat.c +2 -7
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
- *
- * vma->vm_mm->mmap_sem is held for writing.
- */
-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)
 {

Needs a comment explaining why it exists, what it does, how it does it. For maintainability.

Quoted 8 lines
fs/compat.c +5 -2
 	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;

fs/compat.c

Quoted 10 lines
fs/compat.c +10 -0
+	struct mmu_gather *tlb;
+
+	BUG_ON(new_start > new_end);
+
+	if (new_start < old_start) {
+		if (vma != find_vma(mm, new_start))
+			return -EFAULT;
+
+		vma_adjust(vma, new_start, old_end,
+			   vma->vm_pgoff - (-shift >> PAGE_SHIFT), NULL);

hm, a right-shift of a negated unsigned value. That's pretty unusual. I hope you know what you're doing ;)

Quoted 20 lines
fs/compat.c +16 -2
+		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)
+			free_pgd_range(&tlb, new_end, old_end, new_end,
+				vma->vm_next ? vma->vm_next->vm_start : 0);
+		else
+			free_pgd_range(&tlb, old_start, old_end, new_end,
+				vma->vm_next ? vma->vm_next->vm_start : 0);
+		tlb_finish_mmu(tlb, new_end, old_end);
 
-	if (unlikely(anon_vma_prepare(vma)))
-		goto out;
+		vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL);
+	} else {
+		struct vm_area_struct *tmp, *prev;
 

fs/compat.c

Quoted 10 lines
fs/compat.c +3 -7
-	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;
+		tmp = find_vma_prev(mm, new_end, &prev);
+		if ((tmp && tmp->vm_start < new_end) || prev != vma)
+			return -EFAULT;

This reader is all lost. Perhaps a few comments explaining what tests like the above are doing would help him regain his bearings.

Not having an overall description of what this code is doing doesn't help.

Quoted 27 lines
fs/compat.c +16 -9
+		find_vma_prev(mm, vma->vm_start, &prev);
+
+		vma_adjust(vma, old_start, new_end, vma->vm_pgoff, NULL);
+
+		if (length != move_page_tables_up(vma, old_start,
+					       vma, new_start, length))
+			return -ENOMEM;
+
+		lru_add_drain();
+		tlb = tlb_gather_mmu(mm, 0);
+		free_pgd_range(&tlb, old_start, new_start,
+			       prev ? prev->vm_end: 0, new_start);
+		tlb_finish_mmu(tlb, old_start, new_start);
+
+		vma_adjust(vma, new_start, new_end,
+			   vma->vm_pgoff + (shift >> PAGE_SHIFT), NULL);
 	}
-	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);
 
-	/* no need for flush_tlb */
-	return;
-out:

fs/compat.c

Quoted 10 lines
fs/compat.c +4 -2
-	__free_page(page);
-	force_sig(SIGKILL, current);
+	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.
+ */

That's better.

But what extra space is added, and why?

Quoted 59 lines

int setup_arg_pages(struct linux_binprm *bprm,

fs/compat.c +7 -38
 		    unsigned long stack_top,
 		    int executable_stack)
 {
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
+	unsigned long ret;
+	unsigned long stack_base, stack_shift;
 	struct mm_struct *mm = current->mm;
-	int i, ret;
-	long arg_size;
+	struct vm_area_struct *vma = bprm->vma;
 
 #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 */

fs/compat.c

Quoted 10 lines
fs/compat.c +4 -5
-	while (i < MAX_ARG_PAGES)
-		bprm->page[i++] = NULL;
+	stack_shift = stack_base - vma->vm_start;
+	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;
+	BUG_ON(stack_top & ~PAGE_MASK);

Is there much point in this BUG_ON, given that we're about to align stack_top anyway?

Quoted 50 lines
fs/compat.c +14 -24
+	stack_top = arch_align_stack(stack_top);
+	stack_top = PAGE_ALIGN(stack_top);
+	stack_shift = stack_top - vma->vm_end;
+
+	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
+		struct vm_area_struct *prev = NULL;
+		unsigned long 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))
-			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
+			vm_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 &= ~VM_EXEC;
+		vm_flags |= mm->def_flags;
+

fs/compat.c

Quoted 10 lines
fs/compat.c +4 -3
+		ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
+				vm_flags);
+		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);
-	}
+		BUG_ON(prev != vma);

:(

Quoted 39 lines
fs/compat.c +21 -6
-	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);
+		/* Move stack pages down in memory. */
+		if (stack_shift) {
+			ret = shift_arg_pages(vma, stack_shift);
+			if (ret) {
+				up_write(&mm->mmap_sem);
+				return ret;
+			}
+		}
+
+#ifdef CONFIG_STACK_GROWSUP
+		if (expand_stack(vma, vma->vm_end +
+					EXTRA_STACK_VM_PAGES * PAGE_SIZE)) {
+			up_write(&mm->mmap_sem);
+			return -EFAULT;
+		}
+#else
+		if (expand_stack(vma, vma->vm_start -
+					EXTRA_STACK_VM_PAGES * PAGE_SIZE)) {
+			up_write(&mm->mmap_sem);
+			return -EFAULT;
 		}
-		stack_base += PAGE_SIZE;
+#endif
 	}
 
...

Index: linux-2.6-2/include/linux/binfmts.h
===================================================================

include/linux/binfmts.h +0 -0
@@ -5,12 +5,9 @@
 
 struct pt_regs;

include/linux/binfmts.h line 10

Quoted 10 lines
include/linux/binfmts.h +3 -6
 
-/*
- * 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!
- */
-#define MAX_ARG_PAGES 32
+/* FIXME: Find real limits, or none. */
+#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF

DOCUMENTME!

include/linux/binfmts.h struct pt_regs;

Quoted 10 lines
include/linux/binfmts.h +3 -0
 /* sizeof(linux_binprm->buf) */
 #define BINPRM_BUF_SIZE 128
@@ -24,7 +21,12 @@ struct pt_regs;
  */
 
...
 
+#ifdef CONFIG_STACK_GROWSUP
+extern int expand_downwards(struct vm_area_struct *vma, unsigned long address);
+#endif

We don't (or shouldn't) need the ifdefs here.

Quoted 6 lines
include/linux/binfmts.h +0 -6
-		return NULL;
-	if (prev->vm_flags & VM_LOCKED) {
-		make_pages_present(addr, prev->vm_end);
-	}
-	return prev;
-}

include/linux/binfmts.h

Quoted 10 lines
include/linux/binfmts.h +4 -2
-#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)
+#ifndef CONFIG_STACK_GROWSUP
+static inline
+#endif
+int expand_downwards(struct vm_area_struct *vma, unsigned long address)
 {

eww, that was a bit rude.

Can we just leave this as static int then do

int expand_stack_downwards(....)

?

That's a better name anyway.

Quoted 16 lines
include/linux/binfmts.h +10 -0
 	int error;
@@ -1620,6 +1600,34 @@ int expand_stack(struct vm_area_struct *
 	return error;
 }
 
+#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;

include/linux/binfmts.h int expand_stack(struct vm_area_struct * · line 1622

Quoted 10 lines
include/linux/binfmts.h +10 -0
+
+	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);
+	}

unneeded braces

We really should check and propagate the make_pages_present() return value when appropriate. It can fail under -ENOMEM, ulimit exceeded, overcommit, etc.

Quoted 29 lines
include/linux/binfmts.h +8 -0
+	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)
 {

Index: linux-2.6-2/mm/mprotect.c
===================================================================

mm/mprotect.c +1 -1
@@ -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
===================================================================

arch/ia64/ia32/binfmt_elf32.c ia64_elf32_init (struct pt_regs *regs) · line 198

Quoted 4 lines
arch/ia64/ia32/binfmt_elf32.c +1 -0
@@ -195,62 +195,23 @@ ia64_elf32_init (struct pt_regs *regs)
 	ia32_load_state(current);
 }
 
+#undef setup_arg_pages

What's this for?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#17 lore raw

Re: [PATCH 4/4] mm: variable length argument support

OK. It sounds like a healthy dose of comments is in order. I'll clean things up and send out a new patch sometime tonight or tomorrow.

Additional comments inline below:

Quoted 8 lines

fs/binfmt_elf.c create_elf_tables(struct linux_binprm *b · line 268

Quoted 4 lines
fs/binfmt_elf.c +2 -2
-             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)

strnlen_user() is a scary function. Please do remember that if the memory we just strlen'ed is writeable by any user thread then that thread can at any time invalidate the number which the kernel now holds.

At this point, we've already called setup_arg_pages(), so the user memory is our own private copy. No other threads can access it.

Quoted 6 lines
Quoted 6 lines
fs/compat.c +1 -1
-                     !(len = strnlen_user(compat_ptr(str), bprm->p))) {
+                 !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
                      ret = -EFAULT;
                      goto out;
              }
Quoted 7 lines

fs/compat.c static int compat_copy_strings(int argc, · line 1277

Quoted 5 lines
fs/compat.c +1 -1
-             if (bprm->p < len)  {
+             if (MAX_ARG_STRLEN < len) {
                      ret = -E2BIG;
                      goto out;
              }

Do we have an off-by-one here? Should it be <=?

No, strnlen_user() returns N+1 (where N==MAX_ARG_STRLEN) if the string is too large.

Quoted 3 lines

If not, then this code is relying upon the string's terminating \0 coming from userspace? If so, that's buggy: userspace can overwrite the \0 after we ran the strnlen_user(), perhaps, and confound the kernel?

If that's the case, then we will fail to copy the null terminator, and the string will munge into the following string. Since we always access this data via the various userspace access routines, we will either return an error on a later operation, or the new process will segfault shortly upon starting.

Quoted 5 lines

fs/exec.c int copy_strings_kernel(int argc,char ** · line 484

Quoted 2 lines
fs/exec.c +2 -0
+             vma_adjust(vma, new_start, old_end,
+                        vma->vm_pgoff - (-shift >> PAGE_SHIFT), NULL);

hm, a right-shift of a negated unsigned value. That's pretty unusual. I hope you know what you're doing ;)

This is correct. In this case, shift is already populated with a negative, wrapped unsigned value. The -shift is needed to make it positive before the bitwise shift.

Quoted 9 lines
Quoted 5 lines

#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.
+ */

That's better.

But what extra space is added, and why?

We add EXTRA_STACK_VM_PAGES. To be honest, I think neither of us know why this is done. It's just what the old code did, so we preserved it.

Ollie

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#18 lore raw

Re: [PATCH 4/4] mm: variable length argument support

In reply to Andrew Morton
Quoted 27 lines · Andrew Morton
Quoted 14 lines
mm/mmap.c +10 -0
@@ -1620,6 +1600,34 @@ int expand_stack(struct vm_area_struct *
 	return error;
 }
 
+#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;

mm/mmap.c int expand_stack(struct vm_area_struct * · line 1622

Quoted 10 lines
mm/mmap.c +10 -0
+
+	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);
+	}

unneeded braces

Quoted 3 lines

We really should check and propagate the make_pages_present() return value when appropriate. It can fail under -ENOMEM, ulimit exceeded, overcommit, etc.

Right, this is not new ugliness, but indeed a good opportunity to clean up.

Quoted 32 lines
Quoted 32 lines
mm/mmap.c +8 -0
+	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)
 {

Index: linux-2.6-2/mm/mprotect.c
===================================================================

mm/mprotect.c +1 -1
@@ -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
===================================================================

arch/ia64/ia32/binfmt_elf32.c +0 -0
@@ -195,62 +195,23 @@ ia64_elf32_init (struct pt_regs *regs)
 	ia32_load_state(current);
 }
 
Quoted 3 lines

arch/ia64/ia32/binfmt_elf32.c ia64_elf32_init (struct pt_regs *regs) · line 198

Quoted 1 line
arch/ia64/ia32/binfmt_elf32.c +1 -0
+#undef setup_arg_pages

What's this for?

That file reads:

#define setup_arg_pages(bprm,tos,exec) ia32_setup_arg_pages(bprm,exec)

....

#include "../../../fs/binfmt_elf.c"

....

int
ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)

{
        int ret;

        ret = setup_arg_pages(bprm, IA32_STACK_TOP, executable_stack);

/---------------^
We really want to call the real setup_arg_pages() here, not ourselves please.

        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();
        }

        return ret;
}

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#19 lore raw

Re: [PATCH 4/4] mm: variable length argument support

In reply to Peter Zijlstra
Quoted 14 lines · On Tue, 05 Jun 2007 17:05:27 +0200 Peter Zijlstra <[email protected]>…

From: Ollie Wild <[email protected]>

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.

...

Review

Quoted 2 lines
(quoted diff) +2 -0
+				flush_cache_page(bprm->vma, kpos,
+						 page_to_pfn(kmapped_page));

Breaks SuperH:

fs/exec.c: In function `bprm_mm_init':
fs/exec.c:268: warning: unused variable vma' fs/exec.c: In function copy_strings':
fs/exec.c:431: error: structure has no member named `vma'

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#20 lore raw

Re: [PATCH 4/4] mm: variable length argument support

Quoted 21 lines · Andrew Morton
Quoted 14 lines · On Tue, 05 Jun 2007 17:05:27 +0200 Peter Zijlstra <[email protected]>…

From: Ollie Wild <[email protected]>

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.

...

Review

Quoted 2 lines
(quoted diff) +2 -0
+				flush_cache_page(bprm->vma, kpos,
+						 page_to_pfn(kmapped_page));

Breaks SuperH:

Quoted 5 lines

fs/exec.c: In function `bprm_mm_init':
fs/exec.c:268: warning: unused variable vma' fs/exec.c: In function copy_strings':
fs/exec.c:431: error: structure has no member named `vma'

More pointedly, bprm->vma doesn't exist if CONFIG_MMU=n, which Andrew's config seems to have ;-)

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#21 lore raw

Re: [PATCH 4/4] mm: variable length argument support

In reply to Andrew Morton
Quoted 11 lines · Andrew Morton
Quoted 9 lines · On Tue, 05 Jun 2007 17:05:27 +0200 Peter Zijlstra <[email protected]>…

From: Ollie Wild <[email protected]>

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.

Quoted 7 lines

Review

Quoted 7 lines

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

...

(quoted diff) +2 -0
+				flush_cache_page(bprm->vma, kpos,
+						 page_to_pfn(kmapped_page));

Bah, and my frv cross build bums out on an unrelated change,.. I'll see if I can get a noMMU arch building, in the mean time, would you try this:

---

Since no-MMU doesn't do the fancy inactive mm access there is no need to flush cache.

---

fs/exec.c +2 -0
Index: linux-2.6-2/fs/exec.c
===================================================================
@@ -428,8 +428,10 @@ static int copy_strings(int argc, char _
 				kmapped_page = page;
 				kaddr = kmap(kmapped_page);
 				kpos = pos & PAGE_MASK;
+#ifdef CONFIG_MMU
 				flush_cache_page(bprm->vma, kpos,
 						 page_to_pfn(kmapped_page));
+#endif
 			}
 			if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
 				ret = -EFAULT;

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#22 lore raw

Re: [PATCH 4/4] mm: variable length argument support

Quoted 26 lines · On Wed, 06 Jun 2007 10:54:21 +0200 Peter Zijlstra <[email protected]>…
Quoted 7 lines

Review

Quoted 7 lines

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

...

(quoted diff) +2 -0
+				flush_cache_page(bprm->vma, kpos,
+						 page_to_pfn(kmapped_page));

Bah, and my frv cross build bums out on an unrelated change,.. I'll see if I can get a noMMU arch building, in the mean time, would you try this:

---

Since no-MMU doesn't do the fancy inactive mm access there is no need to flush cache.

---

Index: linux-2.6-2/fs/exec.c
===================================================================

fs/exec.c static int copy_strings(int argc, char _ · line 437

Quoted 10 lines
fs/exec.c +2 -0
@@ -428,8 +428,10 @@ static int copy_strings(int argc, char _
 				kmapped_page = page;
 				kaddr = kmap(kmapped_page);
 				kpos = pos & PAGE_MASK;
+#ifdef CONFIG_MMU
 				flush_cache_page(bprm->vma, kpos,
 						 page_to_pfn(kmapped_page));
+#endif
 			}
 			if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
 				ret = -EFAULT;

I think the same problem will happen on NOMMU && STACK_GROWS_UP. There are several new references to bprm->vma in there, not all inside CONFIG_MMU.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#23 lore raw

Re: [PATCH 4/4] mm: variable length argument support

Quoted 33 lines · Andrew Morton
Quoted 31 lines · On Wed, 06 Jun 2007 10:54:21 +0200 Peter Zijlstra <[email protected]>…
Quoted 7 lines

Review

Quoted 7 lines

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

...

(quoted diff) +2 -0
+				flush_cache_page(bprm->vma, kpos,
+						 page_to_pfn(kmapped_page));

Bah, and my frv cross build bums out on an unrelated change,.. I'll see if I can get a noMMU arch building, in the mean time, would you try this:

---

Since no-MMU doesn't do the fancy inactive mm access there is no need to flush cache.

---

Index: linux-2.6-2/fs/exec.c
===================================================================

fs/exec.c +1 -0
@@ -428,8 +428,10 @@ static int copy_strings(int argc, char _
 				kmapped_page = page;
 				kaddr = kmap(kmapped_page);
 				kpos = pos & PAGE_MASK;
+#ifdef CONFIG_MMU
 				flush_cache_page(bprm->vma, kpos,
 						 page_to_pfn(kmapped_page));
Quoted 8 lines

fs/exec.c static int copy_strings(int argc, char _ · line 437

Quoted 5 lines
fs/exec.c +1 -0
+#endif
 			}
 			if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
 				ret = -EFAULT;

I think the same problem will happen on NOMMU && STACK_GROWS_UP. There are several new references to bprm->vma in there, not all inside CONFIG_MMU.

Right, which archs have that combo? I'll go gather cross compilers.

Perhaps I'd better create a flush_arg_page() function and stick that in the mmu/nommu section somewhere earlier on in that file. Patch in a few.

A related question; does anybody know of a no-MMU arch that uses fs/compat.c ? If there is such a beast, that would need some work.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#24 lore raw

Re: [parisc-linux] Re: [PATCH 4/4] mm: variable length argument support

On Wed, Jun 06, 2007 at 11:12:09AM +0200, Peter Zijlstra wrote:
...

Quoted 4 lines
Quoted 2 lines

I think the same problem will happen on NOMMU && STACK_GROWS_UP. There are several new references to bprm->vma in there, not all inside CONFIG_MMU.

Right, which archs have that combo? I'll go gather cross compilers.

parisc only supports with MMU. I don't know who elses uses STACK_GROWS_UP.

hth,
grant

Quoted 11 lines

Perhaps I'd better create a flush_arg_page() function and stick that in the mmu/nommu section somewhere earlier on in that file. Patch in a few.

A related question; does anybody know of a no-MMU arch that uses fs/compat.c ? If there is such a beast, that would need some work.

_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#25 lore raw

Re: [PATCH 4/4] mm: variable length argument support

In reply to Andrew Morton
Quoted 2 lines · Andrew Morton

I think the same problem will happen on NOMMU && STACK_GROWS_UP. There are several new references to bprm->vma in there, not all inside CONFIG_MMU.

I found two: one in setup_arg_pages() and one in get_arg_page() both are under CONFIG_MMU.

---
fix a no-MMU compile error on flush_cache_page() and clean up the no-MMU code a bit by placing more #ifdef CONFIG_MMU stuff into their own function.

---
 fs/exec.c |  112 +++++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 68 insertions(+), 44 deletions(-)
fs/exec.c +68 -44
Index: linux-2.6-2/fs/exec.c
===================================================================
@@ -215,6 +215,58 @@ static void free_arg_pages(struct linux_
 {
 }
 
+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 top of user memory.  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;
+}
+
 #else
 
 static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
@@ -253,6 +305,17 @@ static void free_arg_pages(struct linux_
 		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;
+}
+
 #endif /* CONFIG_MMU */
 
 /*
@@ -265,61 +328,23 @@ int bprm_mm_init(struct linux_binprm *bp
 {
 	int err;
 	struct mm_struct *mm = NULL;
-	struct vm_area_struct *vma = NULL;
 
 	bprm->mm = mm = mm_alloc();
 	err = -ENOMEM;
 	if (!mm)
 		goto err;
 
-	if ((err = init_new_context(current, mm)))
+	err = init_new_context(current, mm);
+	if (err)
 		goto err;
 
-#ifdef CONFIG_MMU
-	bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	err = -ENOMEM;
-	if (!vma)
+	err = __bprm_mm_init(bprm);
+	if (err)
 		goto err;
 
-	down_write(&mm->mmap_sem);
-	{
-		vma->vm_mm = mm;
-
-		/*
-		 * Place the stack at the top of user memory.  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];
-		if ((err = insert_vm_struct(mm, vma))) {
-			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 *);
-#else
-	bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *);
-#endif
-
 	return 0;
 
 err:
-#ifdef CONFIG_MMU
-	if (vma) {
-		bprm->vma = NULL;
-		kmem_cache_free(vm_area_cachep, vma);
-	}
-#endif
-
 	if (mm) {
 		bprm->mm = NULL;
 		mmdrop(mm);
@@ -428,8 +453,7 @@ static int copy_strings(int argc, char _
 				kmapped_page = page;
 				kaddr = kmap(kmapped_page);
 				kpos = pos & PAGE_MASK;
-				flush_cache_page(bprm->vma, kpos,
-						 page_to_pfn(kmapped_page));
+				flush_arg_page(bprm, kpos, kmapped_page);
 			}
 			if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
 				ret = -EFAULT;

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#26 lore raw

Re: [PATCH 4/4] mm: variable length argument support

Quoted 6 lines · Peter Zijlstra
fs/exec.c +6 -0
+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));
+}
+

[snip]

fs/exec.c static void free_arg_pages(struct linux_ · line 312

Quoted 9 lines
fs/exec.c +5 -0
@@ -253,6 +305,17 @@ static void free_arg_pages(struct linux_
 		free_arg_page(bprm, i);
 }
 
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+		struct page *page)
+{
+}
+

inline?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#27 lore raw

Re: [PATCH 4/4] mm: variable length argument support

Quoted 13 lines · Paul Mundt
Quoted 6 lines · Peter Zijlstra
fs/exec.c +6 -0
+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));
+}
+

[snip]

Quoted 4 lines
fs/exec.c +0 -0
@@ -253,6 +305,17 @@ static void free_arg_pages(struct linux_
 		free_arg_page(bprm, i);
 }
 
Quoted 6 lines

fs/exec.c static void free_arg_pages(struct linux_ · line 223

Quoted 5 lines
fs/exec.c +5 -0
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+		struct page *page)
+{
+}
+

inline?

could do I guess, but doesn't this modern gcc thing auto inline statics that are so small?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#29 lore raw

PATCH 4/4 mm: variable length argument support

In reply to Peter Zijlstra

From: Ollie Wild <[email protected]>

Remove the arg+env limit of MAX_ARG_PAGES by copying the strings directly

Quoted 1 line

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.

---
 arch/ia64/ia32/binfmt_elf32.c     |   61 ----
 arch/um/kernel/trap.c             |    2 
 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                       |  130 +++-----
 fs/exec.c                         |  566 +++++++++++++++++++++++---------------
 include/asm-um/processor-i386.h   |    3 
 include/asm-um/processor-x86_64.h |    3 
 include/linux/binfmts.h           |   17 -
 include/linux/mm.h                |    7 
 kernel/auditsc.c                  |    2 
 mm/mmap.c                         |   56 ++-
 mm/mprotect.c                     |    2 
 17 files changed, 495 insertions(+), 458 deletions(-)
arch/um/kernel/trap.c +0 -2
Index: linux-2.6-2/arch/um/kernel/trap.c
===================================================================
@@ -61,8 +61,6 @@ int handle_page_fault(unsigned long addr
 		goto good_area;
 	else if(!(vma->vm_flags & VM_GROWSDOWN))
 		goto out;
-	else if(is_user && !ARCH_IS_STACKGROW(address))
-		goto out;
 	else if(expand_stack(vma, address))
 		goto out;
 
arch/x86_64/ia32/ia32_binfmt.c +0 -58

70 lines not on this page · raw message

fs/binfmt_elf.c +19 -9
Index: linux-2.6-2/fs/binfmt_elf.c
===================================================================
@@ -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;
 	}
@@ -777,10 +787,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;
 
@@ -988,9 +994,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;
fs/binfmt_elf_fdpic.c +4 -4
Index: linux-2.6-2/fs/binfmt_elf_fdpic.c
===================================================================
@@ -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;
 	}
fs/binfmt_misc.c +3 -1
Index: linux-2.6-2/fs/binfmt_misc.c
===================================================================
@@ -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) {
fs/binfmt_script.c +3 -1
Index: linux-2.6-2/fs/binfmt_script.c
===================================================================
@@ -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++;
fs/compat.c +54 -76

212 lines not on this page · raw message

fs/exec.c +350 -216

739 lines not on this page · raw message

include/asm-um/processor-i386.h +0 -3
Index: linux-2.6-2/include/asm-um/processor-i386.h
===================================================================
@@ -67,9 +67,6 @@ static inline void rep_nop(void)
 #define current_text_addr() \
 	({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
 
-#define ARCH_IS_STACKGROW(address) \
-       (address + 32 >= UPT_SP(&current->thread.regs.regs))
-
 #define KSTK_EIP(tsk) KSTK_REG(tsk, EIP)
 #define KSTK_ESP(tsk) KSTK_REG(tsk, UESP)
 #define KSTK_EBP(tsk) KSTK_REG(tsk, EBP)
include/asm-um/processor-x86_64.h +0 -3
Index: linux-2.6-2/include/asm-um/processor-x86_64.h
===================================================================
@@ -44,9 +44,6 @@ static inline void arch_copy_thread(stru
 #define current_text_addr() \
 	({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; })
 
-#define ARCH_IS_STACKGROW(address) \
-        (address + 128 >= UPT_SP(&current->thread.regs.regs))
-
 #define KSTK_EIP(tsk) KSTK_REG(tsk, RIP)
 #define KSTK_ESP(tsk) KSTK_REG(tsk, RSP)
 
include/linux/binfmts.h +10 -7
Index: linux-2.6-2/include/linux/binfmts.h
===================================================================
@@ -5,12 +5,9 @@
 
 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!
- */
-#define MAX_ARG_PAGES 32
+/* FIXME: Find real limits, or none. */
+#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF
 
 /* sizeof(linux_binprm->buf) */
 #define BINPRM_BUF_SIZE 128
@@ -24,7 +21,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 +71,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 +88,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);
include/linux/mm.h +6 -1
Index: linux-2.6-2/include/linux/mm.h
===================================================================
@@ -786,7 +786,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);
@@ -812,6 +811,9 @@ extern unsigned long move_page_tables_up
 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);
 
 /*
  * Prototype to add a shrinker callback for ageable caches.
@@ -1130,6 +1132,9 @@ extern int expand_stack(struct vm_area_s
 #ifdef CONFIG_IA64
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #endif
+#ifdef CONFIG_STACK_GROWSUP
+extern int expand_downwards(struct vm_area_struct *vma, unsigned long address);
+#endif
 
 /* 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);
mm/mmap.c +32 -24

71 lines not on this page · raw message

mm/mprotect.c +1 -1
Index: linux-2.6-2/mm/mprotect.c
===================================================================
@@ -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)
 {
arch/ia64/ia32/binfmt_elf32.c +11 -50

73 lines not on this page · raw message

arch/x86_64/ia32/ia32_aout.c +1 -1
Index: linux-2.6-2/arch/x86_64/ia32/ia32_aout.c
===================================================================
@@ -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); 
kernel/auditsc.c +1 -1
Index: linux-2.6-2/kernel/auditsc.c
===================================================================
@@ -848,7 +848,7 @@ static void audit_log_execve_info(struct
 		long ret;
 		char *tmp;
 
-		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 in something is _very_ wrong.
Signature · 4 lines
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux