[PATCH][RFC] Allow setproctitle to work again

Brian Gerst bgerst en quark.vpplus.com
Mie Ene 26 14:00:02 CST 2000


Here is the patch I promised a few days ago.  It Works For Me(tm),
although there are some applications (Netscape in particular) that
mangle their argv array and cause garbage to be output.  Summary of the
patch:
- mm->{arg,env}_{start,end} now point to the argv[] and envp[] arrays
instead of the string space on the user stack.  I have only tested
binfmt_elf.
- access_process_vm has been modified to perform strncpy instead of
memcpy when requested.
- Some crufty code that touched the environment variable space of insmod
was removed from the floppy driver.  I see no reason for this code to be
there, and I didn't really want to fix it to work with the new scheme.

While this patch restores the ability to set the process title by
strcpy(argv[0], title), it also allows for argv[0]=title to work, which
is much safer and less prone to trashing the stack and environment
space.

--

				Brian Gerst
------------ próxima parte ------------
diff -urN linux-2.3.41p3/arch/alpha/kernel/ptrace.c linux-proctitle/arch/alpha/kernel/ptrace.c
--- linux-2.3.41p3/arch/alpha/kernel/ptrace.c	Mon Dec  6 22:23:26 1999
+++ linux-proctitle/arch/alpha/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -132,14 +132,14 @@
 static inline int
 read_int(struct task_struct *task, unsigned long addr, int * data)
 {
-	int copied = access_process_vm(task, addr, data, sizeof(int), 0);
+	int copied = access_process_vm(task, addr, data, sizeof(int), APVM_READ);
 	return (copied == sizeof(int)) ? 0 : -EIO;
 }
 
 static inline int
 write_int(struct task_struct *task, unsigned long addr, int data)
 {
-	int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
+	int copied = access_process_vm(task, addr, &data, sizeof(int), APVM_WRITE);
 	return (copied == sizeof(int)) ? 0 : -EIO;
 }
 
@@ -292,7 +292,7 @@
 	case PTRACE_PEEKTEXT: /* read word at location addr. */
 	case PTRACE_PEEKDATA: {
 		unsigned long tmp;
-		int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ);
 		ret = -EIO;
 		if (copied != sizeof(tmp))
 			goto out;
@@ -313,7 +313,7 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA: {
 		unsigned long tmp = data;
-		int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
+		int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_WRITE);
 		ret = (copied == sizeof(tmp)) ? 0 : -EIO;
 		goto out;
 	}
diff -urN linux-2.3.41p3/arch/arm/kernel/ptrace.c linux-proctitle/arch/arm/kernel/ptrace.c
--- linux-2.3.41p3/arch/arm/kernel/ptrace.c	Wed Oct 20 19:29:08 1999
+++ linux-proctitle/arch/arm/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -64,7 +64,7 @@
 {
 	int copied;
 
-	copied = access_process_vm(child, addr, res, sizeof(*res), 0);
+	copied = access_process_vm(child, addr, res, sizeof(*res), APVM_READ);
 
 	return copied != sizeof(*res) ? -EIO : 0;
 }
@@ -74,7 +74,7 @@
 {
 	int copied;
 
-	copied = access_process_vm(child, addr, &val, sizeof(val), 1);
+	copied = access_process_vm(child, addr, &val, sizeof(val), APVM_WRITE);
 
 	return copied != sizeof(val) ? -EIO : 0;
 }
diff -urN linux-2.3.41p3/arch/i386/kernel/ptrace.c linux-proctitle/arch/i386/kernel/ptrace.c
--- linux-2.3.41p3/arch/i386/kernel/ptrace.c	Sun Jan 23 12:49:43 2000
+++ linux-proctitle/arch/i386/kernel/ptrace.c	Wed Jan 26 01:26:31 2000
@@ -203,7 +203,7 @@
 		unsigned long tmp;
 		int copied;
 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ);
 		ret = -EIO;
 		if (copied != sizeof(tmp))
 			break;
@@ -237,7 +237,7 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+		if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data))
 			break;
 		ret = -EIO;
 		break;
diff -urN linux-2.3.41p3/arch/mips/kernel/irixelf.c linux-proctitle/arch/mips/kernel/irixelf.c
--- linux-2.3.41p3/arch/mips/kernel/irixelf.c	Sun Jul 25 16:45:25 1999
+++ linux-proctitle/arch/mips/kernel/irixelf.c	Wed Jan 26 01:25:51 2000
@@ -206,25 +206,25 @@
 	}
 #undef NEW_AUX_ENT
 
+	current->mm->env_end = (unsigned long) sp;
 	sp -= envc+1;
 	envp = (elf_caddr_t *) sp;
+	current->mm->arg_end = current->mm->env_start = (unsigned long) sp;
 	sp -= argc+1;
 	argv = (elf_caddr_t *) sp;
+	current->mm->arg_start = (unsigned long) sp;
 
 	__put_user((elf_addr_t)argc,--sp);
-	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,argv++);
 		p += strlen_user(p);
 	}
 	__put_user(NULL, argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,envp++);
 		p += strlen_user(p);
 	}
 	__put_user(NULL, envp);
-	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
 
diff -urN linux-2.3.41p3/arch/mips/kernel/ptrace.c linux-proctitle/arch/mips/kernel/ptrace.c
--- linux-2.3.41p3/arch/mips/kernel/ptrace.c	Mon Jul  5 22:44:57 1999
+++ linux-proctitle/arch/mips/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -112,7 +112,7 @@
 		unsigned long tmp;
 		int copied;
 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ);
 		res = -EIO;
 		if (copied != sizeof(tmp))
 			goto out;
@@ -184,7 +184,7 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		res = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+		if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE)
 		    == sizeof(data))
 			goto out;
 		res = -EIO;
diff -urN linux-2.3.41p3/arch/ppc/kernel/ptrace.c linux-proctitle/arch/ppc/kernel/ptrace.c
--- linux-2.3.41p3/arch/ppc/kernel/ptrace.c	Tue Aug 31 14:36:43 1999
+++ linux-proctitle/arch/ppc/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -358,7 +358,7 @@
 			unsigned long tmp;
 			int copied;
 
-			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ);
 			ret = -EIO;
 			if (copied != sizeof(tmp))
 				goto out;
@@ -399,7 +399,7 @@
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
 			ret = 0;
-			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+			if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data))
 				goto out;
 			ret = -EIO;
 			goto out;
diff -urN linux-2.3.41p3/arch/sh/kernel/ptrace.c linux-proctitle/arch/sh/kernel/ptrace.c
--- linux-2.3.41p3/arch/sh/kernel/ptrace.c	Wed Sep  1 18:34:01 1999
+++ linux-proctitle/arch/sh/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -208,7 +208,7 @@
 			unsigned long tmp;
 			int copied;
 
-			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ);
 			ret = -EIO;
 			if (copied != sizeof(tmp))
 				goto out;
@@ -244,7 +244,7 @@
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
 			ret = 0;
-			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+			if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data))
 				goto out;
 			ret = -EIO;
 			goto out;
diff -urN linux-2.3.41p3/arch/sparc/kernel/ptrace.c linux-proctitle/arch/sparc/kernel/ptrace.c
--- linux-2.3.41p3/arch/sparc/kernel/ptrace.c	Tue Aug 31 14:23:29 1999
+++ linux-proctitle/arch/sparc/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -371,7 +371,7 @@
 		unsigned long tmp;
 
 		if (access_process_vm(child, addr,
-				      &tmp, sizeof(tmp), 0) == sizeof(tmp))
+				      &tmp, sizeof(tmp), APVM_READ) == sizeof(tmp))
 			pt_os_succ_return(regs, tmp, (long *)data);
 		else
 			pt_error_return(regs, EIO);
@@ -389,7 +389,7 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA: {
 		if (access_process_vm(child, addr,
-				      &data, sizeof(data), 1) == sizeof(data))
+				      &data, sizeof(data), APVM_WRITE) == sizeof(data))
 			pt_succ_return(regs, 0);
 		else
 			pt_error_return(regs, EIO);
diff -urN linux-2.3.41p3/arch/sparc64/kernel/binfmt_aout32.c linux-proctitle/arch/sparc64/kernel/binfmt_aout32.c
--- linux-2.3.41p3/arch/sparc64/kernel/binfmt_aout32.c	Thu Aug 26 15:42:32 1999
+++ linux-proctitle/arch/sparc64/kernel/binfmt_aout32.c	Wed Jan 26 01:25:51 2000
@@ -175,12 +175,15 @@
 	if ((envc+argc+3)&1)
 		--sp;
 
+	current->mm->env_end = (unsigned long) sp;
 	sp -= envc+1;
 	envp = (u32 *) sp;
+	current->mm->arg_end = current->mm->env_start = (unsigned long) sp;
 	sp -= argc+1;
 	argv = (u32 *) sp;
+	current->mm->arg_start = (unsigned long) sp;
+
 	put_user(argc,--sp);
-	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		char c;
 		put_user(((u32)A(p)),argv++);
@@ -189,7 +192,6 @@
 		} while (c);
 	}
 	put_user(NULL,argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		char c;
 		put_user(((u32)A(p)),envp++);
@@ -198,7 +200,6 @@
 		} while (c);
 	}
 	put_user(NULL,envp);
-	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
 
diff -urN linux-2.3.41p3/arch/sparc64/kernel/ptrace.c linux-proctitle/arch/sparc64/kernel/ptrace.c
--- linux-2.3.41p3/arch/sparc64/kernel/ptrace.c	Tue Aug  3 01:07:16 1999
+++ linux-proctitle/arch/sparc64/kernel/ptrace.c	Wed Jan 26 01:25:51 2000
@@ -244,13 +244,13 @@
 		res = -EIO;
 		if (current->thread.flags & SPARC_FLAG_32BIT) {
 			copied = access_process_vm(child, addr,
-						   &tmp32, sizeof(tmp32), 0);
+						   &tmp32, sizeof(tmp32), APVM_READ);
 			tmp64 = (unsigned long) tmp32;
 			if (copied == sizeof(tmp32))
 				res = 0;
 		} else {
 			copied = access_process_vm(child, addr,
-						   &tmp64, sizeof(tmp64), 0);
+						   &tmp64, sizeof(tmp64), APVM_READ);
 			if (copied == sizeof(tmp64))
 				res = 0;
 		}
@@ -270,13 +270,13 @@
 		if (current->thread.flags & SPARC_FLAG_32BIT) {
 			tmp32 = data;
 			copied = access_process_vm(child, addr,
-						   &tmp32, sizeof(tmp32), 1);
+						   &tmp32, sizeof(tmp32), APVM_WRITE);
 			if (copied == sizeof(tmp32))
 				res = 0;
 		} else {
 			tmp64 = data;
 			copied = access_process_vm(child, addr,
-						   &tmp64, sizeof(tmp64), 1);
+						   &tmp64, sizeof(tmp64), APVM_WRITE);
 			if (copied == sizeof(tmp64))
 				res = 0;
 		}
diff -urN linux-2.3.41p3/drivers/block/floppy.c linux-proctitle/drivers/block/floppy.c
--- linux-2.3.41p3/drivers/block/floppy.c	Sun Jan 23 12:49:47 2000
+++ linux-proctitle/drivers/block/floppy.c	Wed Jan 26 01:33:13 2000
@@ -4330,60 +4330,13 @@
 	}
 }
 
-static void __init mod_setup(char *pattern, int (*setup)(char *))
-{
-	unsigned long i;
-	char c;
-	int j;
-	int match;
-	char buffer[100];
-	int length = strlen(pattern)+1;
-
-	match=0;
-	j=1;
-
-	for (i=current->mm->env_start; i< current->mm->env_end; i ++){
-		get_user(c, (char *)i);
-		if (match){
-			if (j==99)
-				c='\0';
-			buffer[j] = c;
-			if (!c || c == ' ' || c == '\t'){
-				if (j){
-					buffer[j] = '\0';
-					setup(buffer);
-				}
-				j=0;
-			} else
-				j++;
-			if (!c)
-				break;
-			continue;
-		}
-		if ((!j && !c) || (j && c == pattern[j-1]))
-			j++;
-		else
-			j=0;
-		if (j==length){
-			match=1;
-			j=0;
-		}
-	}
-}
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
 int init_module(void)
 {
 	printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n");
 		
 	if(floppy)
 		parse_floppy_cfg_string(floppy);
-	else
-		mod_setup("floppy=", floppy_setup);
-		
+
 	return floppy_init();
 }
 
@@ -4403,10 +4356,6 @@
 MODULE_PARM(FLOPPY_DMA,"i");
 MODULE_AUTHOR("Alain L. Knaff");
 MODULE_SUPPORTED_DEVICE("fd");
-
-#ifdef __cplusplus
-}
-#endif
 
 #else
 
diff -urN linux-2.3.41p3/fs/binfmt_aout.c linux-proctitle/fs/binfmt_aout.c
--- linux-2.3.41p3/fs/binfmt_aout.c	Wed Nov 24 11:36:09 1999
+++ linux-proctitle/fs/binfmt_aout.c	Wed Jan 26 01:25:51 2000
@@ -225,16 +225,18 @@
 	put_user(bprm->exec, --sp);
 	put_user(0x3e9, --sp);
 #endif
+	current->mm->env_end = (unsigned long) sp;
 	sp -= envc+1;
 	envp = (char **) sp;
+	current->mm->env_start = current->mm->arg_end = (unsigned long) sp;
 	sp -= argc+1;
 	argv = (char **) sp;
+	current->mm->arg_start = (unsigned long) sp;
 #if defined(__i386__) || defined(__mc68000__)
 	put_user((unsigned long) envp,--sp);
 	put_user((unsigned long) argv,--sp);
 #endif
 	put_user(argc,--sp);
-	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		char c;
 		put_user(p,argv++);
@@ -243,7 +245,6 @@
 		} while (c);
 	}
 	put_user(NULL,argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		char c;
 		put_user(p,envp++);
@@ -252,7 +253,6 @@
 		} while (c);
 	}
 	put_user(NULL,envp);
-	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
 
diff -urN linux-2.3.41p3/fs/binfmt_elf.c linux-proctitle/fs/binfmt_elf.c
--- linux-2.3.41p3/fs/binfmt_elf.c	Wed Jan 12 18:53:02 2000
+++ linux-proctitle/fs/binfmt_elf.c	Wed Jan 26 01:25:51 2000
@@ -173,29 +173,29 @@
 	}
 #undef NEW_AUX_ENT
 
+	current->mm->env_end = (unsigned long) sp;
 	sp -= envc+1;
 	envp = (elf_caddr_t *) sp;
+	current->mm->env_start = current->mm->arg_end = (unsigned long) sp;
 	sp -= argc+1;
 	argv = (elf_caddr_t *) sp;
+	current->mm->arg_start = (unsigned long) sp;
 	if (!ibcs) {
 		__put_user((elf_addr_t)(unsigned long) envp,--sp);
 		__put_user((elf_addr_t)(unsigned long) argv,--sp);
 	}
 
 	__put_user((elf_addr_t)argc,--sp);
-	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,argv++);
 		p += strlen_user(p);
 	}
 	__put_user(NULL, argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,envp++);
 		p += strlen_user(p);
 	}
 	__put_user(NULL, envp);
-	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
 
diff -urN linux-2.3.41p3/fs/proc/base.c linux-proctitle/fs/proc/base.c
--- linux-2.3.41p3/fs/proc/base.c	Wed Jan 12 18:52:44 2000
+++ linux-proctitle/fs/proc/base.c	Wed Jan 26 02:01:58 2000
@@ -100,15 +100,40 @@
 
 /* task is locked and can't drop mm, so we are safe */
 
+static int get_array(struct task_struct *task, unsigned long start,
+                     unsigned long end, char *buffer)
+{
+	unsigned long str;
+	int res;
+	int buflen = 0;
+
+	while (start < end) {
+		res = access_process_vm(task, start, &str, sizeof(str), APVM_READ);
+		if (res != sizeof(str) || !str)
+			break;
+
+		res = access_process_vm(task, str, buffer, PAGE_SIZE - buflen,
+		                        APVM_READ | APVM_STRNCPY);
+		if (!res || buffer[res - 1])
+			break;
+
+		buffer += res;
+		buflen += res;
+
+		start += sizeof(str);
+	}
+
+	return buflen;
+}
+
+/* task is locked and can't drop mm, so we are safe */
+
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
 	struct mm_struct *mm = task->mm;
 	int res = 0;
 	if (mm) {
-		int len = mm->env_end - mm->env_start;
-		if (len > PAGE_SIZE)
-			len = PAGE_SIZE;
-		res = access_process_vm(task, mm->env_start, buffer, len, 0);
+		res = get_array(task, mm->env_start, mm->env_end, buffer);
 	}
 	return res;
 }
@@ -120,10 +145,7 @@
 	struct mm_struct *mm = task->mm;
 	int res = 0;
 	if (mm) {
-		int len = mm->arg_end - mm->arg_start;
-		if (len > PAGE_SIZE)
-			len = PAGE_SIZE;
-		res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+		res = get_array(task, mm->arg_start, mm->arg_end, buffer);
 	}
 	return res;
 }
@@ -288,7 +310,7 @@
 		int this_len, retval;
 
 		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-		retval = access_process_vm(task, src, page, this_len, 0);
+		retval = access_process_vm(task, src, page, this_len, APVM_READ);
 		if (!retval) {
 			if (!copied)
 				copied = -EIO;
@@ -331,7 +353,7 @@
 			copied = -EFAULT;
 			break;
 		}
-		retval = access_process_vm(task, dst, page, this_len, 1);
+		retval = access_process_vm(task, dst, page, this_len, APVM_WRITE);
 		if (!retval) {
 			if (!copied)
 				copied = -EIO;
diff -urN linux-2.3.41p3/include/linux/mm.h linux-proctitle/include/linux/mm.h
--- linux-2.3.41p3/include/linux/mm.h	Sun Jan 23 12:50:00 2000
+++ linux-proctitle/include/linux/mm.h	Wed Jan 26 01:52:31 2000
@@ -390,6 +390,11 @@
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
 
+/* Flags for access_process_vm() */
+#define APVM_READ	0
+#define APVM_WRITE	1
+#define APVM_STRNCPY	2
+
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
 
diff -urN linux-2.3.41p3/kernel/ptrace.c linux-proctitle/kernel/ptrace.c
--- linux-2.3.41p3/kernel/ptrace.c	Mon Nov 22 23:48:55 1999
+++ linux-proctitle/kernel/ptrace.c	Wed Jan 26 01:56:54 2000
@@ -18,13 +18,14 @@
 /*
  * Access another process' address space, one page at a time.
  */
-static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
+static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma,
+                           unsigned long addr, void *buf, int len, int flags)
 {
 	pgd_t * pgdir;
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
 	unsigned long mapnr;
-	unsigned long maddr; 
+	char * maddr;
 	struct page *page;
 
 repeat:
@@ -42,29 +43,32 @@
 	if (!pte_present(*pgtable))
 		goto fault_in_page;
 	mapnr = pte_pagenr(*pgtable);
-	if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
+	if ((flags & APVM_WRITE) && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
 		goto fault_in_page;
 	if (mapnr >= max_mapnr)
 		return 0;
 	page = mem_map + mapnr;
 	flush_cache_page(vma, addr);
 
-	if (write) {
-		maddr = kmap(page);
-		memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
-		flush_page_to_ram(page);
-		kunmap(page);
+	maddr = (char *) kmap(page) + (addr & ~PAGE_MASK);
+	if (flags & APVM_WRITE) {
+		if (flags & APVM_STRNCPY)
+			len = strnlen(buf, len) + 1;
+		memcpy(maddr, buf, len);
 	} else {
-		maddr = kmap(page);
-		memcpy(buf, (char *)maddr + (addr & ~PAGE_MASK), len);
-		flush_page_to_ram(page);
-		kunmap(page);
+		if (flags & APVM_STRNCPY)
+			len = strnlen(maddr, len) + 1;
+		memcpy(buf, maddr, len);
 	}
+
+	flush_page_to_ram(page);
+	kunmap(page);
+
 	return len;
 
 fault_in_page:
 	/* -1: out of memory. 0 - unmapped page */
-	if (handle_mm_fault(tsk, vma, addr, write) > 0)
+	if (handle_mm_fault(tsk, vma, addr, (flags & APVM_WRITE)) > 0)
 		goto repeat;
 	return 0;
 
@@ -77,7 +81,7 @@
 	return 0;
 }
 
-int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int flags)
 {
 	int copied;
 	struct vm_area_struct * vma;
@@ -96,7 +100,7 @@
 
 		if (this_len > len)
 			this_len = len;
-		retval = access_one_page(tsk, vma, addr, buf, this_len, write);
+		retval = access_one_page(tsk, vma, addr, buf, this_len, flags);
 		copied += retval;
 		if (retval != this_len)
 			break;
@@ -108,6 +112,10 @@
 		addr += retval;
 		buf += retval;
 
+		/* Catch case where null is last byte on page */
+		if ((flags & APVM_STRNCPY) && !*((char*)buf-1))
+			break;
+
 		if (addr < vma->vm_end)
 			continue;	
 		if (!vma->vm_next)
@@ -130,7 +138,7 @@
 		int this_len, retval;
 
 		this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
-		retval = access_process_vm(tsk, src, buf, this_len, 0);
+		retval = access_process_vm(tsk, src, buf, this_len, APVM_READ);
 		if (!retval) {
 			if (copied)
 				break;
@@ -157,7 +165,7 @@
 		this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 		if (copy_from_user(buf, src, this_len))
 			return -EFAULT;
-		retval = access_process_vm(tsk, dst, buf, this_len, 1);
+		retval = access_process_vm(tsk, dst, buf, this_len, APVM_WRITE);
 		if (!retval) {
 			if (copied)
 				break;


Más información sobre la lista de distribución Ayuda