In the Linux kernel, the following vulnerability has been resolved: uprobes: Reject the shared zeropage in uprobewriteopcode() We triggered the following crash in syzkaller tests: BUG: Bad page state in process syz.7.38 pfn:1eff3 page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1eff3 flags: 0x3fffff00004004(referenced|reserved|node=0|zone=1|lastcpupid=0x1fffff) raw: 003fffff00004004 ffffe6c6c07bfcc8 ffffe6c6c07bfcc8 0000000000000000 raw: 0000000000000000 0000000000000000 00000000fffffffe 0000000000000000 page dumped because: PAGEFLAGSCHECKATFREE flag(s) set Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 Call Trace: <TASK> dumpstacklvl+0x32/0x50 badpage+0x69/0xf0 freeunrefpageprepare+0x401/0x500 freeunrefpage+0x6d/0x1b0 uprobewriteopcode+0x460/0x8e0 installbreakpoint.part.0+0x51/0x80 registerforeachvma+0x1d9/0x2b0 uproberegister+0x245/0x300 bpfuprobemultilinkattach+0x29b/0x4f0 linkcreate+0x1e2/0x280 _sysbpf+0x75f/0xac0 _x64sysbpf+0x1a/0x30 dosyscall64+0x56/0x100 entrySYSCALL64afterhwframe+0x78/0xe2 BUG: Bad rss-counter state mm:00000000452453e0 type:MMFILEPAGES val:-1 The following syzkaller test case can be used to reproduce: r2 = creat(&(0x7f0000000000)='./file0\x00', 0x8) write$nbd(r2, &(0x7f0000000580)=ANY=[], 0x10) r4 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file0\x00', 0x42, 0x0) mmap$IORINGOFFSQRING(&(0x7f0000ffd000/0x3000)=nil, 0x3000, 0x0, 0x12, r4, 0x0) r5 = userfaultfd(0x80801) ioctl$UFFDIOAPI(r5, 0xc018aa3f, &(0x7f0000000040)={0xaa, 0x20}) r6 = userfaultfd(0x80801) ioctl$UFFDIOAPI(r6, 0xc018aa3f, &(0x7f0000000140)) ioctl$UFFDIOREGISTER(r6, 0xc020aa00, &(0x7f0000000100)={{&(0x7f0000ffc000/0x4000)=nil, 0x4000}, 0x2}) ioctl$UFFDIOZEROPAGE(r5, 0xc020aa04, &(0x7f0000000000)={{&(0x7f0000ffd000/0x1000)=nil, 0x1000}}) r7 = bpf$PROGLOAD(0x5, &(0x7f0000000140)={0x2, 0x3, &(0x7f0000000200)=ANY=[@ANYBLOB="1800000000120000000000000000000095"], &(0x7f0000000000)='GPL\x00', 0x7, 0x0, 0x0, 0x0, 0x0, '\x00', 0x0, @fallback=0x30, 0xffffffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, @void, @value}, 0x94) bpf$BPFLINKCREATEXDP(0x1c, &(0x7f0000000040)={r7, 0x0, 0x30, 0x1e, @val=@uprobemulti={&(0x7f0000000080)='./file0\x00', &(0x7f0000000100)=[0x2], 0x0, 0x0, 0x1}}, 0x40) The cause is that zero pfn is set to the PTE without increasing the RSS count in mfillatomicptezeropage() and the refcount of zero folio does not increase accordingly. Then, the operation on the same pfn is performed in uprobewriteopcode()->replacepage() to unconditional decrease the RSS count and oldfolio's refcount. Therefore, two bugs are introduced: 1. The RSS count is incorrect, when process exit, the checkmm() report error "Bad rss-count". 2. The reserved folio (zero folio) is freed when folio->refcount is zero, then freepagesprepare->freepageisbad() report error "Bad page state". There is more, the following warning could also theoretically be triggered: _replacepage() -> ... -> folioremovermappte() -> VMWARNONFOLIO(iszerofolio(folio), folio) Considering that uprobe hit on the zero folio is a very rare case, just reject zero old folio immediately after getuserpagevma_remote(). [ mingo: Cleaned up the changelog ]