lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Mon, 16 Jun 2008 09:58:28 +0200
From:	renzo@...unibo.it (Renzo Davoli)
To:	LKML <linux-kernel@...r.kernel.org>, Jeff Dike <jdike@...toit.com>,
	Roland McGrath <roland@...hat.com>
Subject: [PATCH 1/2] ptrace_multi: speedup for virtual machines (and debuggers) running on ptrace

This patch implements PTRACE_MULTI.

Several ptrace requests can be packed up and sent together to the
kernel. This speeds up Virtual Machines and, if you like, debuggers.

Signed-off-by: Renzo Davoli <renzo@...unibo.it>

---
diff -Naur linux-2.6.26-rc6/include/linux/mm.h linux-2.6.26-rc6-ptrace_multi/include/linux/mm.h
--- linux-2.6.26-rc6/include/linux/mm.h	2008-06-13 13:33:30.000000000 +0200
+++ linux-2.6.26-rc6-ptrace_multi/include/linux/mm.h	2008-06-14 16:56:11.000000000 +0200
@@ -804,6 +804,7 @@
 
 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);
+extern int access_process_vm_user(struct task_struct *tsk, unsigned long addr, char __user *ubuf, int len, int write, int string);
 
 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);
diff -Naur linux-2.6.26-rc6/include/linux/ptrace.h linux-2.6.26-rc6-ptrace_multi/include/linux/ptrace.h
--- linux-2.6.26-rc6/include/linux/ptrace.h	2008-06-13 13:33:30.000000000 +0200
+++ linux-2.6.26-rc6-ptrace_multi/include/linux/ptrace.h	2008-06-14 16:56:11.000000000 +0200
@@ -27,6 +27,18 @@
 #define PTRACE_GETSIGINFO	0x4202
 #define PTRACE_SETSIGINFO	0x4203
 
+#define PTRACE_MULTI            0x4300
+#define PTRACE_PEEKCHARDATA     0x4301
+#define PTRACE_POKECHARDATA     0x4302
+#define PTRACE_PEEKSTRINGDATA   0x4303
+
+struct ptrace_multi {
+	long request;
+	long addr;
+	void *localaddr;
+	long length;
+};
+
 /* options set using PTRACE_SETOPTIONS */
 #define PTRACE_O_TRACESYSGOOD	0x00000001
 #define PTRACE_O_TRACEFORK	0x00000002
@@ -84,6 +96,7 @@
 extern struct task_struct *ptrace_get_task_struct(pid_t pid);
 extern int ptrace_traceme(void);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
+extern int ptrace_readstringdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
 extern int ptrace_attach(struct task_struct *tsk);
 extern int ptrace_detach(struct task_struct *, unsigned int);
diff -Naur linux-2.6.26-rc6/kernel/ptrace.c linux-2.6.26-rc6-ptrace_multi/kernel/ptrace.c
--- linux-2.6.26-rc6/kernel/ptrace.c	2008-06-13 13:33:31.000000000 +0200
+++ linux-2.6.26-rc6-ptrace_multi/kernel/ptrace.c	2008-06-14 19:00:13.000000000 +0200
@@ -2,6 +2,7 @@
  * linux/kernel/ptrace.c
  *
  * (C) Copyright 1999 Linus Torvalds
+ * PTRACE_MULTI support 2008 Renzo Davoli
  *
  * Common interfaces for "ptrace()" which we do not want
  * to continually duplicate across every architecture.
@@ -244,52 +245,23 @@
 
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
 {
-	int copied = 0;
+	if (!access_ok(VERIFY_WRITE, dst, len))
+		return -EIO;
+	return access_process_vm_user(tsk, src, dst, len, 0, 0);
+}
 
-	while (len > 0) {
-		char buf[128];
-		int this_len, retval;
-
-		this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
-		retval = access_process_vm(tsk, src, buf, this_len, 0);
-		if (!retval) {
-			if (copied)
-				break;
-			return -EIO;
-		}
-		if (copy_to_user(dst, buf, retval))
-			return -EFAULT;
-		copied += retval;
-		src += retval;
-		dst += retval;
-		len -= retval;			
-	}
-	return copied;
+int ptrace_readstringdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
+{
+	if (!access_ok(VERIFY_WRITE, dst, len))
+		return -EIO;
+	return access_process_vm_user(tsk, src, dst, len, 0, 1);
 }
 
 int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
 {
-	int copied = 0;
-
-	while (len > 0) {
-		char buf[128];
-		int this_len, retval;
-
-		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);
-		if (!retval) {
-			if (copied)
-				break;
-			return -EIO;
-		}
-		copied += retval;
-		src += retval;
-		dst += retval;
-		len -= retval;			
-	}
-	return copied;
+	if (!access_ok(VERIFY_READ, dst, len))
+		return -EIO;
+	return access_process_vm_user(tsk, dst, src, len, 1, 0);
 }
 
 static int ptrace_setoptions(struct task_struct *child, long data)
@@ -534,6 +506,50 @@
 #define arch_ptrace_attach(child)	do { } while (0)
 #endif
 
+static int multi_ptrace(struct task_struct *child, long request, long addr, long size)
+{
+	int i, ret;
+	long j;
+	ret=0;
+	if (!access_ok(VERIFY_READ, addr,size*sizeof(struct ptrace_multi))) {
+		ret = -EIO;
+		goto out_multi_ptrace;
+	}
+	for (i=0; i<size && ret==0; i++, addr+=sizeof(struct ptrace_multi)) {
+		unsigned long len;
+		struct ptrace_multi __user pm ;
+		if (__copy_from_user(&pm, (struct ptrace_multi __user *)addr, sizeof(struct ptrace_multi)) == 0) {
+			len = pm.length;
+			switch ( pm.request){
+				case PTRACE_PEEKTEXT:
+				case PTRACE_PEEKDATA:
+				case PTRACE_PEEKUSR:
+				case PTRACE_POKETEXT:
+				case PTRACE_POKEDATA:
+				case PTRACE_POKEUSR:
+					if (len <= 0) len=1;
+					for (j=0; j<len && ret==0; j++)
+						ret=arch_ptrace(child, pm.request, (long) (pm.addr) + j*sizeof(long), (long) (pm.localaddr) + j*sizeof(long));
+					break;
+				case PTRACE_PEEKCHARDATA:
+					ret = ptrace_readdata(child, pm.addr, pm.localaddr, len);
+					break;
+				case PTRACE_POKECHARDATA:
+					ret = ptrace_writedata(child, pm.localaddr, pm.addr, len);
+					break;
+				case PTRACE_PEEKSTRINGDATA:
+					ret = ptrace_readstringdata(child, pm.addr, pm.localaddr, len);
+					break;
+				default:
+					ret=arch_ptrace(child, pm.request, (long) (pm.addr), (long) (pm.localaddr));
+					break;
+			}
+		}
+	}
+out_multi_ptrace:
+	return ret;
+}
+
 asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
@@ -571,9 +587,10 @@
 	if (ret < 0)
 		goto out_put_task_struct;
 
-	ret = arch_ptrace(child, request, addr, data);
-	if (ret < 0)
-		goto out_put_task_struct;
+	if (request == PTRACE_MULTI)
+		ret = multi_ptrace(child, request, addr, data);
+	else
+		ret = arch_ptrace(child, request, addr, data);
 
  out_put_task_struct:
 	put_task_struct(child);
@@ -656,6 +673,57 @@
 	return ret;
 }
 
+struct compat_ptrace_multi {
+	compat_long_t request;
+	compat_ulong_t addr;
+	compat_ulong_t localaddr;
+	compat_ulong_t length;
+};
+
+static int compat_multi_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t size)
+{
+	int i, ret;
+	compat_long_t j;
+	ret=0;
+	if (!access_ok(VERIFY_READ, addr,size*sizeof(struct compat_ptrace_multi))) {
+		ret = -EIO;
+		goto out_multi_ptrace;
+	}
+	for (i=0; i<size && ret==0; i++, addr+=sizeof(struct compat_ptrace_multi)) {
+		compat_ulong_t len;
+		struct compat_ptrace_multi __user pm ;
+		if (__copy_from_user(&pm, (struct compat_ptrace_multi __user *)(u_long)addr, sizeof(struct compat_ptrace_multi)) == 0) {
+			len = pm.length;
+			switch ( pm.request){
+				case PTRACE_PEEKTEXT:
+				case PTRACE_PEEKDATA:
+				case PTRACE_PEEKUSR:
+				case PTRACE_POKETEXT:
+				case PTRACE_POKEDATA:
+				case PTRACE_POKEUSR:
+					if (len <= 0) len=1;
+					for (j=0; j<len && ret==0; j++)
+						ret=compat_arch_ptrace(child, pm.request, (compat_long_t) (pm.addr) + j*sizeof(compat_long_t), (compat_ulong_t) (pm.localaddr) + j*sizeof(compat_long_t));
+					break;
+				case PTRACE_PEEKCHARDATA:
+					ret = ptrace_readdata(child, pm.addr, (char __user *)(long)pm.localaddr, len);
+					break;
+				case PTRACE_POKECHARDATA:
+					ret = ptrace_writedata(child, (char __user *)(long)pm.localaddr, pm.addr, len);
+					break;
+				case PTRACE_PEEKSTRINGDATA:
+					ret = ptrace_readstringdata(child, pm.addr, (char __user *)(long)pm.localaddr, len);
+				break;
+				default:
+					ret=compat_arch_ptrace(child, pm.request, (compat_ulong_t) (pm.addr), (compat_ulong_t) (pm.localaddr));
+				break;
+			}
+		}
+	}
+out_multi_ptrace:
+	return ret;
+}
+
 asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
 				  compat_long_t addr, compat_long_t data)
 {
@@ -689,8 +757,12 @@
 	}
 
 	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (!ret)
-		ret = compat_arch_ptrace(child, request, addr, data);
+	if (!ret) {
+		if (request == PTRACE_MULTI)
+			ret= compat_multi_ptrace(child, request, addr, data);
+		else
+			ret = compat_arch_ptrace(child, request, addr, data);
+	}
 
  out_put_task_struct:
 	put_task_struct(child);
diff -Naur linux-2.6.26-rc6/mm/memory.c linux-2.6.26-rc6-ptrace_multi/mm/memory.c
--- linux-2.6.26-rc6/mm/memory.c	2008-06-13 13:33:31.000000000 +0200
+++ linux-2.6.26-rc6-ptrace_multi/mm/memory.c	2008-06-14 16:56:11.000000000 +0200
@@ -2793,6 +2793,74 @@
 }
 
 /*
+ * Access another process' address space to/from user space
+ * Do not walk the page table directly, use get_user_pages
+ */
+int access_process_vm_user(struct task_struct *tsk, unsigned long addr, char __user *ubuf, int len, int write, int string)
+{
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	struct page *page;
+	char *buf;
+	unsigned long old_addr = addr;
+
+	mm = get_task_mm(tsk);
+	if (!mm)
+		return 0;
+
+	buf=kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	down_read(&mm->mmap_sem);
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		int bytes, ret, offset;
+		void *maddr;
+
+		ret = get_user_pages(tsk, mm, addr, 1,
+				write, 1, &page, &vma);
+		if (ret <= 0)
+			break;
+
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
+
+		maddr = kmap(page);
+		if (write) {
+			__copy_from_user(buf,ubuf,bytes);
+			copy_to_user_page(vma, page, addr,
+					maddr + offset, buf, bytes);
+			if (!PageCompound(page))
+				set_page_dirty_lock(page);
+		} else {
+			copy_from_user_page(vma, page, addr,
+					buf, maddr + offset, bytes);
+			if (string) {
+				for (offset=0;offset<bytes;offset++)
+					if (buf[offset]==0)
+						break;
+				if (offset < bytes)
+					bytes=len=offset+1;
+			}
+			ret=__copy_to_user(ubuf,buf,bytes);
+		}
+		kunmap(page);
+		page_cache_release(page);
+		len -= bytes;
+		ubuf += bytes;
+		addr += bytes;
+	}
+	up_read(&mm->mmap_sem);
+	mmput(mm);
+
+	kfree(buf);
+	return addr - old_addr;
+}
+
+/*
  * Print the name of a VMA.
  */
 void print_vma_addr(char *prefix, unsigned long ip)
diff -Naur linux-2.6.26-rc6/patch-linux-2.6.25.5-ptrace_vm linux-2.6.26-rc6-ptrace_multi/patch-linux-2.6.25.5-ptrace_vm
--- linux-2.6.26-rc6/patch-linux-2.6.25.5-ptrace_vm	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.26-rc6-ptrace_multi/patch-linux-2.6.25.5-ptrace_vm	2008-06-14 16:56:11.000000000 +0200
@@ -0,0 +1 @@
+diff -Naur linux-2.6.25.5 linux-2.6.25.5.ptrace_vm
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ