summaryrefslogtreecommitdiffstats
path: root/sys/uvm/uvm_pdaemon.c
diff options
context:
space:
mode:
authoroga <oga@openbsd.org>2009-06-26 20:26:02 +0000
committeroga <oga@openbsd.org>2009-06-26 20:26:02 +0000
commit84325188ef337ca68a1156c00679c9339e200aa9 (patch)
treea3a4a5cfb380e7d6e87948b34d5a91f9ca388adf /sys/uvm/uvm_pdaemon.c
parentRemove some unused function declarations; no binary change. (diff)
downloadwireguard-openbsd-84325188ef337ca68a1156c00679c9339e200aa9.tar.xz
wireguard-openbsd-84325188ef337ca68a1156c00679c9339e200aa9.zip
Fix a use after free in the pagedaemon.
specifically, if we free a RELEASED anon, then we will first of all remove the page from the anon, free the anon, then get the next page relative to the anon page, then call uvm_pagefree(). The problem is that while we zero out anon->an_page, we do not zero out pg->uanon. Now, uvm_pagefree() if pg->uanon is not NULL zeroes out some variables in the struct for us. One of the backed out commits added more zeroing there which would have exacerbated this use after free under heavy paging (which was where we saw bugs). Fix this by zeroing out pg->uanon. I have looked for other similar cases, but have not found any as of yet. been in snaps a while, "please do commit that" deraadt@
Diffstat (limited to 'sys/uvm/uvm_pdaemon.c')
-rw-r--r--sys/uvm/uvm_pdaemon.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/sys/uvm/uvm_pdaemon.c b/sys/uvm/uvm_pdaemon.c
index d62b66f5999..e16ae26ea3b 100644
--- a/sys/uvm/uvm_pdaemon.c
+++ b/sys/uvm/uvm_pdaemon.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_pdaemon.c,v 1.50 2009/06/17 00:13:59 oga Exp $ */
+/* $OpenBSD: uvm_pdaemon.c,v 1.51 2009/06/26 20:26:02 oga Exp $ */
/* $NetBSD: uvm_pdaemon.c,v 1.23 2000/08/20 10:24:14 bjh21 Exp $ */
/*
@@ -823,8 +823,13 @@ uvmpd_scan_inactive(struct pglist *pglst)
/* released during I/O? */
if (p->pg_flags & PG_RELEASED) {
if (anon) {
- /* remove page so we can get nextpg */
+ /*
+ * remove page so we can get nextpg,
+ * also zero out anon so we don't use
+ * it after the free.
+ */
anon->an_page = NULL;
+ p->uanon = NULL;
simple_unlock(&anon->an_lock);
uvm_anfree(anon); /* kills anon */