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; } /*