Module Name:    src
Committed By:   christos
Date:           Wed Jun  1 00:49:45 UTC 2016

Modified Files:
        src/sys/uvm: uvm_map.c

Log Message:
Avoid locking issues when copying out requires taking a fault and we are
finding out our own maps, by allocating a buffer and copying out after
we collected the information.


To generate a diff of this commit:
cvs rdiff -u -r1.337 -r1.338 src/sys/uvm/uvm_map.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/uvm/uvm_map.c
diff -u src/sys/uvm/uvm_map.c:1.337 src/sys/uvm/uvm_map.c:1.338
--- src/sys/uvm/uvm_map.c:1.337	Wed May 25 13:43:58 2016
+++ src/sys/uvm/uvm_map.c	Tue May 31 20:49:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_map.c,v 1.337 2016/05/25 17:43:58 christos Exp $	*/
+/*	$NetBSD: uvm_map.c,v 1.338 2016/06/01 00:49:44 christos Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.337 2016/05/25 17:43:58 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.338 2016/06/01 00:49:44 christos Exp $");
 
 #include "opt_ddb.h"
 #include "opt_uvmhist.h"
@@ -4877,14 +4877,18 @@ fill_vmentries(struct lwp *l, pid_t pid,
 {
 	int error;
 	struct proc *p;
-	struct kinfo_vmentry vme;
+	struct kinfo_vmentry *vme;
 	struct vmspace *vm;
 	struct vm_map *map;
 	struct vm_map_entry *entry;
 	char *dp;
-	size_t count;
+	size_t count, vmesize;
 
+	vme = NULL;
+	vmesize = *oldlenp;
 	count = 0;
+	if (oldp && *oldlenp > 1024 * 1024)
+		return E2BIG;
 
 	if ((error = proc_find_locked(l, &p, pid)) != 0)
 		return error;
@@ -4896,31 +4900,44 @@ fill_vmentries(struct lwp *l, pid_t pid,
 	vm_map_lock_read(map);
 
 	dp = oldp;
+	if (oldp)
+		vme = kmem_alloc(vmesize, KM_SLEEP);
 	for (entry = map->header.next; entry != &map->header;
 	    entry = entry->next) {
 		if (oldp && (dp - (char *)oldp) < *oldlenp + elem_size) {
-			error = fill_vmentry(l, p, &vme, map, entry);
+			error = fill_vmentry(l, p, &vme[count], map, entry);
 			if (error)
-				break;
-			error = sysctl_copyout(l, &vme, dp,
-			    min(elem_size, sizeof(vme)));
-			if (error)
-				break;
+				goto out;
 			dp += elem_size;
 		}
 		count++;
 	}
 	vm_map_unlock_read(map);
 	uvmspace_free(vm);
+
 out:
 	if (pid != -1)
 		mutex_exit(p->p_lock);
 	if (error == 0) {
+		const u_int esize = min(sizeof(*vme), elem_size);
+		dp = oldp;
+		for (size_t i = 0; i < count; i++) {
+			if (oldp && (dp - (char *)oldp) < *oldlenp + elem_size)
+			{
+				error = sysctl_copyout(l, &vme[i], dp, esize);
+				if (error)
+					break;
+				dp += elem_size;
+			} else
+				break;
+		}
 		count *= elem_size;
 		if (oldp != NULL && *oldlenp < count)
 			error = ENOSPC;
 		*oldlenp = count;
 	}
+	if (vme)
+		kmem_free(vme, vmesize);
 	return error;
 }
 

Reply via email to