tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
netbsd32: race condition in swapctl()
Hi,
the 32bit version of swapctl() calls uvm_swap_stats() without locking
'swap_syscall_lock'. Which means that if you perform a swapctl() call
and at the same time update/add/delete a swap device, you may end up
with a memory corruption.
Here is a patch. Tested on amd64 (with a 32bit binary).
Ok?
Index: compat/netbsd32/netbsd32_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_netbsd.c,v
retrieving revision 1.195
diff -u -r1.195 netbsd32_netbsd.c
--- compat/netbsd32/netbsd32_netbsd.c 16 Jun 2015 10:42:38 -0000 1.195
+++ compat/netbsd32/netbsd32_netbsd.c 21 Jun 2015 09:13:03 -0000
@@ -1747,11 +1747,16 @@
if (count < 0)
return EINVAL;
- if (count == 0 || uvmexp.nswapdev == 0)
- return 0;
- /* Make sure userland cannot exhaust kernel memory */
+
+ swapsys_lock(RW_WRITER);
+
if ((size_t)count > (size_t)uvmexp.nswapdev)
count = uvmexp.nswapdev;
+ if (count == 0) {
+ /* No swap device */
+ swapsys_unlock();
+ return 0;
+ }
ksep_len = sizeof(*ksep) * count;
ksep = kmem_alloc(ksep_len, KM_SLEEP);
@@ -1760,6 +1765,8 @@
uvm_swap_stats(SWAP_STATS, ksep, count, retval);
count = *retval;
+ swapsys_unlock();
+
for (i = 0; i < count; i++) {
se32.se_dev = ksep[i].se_dev;
se32.se_flags = ksep[i].se_flags;
Index: uvm/uvm_swap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_swap.c,v
retrieving revision 1.172
diff -u -r1.172 uvm_swap.c
--- uvm/uvm_swap.c 25 Jul 2014 08:10:40 -0000 1.172
+++ uvm/uvm_swap.c 21 Jun 2015 09:13:03 -0000
@@ -430,6 +430,15 @@
return NULL;
}
+void swapsys_lock(krw_t op)
+{
+ rw_enter(&swap_syscall_lock, op);
+}
+
+void swapsys_unlock(void)
+{
+ rw_exit(&swap_syscall_lock);
+}
/*
* sys_swapctl: main entry point for swapctl(2) system call
@@ -741,6 +750,8 @@
struct swapdev *sdp;
int count = 0;
+ KASSERT(rw_lock_held(&swap_syscall_lock));
+
LIST_FOREACH(spp, &swap_priority, spi_swappri) {
TAILQ_FOREACH(sdp, &spp->spi_swapdev, swd_next) {
int inuse;
Index: uvm/uvm_swap.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_swap.h,v
retrieving revision 1.20
diff -u -r1.20 uvm_swap.h
--- uvm/uvm_swap.h 3 Feb 2014 13:20:21 -0000 1.20
+++ uvm/uvm_swap.h 21 Jun 2015 09:13:03 -0000
@@ -48,7 +48,10 @@
void uvm_swap_free(int, int);
void uvm_swap_markbad(int, int);
bool uvm_swapisfull(void);
+void swapsys_lock(krw_t);
+void swapsys_unlock(void);
void uvm_swap_stats(int, struct swapent *, int, register_t *);
+
#else /* defined(VMSWAP) */
#define uvm_swapisfull() true
#define uvm_swap_stats(c, sep, count, retval) { *retval = 0; }
Home |
Main Index |
Thread Index |
Old Index