In the Linux kernel, the following vulnerability has been resolved: fs/erofs/fileio: call erofsonlinefoliosplit() after bioaddfolio() If bioaddfolio() fails (because it is full), erofsfileioscanfolio() needs to submit the I/O request via erofsfileiorqsubmit() and allocate a new I/O request with an empty struct bio
. Then it retries the bioaddfolio() call. However, at this point, erofsonlinefoliosplit() has already been called which increments folio->private
; the retry will call erofsonlinefoliosplit() again, but there will never be a matching erofsonlinefolioend() call. This leaves the folio locked forever and all waiters will be stuck in foliowaitbitcommon(). This bug has been added by commit ce63cb62d794 ("erofs: support unencoded inodes for fileio"), but was practically unreachable because there was room for 256 folios in the struct bio
- until commit 9f74ae8c9ac9 ("erofs: shorten bvecs[] for file-backed mounts") which reduced the array capacity to 16 folios. It was now trivial to trigger the bug by manually invoking readahead from userspace, e.g.: posixfadvise(fd, 0, st.stsize, POSIXFADVWILLNEED); This should be fixed by invoking erofsonlinefoliosplit() only after bioaddfolio() has succeeded. This is safe: asynchronous completions invoking erofsonlinefolioend() will not unlock the folio because erofsfileioscanfolio() is still holding a reference to be released by erofsonlinefolioend() at the end.