Module Name:    src
Committed By:   rmind
Date:           Sun Feb  5 16:08:28 UTC 2012

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

Log Message:
- sys_swapctl: validate the number of swap devices argument for SWAP_STATS.
- uvm_swap_stats: fix a buffer overrun, add some asserts.

Reviewed by mrg@


To generate a diff of this commit:
cvs rdiff -u -r1.160 -r1.161 src/sys/uvm/uvm_swap.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_swap.c
diff -u src/sys/uvm/uvm_swap.c:1.160 src/sys/uvm/uvm_swap.c:1.161
--- src/sys/uvm/uvm_swap.c:1.160	Sat Jan 28 00:00:06 2012
+++ src/sys/uvm/uvm_swap.c	Sun Feb  5 16:08:28 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_swap.c,v 1.160 2012/01/28 00:00:06 rmind Exp $	*/
+/*	$NetBSD: uvm_swap.c,v 1.161 2012/02/05 16:08:28 rmind Exp $	*/
 
 /*
  * Copyright (c) 1995, 1996, 1997, 2009 Matthew R. Green
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.160 2012/01/28 00:00:06 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.161 2012/02/05 16:08:28 rmind Exp $");
 
 #include "opt_uvmhist.h"
 #include "opt_compat_netbsd.h"
@@ -398,8 +398,7 @@ swaplist_trim(void)
 {
 	struct swappri *spp, *nextspp;
 
-	for (spp = LIST_FIRST(&swap_priority); spp != NULL; spp = nextspp) {
-		nextspp = LIST_NEXT(spp, spi_swappri);
+	LIST_FOREACH_SAFE(spp, &swap_priority, spi_swappri, nextspp) {
 		if (CIRCLEQ_FIRST(&spp->spi_swapdev) !=
 		    (void *)&spp->spi_swapdev)
 			continue;
@@ -454,20 +453,11 @@ sys_swapctl(struct lwp *l, const struct 
 	struct swapent *sep;
 #define SWAP_PATH_MAX (PATH_MAX + 1)
 	char	*userpath;
-	size_t	len;
+	size_t	len = 0;
 	int	error, misc;
 	int	priority;
 	UVMHIST_FUNC("sys_swapctl"); UVMHIST_CALLED(pdhist);
 
-	misc = SCARG(uap, misc);
-
-	userpath = kmem_alloc(SWAP_PATH_MAX, KM_SLEEP);
-
-	/*
-	 * ensure serialized syscall access by grabbing the swap_syscall_lock
-	 */
-	rw_enter(&swap_syscall_lock, RW_WRITER);
-
 	/*
 	 * we handle the non-priv NSWAP and STATS request first.
 	 *
@@ -475,13 +465,20 @@ sys_swapctl(struct lwp *l, const struct 
 	 * [can also be obtained with uvmexp sysctl]
 	 */
 	if (SCARG(uap, cmd) == SWAP_NSWAP) {
-		UVMHIST_LOG(pdhist, "<- done SWAP_NSWAP=%d", uvmexp.nswapdev,
-		    0, 0, 0);
-		*retval = uvmexp.nswapdev;
-		error = 0;
-		goto out;
+		const int nswapdev = uvmexp.nswapdev;
+		UVMHIST_LOG(pdhist, "<- done SWAP_NSWAP=%d", nswapdev, 0, 0, 0);
+		*retval = nswapdev;
+		return 0;
 	}
 
+	misc = SCARG(uap, misc);
+	userpath = kmem_alloc(SWAP_PATH_MAX, KM_SLEEP);
+
+	/*
+	 * ensure serialized syscall access by grabbing the swap_syscall_lock
+	 */
+	rw_enter(&swap_syscall_lock, RW_WRITER);
+
 	/*
 	 * SWAP_STATS: get stats on current # of configured swap devs
 	 *
@@ -500,6 +497,12 @@ sys_swapctl(struct lwp *l, const struct 
 	    ) {
 		if ((size_t)misc > (size_t)uvmexp.nswapdev)
 			misc = uvmexp.nswapdev;
+
+		if (misc == 0) {
+			error = EINVAL;
+			goto out;
+		}
+		KASSERT(misc > 0);
 #if defined(COMPAT_13)
 		if (SCARG(uap, cmd) == SWAP_STATS13)
 			len = sizeof(struct swapent13) * misc;
@@ -561,6 +564,7 @@ sys_swapctl(struct lwp *l, const struct 
 		if (SCARG(uap, cmd) == SWAP_ON &&
 		    copystr("miniroot", userpath, SWAP_PATH_MAX, &len))
 			panic("swapctl: miniroot copy failed");
+		KASSERT(len > 0);
 	} else {
 		struct pathbuf *pb;
 
@@ -656,9 +660,10 @@ sys_swapctl(struct lwp *l, const struct 
 		swaplist_insert(sdp, spp, priority);
 		mutex_exit(&uvm_swap_data_lock);
 
+		KASSERT(len > 0);
 		sdp->swd_pathlen = len;
-		sdp->swd_path = kmem_alloc(sdp->swd_pathlen, KM_SLEEP);
-		if (copystr(userpath, sdp->swd_path, sdp->swd_pathlen, 0) != 0)
+		sdp->swd_path = kmem_alloc(len, KM_SLEEP);
+		if (copystr(userpath, sdp->swd_path, len, 0) != 0)
 			panic("swapctl: copystr");
 
 		/*
@@ -737,12 +742,13 @@ uvm_swap_stats(int cmd, struct swapent *
 	int count = 0;
 
 	LIST_FOREACH(spp, &swap_priority, spi_swappri) {
-		for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev);
-		     sdp != (void *)&spp->spi_swapdev && sec-- > 0;
-		     sdp = CIRCLEQ_NEXT(sdp, swd_next)) {
+		CIRCLEQ_FOREACH(sdp, &spp->spi_swapdev, swd_next) {
 			int inuse;
 
-		  	/*
+			if (sec-- <= 0)
+				break;
+
+			/*
 			 * backwards compatibility for system call.
 			 * For NetBSD 1.3 and 5.0, we have to use
 			 * the 32 bit dev_t.  For 5.0 and -current
@@ -759,8 +765,9 @@ uvm_swap_stats(int cmd, struct swapent *
 				sep->se_nblks = sdp->swd_nblks;
 				sep->se_inuse = inuse;
 				sep->se_priority = sdp->swd_priority;
-				memcpy(&sep->se_path, sdp->swd_path,
-				       sizeof sep->se_path);
+				KASSERT(sdp->swd_pathlen <
+				    sizeof(sep->se_path));
+				strcpy(sep->se_path, sdp->swd_path);
 				sep++;
 #if defined(COMPAT_13)
 			} else if (cmd == SWAP_STATS13) {
@@ -784,8 +791,9 @@ uvm_swap_stats(int cmd, struct swapent *
 				sep50->se50_nblks = sdp->swd_nblks;
 				sep50->se50_inuse = inuse;
 				sep50->se50_priority = sdp->swd_priority;
-				memcpy(&sep50->se50_path, sdp->swd_path,
-				       sizeof sep50->se50_path);
+				KASSERT(sdp->swd_pathlen <
+				    sizeof(sep50->se50_path));
+				strcpy(sep50->se50_path, sdp->swd_path);
 				sep = (struct swapent *)(sep50 + 1);
 #endif
 #if defined(COMPAT_13) || defined(COMPAT_50)
@@ -794,9 +802,7 @@ uvm_swap_stats(int cmd, struct swapent *
 			count++;
 		}
 	}
-
 	*retval = count;
-	return;
 }
 
 /*

Reply via email to