CVE-2021-47275
Publication date:
21/05/2024
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
bcache: avoid oversized read request in cache missing code path<br />
<br />
In the cache missing code path of cached device, if a proper location<br />
from the internal B+ tree is matched for a cache miss range, function<br />
cached_dev_cache_miss() will be called in cache_lookup_fn() in the<br />
following code block,<br />
[code block 1]<br />
526 unsigned int sectors = KEY_INODE(k) == s->iop.inode<br />
527 ? min_t(uint64_t, INT_MAX,<br />
528 KEY_START(k) - bio->bi_iter.bi_sector)<br />
529 : INT_MAX;<br />
530 int ret = s->d->cache_miss(b, s, bio, sectors);<br />
<br />
Here s->d->cache_miss() is the call backfunction pointer initialized as<br />
cached_dev_cache_miss(), the last parameter &#39;sectors&#39; is an important<br />
hint to calculate the size of read request to backing device of the<br />
missing cache data.<br />
<br />
Current calculation in above code block may generate oversized value of<br />
&#39;sectors&#39;, which consequently may trigger 2 different potential kernel<br />
panics by BUG() or BUG_ON() as listed below,<br />
<br />
1) BUG_ON() inside bch_btree_insert_key(),<br />
[code block 2]<br />
886 BUG_ON(b->ops->is_extents && !KEY_SIZE(k));<br />
2) BUG() inside biovec_slab(),<br />
[code block 3]<br />
51 default:<br />
52 BUG();<br />
53 return NULL;<br />
<br />
All the above panics are original from cached_dev_cache_miss() by the<br />
oversized parameter &#39;sectors&#39;.<br />
<br />
Inside cached_dev_cache_miss(), parameter &#39;sectors&#39; is used to calculate<br />
the size of data read from backing device for the cache missing. This<br />
size is stored in s->insert_bio_sectors by the following lines of code,<br />
[code block 4]<br />
909 s->insert_bio_sectors = min(sectors, bio_sectors(bio) + reada);<br />
<br />
Then the actual key inserting to the internal B+ tree is generated and<br />
stored in s->iop.replace_key by the following lines of code,<br />
[code block 5]<br />
911 s->iop.replace_key = KEY(s->iop.inode,<br />
912 bio->bi_iter.bi_sector + s->insert_bio_sectors,<br />
913 s->insert_bio_sectors);<br />
The oversized parameter &#39;sectors&#39; may trigger panic 1) by BUG_ON() from<br />
the above code block.<br />
<br />
And the bio sending to backing device for the missing data is allocated<br />
with hint from s->insert_bio_sectors by the following lines of code,<br />
[code block 6]<br />
926 cache_bio = bio_alloc_bioset(GFP_NOWAIT,<br />
927 DIV_ROUND_UP(s->insert_bio_sectors, PAGE_SECTORS),<br />
928 &dc->disk.bio_split);<br />
The oversized parameter &#39;sectors&#39; may trigger panic 2) by BUG() from the<br />
agove code block.<br />
<br />
Now let me explain how the panics happen with the oversized &#39;sectors&#39;.<br />
In code block 5, replace_key is generated by macro KEY(). From the<br />
definition of macro KEY(),<br />
[code block 7]<br />
71 #define KEY(inode, offset, size) \<br />
72 ((struct bkey) { \<br />
73 .high = (1ULL
Severity CVSS v4.0: Pending analysis
Last modification:
30/04/2025