In the Linux kernel, the following vulnerability has been resolved:
usb: gadget: ffs: Clear ffseventfd in ffsdataclear.
ffsdataclear is indirectly called from both ffsfskillsb and ffsep0release, so it ends up being called twice when userland closes ep0 and then unmounts ffs. If userland provided an eventfd along with function's USB descriptors, it ends up calling eventfdctxput as many times, causing a refcount underflow. NULL-ify ffseventfd to prevent these extraneous eventfdctx_put calls.
Also, set epfiles to NULL right after de-allocating it, for readability.
For completeness, ffsdataclear actually ends up being called thrice, the last call being before the whole ffs structure gets freed, so when this specific sequence happens there is a second underflow happening (but not being reported):
/sys/kernel/debug/tracing# modprobe usbffs /sys/kernel/debug/tracing# echo ffsdataclear > setftracefilter /sys/kernel/debug/tracing# echo function > currenttracer /sys/kernel/debug/tracing# echo 1 > tracingon (setup gadget, run and kill function userland process, teardown gadget) /sys/kernel/debug/tracing# echo 0 > tracingon /sys/kernel/debug/tracing# cat trace smartcard-openp-436 [000] ..... 1946.208786: ffsdataclear <-ffsdataclosed smartcard-openp-431 [000] ..... 1946.279147: ffsdataclear <-ffsdataclosed smartcard-openp-431 [000] .n... 1946.905512: ffsdataclear <-ffsdata_put
Warning output corresponding to above trace: [ 1946.284139] WARNING: CPU: 0 PID: 431 at lib/refcount.c:28 refcountwarnsaturate+0x110/0x15c [ 1946.293094] refcountt: underflow; use-after-free. [ 1946.298164] Modules linked in: usbfncm(E) uether(E) usbffs(E) hciuart(E) btqca(E) btrtl(E) btbcm(E) btintel(E) bluetooth(E) nlsascii(E) nlscp437(E) vfat(E) fat(E) bcm2835v4l2(CE) bcm2835mmalvchiq(CE) videobuf2vmalloc(E) videobuf2memops(E) sha512generic(E) videobuf2v4l2(E) sha512arm(E) videobuf2common(E) videodev(E) cpufreqdt(E) sndbcm2835(CE) brcmfmac(E) mc(E) vc4(E) ctr(E) brcmutil(E) sndsoccore(E) sndpcmdmaengine(E) drbg(E) sndpcm(E) sndtimer(E) snd(E) soundcore(E) drmkmshelper(E) cec(E) ansicprng(E) rccore(E) syscopyarea(E) raspberrypicpufreq(E) sysfillrect(E) sysimgblt(E) cfg80211(E) max17040battery(OE) raspberrypihwmon(E) fbsysfops(E) regmapi2c(E) ecdhgeneric(E) rfkill(E) ecc(E) bcm2835rng(E) rngcore(E) vchiq(CE) ledsgpio(E) libcomposite(E) fuse(E) configfs(E) iptables(E) xtables(E) autofs4(E) ext4(E) crc16(E) mbcache(E) jbd2(E) crc32cgeneric(E) sdhciiproc(E) sdhcipltfm(E) sdhci(E) [ 1946.399633] CPU: 0 PID: 431 Comm: smartcard-openp Tainted: G C OE 5.15.0-1-rpi #1 Debian 5.15.3-1 [ 1946.417950] Hardware name: BCM2835 [ 1946.425442] Backtrace: [ 1946.432048] [<c08d60a0>] (dumpbacktrace) from [<c08d62ec>] (showstack+0x20/0x24) [ 1946.448226] r7:00000009 r6:0000001c r5:c04a948c r4:c0a64e2c [ 1946.458412] [<c08d62cc>] (showstack) from [<c08d9ae0>] (dumpstack+0x28/0x30) [ 1946.470380] [<c08d9ab8>] (dumpstack) from [<c0123500>] (warn+0xe8/0x154) [ 1946.482067] r5:c04a948c r4:c0a71dc8 [ 1946.490184] [<c0123418>] (warn) from [<c08d6948>] (warnslowpathfmt+0xa0/0xe4) [ 1946.506758] r7:00000009 r6:0000001c r5:c0a71dc8 r4:c0a71e04 [ 1946.517070] [<c08d68ac>] (warnslowpathfmt) from [<c04a948c>] (refcountwarnsaturate+0x110/0x15c) [ 1946.535309] r8:c0100224 r7:c0dfcb84 r6:ffffffff r5:c3b84c00 r4:c24a17c0 [ 1946.546708] [<c04a937c>] (refcountwarnsaturate) from [<c0380134>] (eventfdctxput+0x48/0x74) [ 1946.564476] [<c03800ec>] (eventfdctxput) from [<bf5464e8>] (ffsdataclear+0xd0/0x118 [usbffs]) [ 1946.582664] r5:c3b84c00 r4:c2695b00 [ 1946.590668] [<bf546418>] (ffsdataclear [usbffs]) from [<bf547cc0>] (ffsdataclosed+0x9c/0x150 [usbffs]) [ 1946.609608] r5:bf54d014 r4:c2695b00 [ 1946.617522] [<bf547c24>] (ffsdataclosed [usbffs]) from [<bf547da0>] (ffsfskillsb+0x2c/0x30 [usbf_fs]) [ 1946.636217] r7:c0dfcb ---truncated---