Download raw body.
diagprintf(9) aka Syzkaller debugging
On 11/12/25(Thu) 14:58, Martin Pieuchot wrote:
> Thanks to the recently added KASSERT(), syzkaller exposed an
> inconsistency bug where a physical page ends up on a managed list and
> with a non-0 `wired_count':
> https://syzkaller.appspot.com/bug?extid=f3c3aa16434bc13e3138
> https://syzkaller.appspot.com/bug?extid=c1461974b88117f479c9
>
> It's not clear to me how this can happen. So I'd like to get more
> informations.
> Syzkaller reports anything after 'panic' and I'd like to print per-page
> informations (call uvm_page_printit()). So I added a new printf(9)-like
> function that prints to a static buffer:
>
> panic: page on LRU PAGE 0xfffffd8002dd5a58:
> flags=200004<TABLED,AOBJ>, vers=1, wire_count=0, pa=0x74c7000
> uobject=0xfffffd8007575f30, uanon=0x0, offset=0x0
> [page ownership tracking disabled] vm_page_md 0xfffffd8002dd5ac0
> checking object list
> page found on object list
Here's a more specific approach following feedbacks from deraadt@. I'm
also looking into something that can be committed because there's no way
to test this as syzkaller has no reproducer (yet) for this bug.
Comments? Oks?
Index: uvm/uvm_page.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_page.c,v
diff -u -p -r1.184 uvm_page.c
--- uvm/uvm_page.c 10 Dec 2025 08:38:18 -0000 1.184
+++ uvm/uvm_page.c 15 Dec 2025 13:08:25 -0000
@@ -75,6 +75,7 @@
#include <sys/smr.h>
#include <uvm/uvm.h>
+#include <uvm/uvm_ddb.h>
/*
* for object trees
@@ -1219,6 +1220,42 @@ uvm_pagelookup(struct uvm_object *obj, v
return (pg);
}
+#ifdef DIAGNOSTIC
+char diagbuf[1024]; /* static buffer for uvm_page_printit(). */
+int diagpr(const char *, ...) __attribute__((__format__(__kprintf__,1,2)));
+
+int
+diagpr(const char *fmt, ...)
+{
+ static int diaglen;
+ int len, retval;
+ va_list ap;
+
+ len = sizeof(diagbuf) - diaglen;
+ if (len <= 1)
+ return -1;
+ va_start(ap, fmt);
+ retval = vsnprintf(diagbuf + diaglen, len, fmt, ap);
+ va_end(ap);
+
+ diaglen += retval;
+ return retval;
+}
+#endif /* DIAGNOSTIC */
+
+void
+assert_not_managed(struct vm_page *pg)
+{
+#ifdef DIAGNOSTIC
+ if (pg->pg_flags & (PQ_INACTIVE|PQ_ACTIVE)) {
+#ifdef DDB
+ uvm_page_printit(pg, TRUE, diagpr);
+#endif
+ panic("page on LRU %s", diagbuf);
+ }
+#endif
+}
+
/*
* uvm_pagewire: wire the page, thus removing it from the daemon's grasp
*/
@@ -1233,6 +1270,7 @@ uvm_pagewire(struct vm_page *pg)
uvm_unlock_pageq();
atomic_inc_int(&uvmexp.wired);
}
+ assert_not_managed(pg);
pg->wire_count++;
}
@@ -1264,7 +1302,7 @@ uvm_pagedeactivate(struct vm_page *pg)
KASSERT(uvm_page_owner_locked_p(pg, FALSE));
if (pg->wire_count > 0) {
- KASSERT((pg->pg_flags & (PQ_INACTIVE|PQ_ACTIVE)) == 0);
+ assert_not_managed(pg);
return;
}
Index: uvm/uvm_map.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.c,v
diff -u -p -r1.349 uvm_map.c
--- uvm/uvm_map.c 10 Dec 2025 08:38:18 -0000 1.349
+++ uvm/uvm_map.c 11 Dec 2025 11:54:02 -0000
@@ -2947,7 +2947,7 @@ uvm_object_printit(struct uvm_object *uo
*/
static const char page_flagbits[] =
"\20\1BUSY\2WANTED\3TABLED\4CLEAN\5CLEANCHK\6RELEASED\7FAKE\10RDONLY"
- "\11ZERO\12DEV\15PAGER1\21FREE\22INACTIVE\23ACTIVE\25ANON\26AOBJ"
+ "\11ZERO\12DEV\21FREE\22INACTIVE\23ACTIVE\25ANON\26AOBJ"
"\27ENCRYPT\31PMAP0\32PMAP1\33PMAP2\34PMAP3\35PMAP4\36PMAP5";
void
diagprintf(9) aka Syzkaller debugging