CVE-2022-50549CVE-2022-50549是Linux内核中dm thin(device-mapper thin provisioning)子系统存在的一个ABBA死锁漏洞。该漏洞涉及内核shrink_slab内存回收机制与dm_pool_abort_metadata元数据中止操作之间的锁竞争问题。当系统执行drop_caches操作触发内存回收(shrink_slab)时,会获取shrinker_rwsem读锁(LOCK A),随后通过ext4文件系统路径调用submit_bh提交BIO请求。在BIO处理过程中,dm thin的kworker线程在处理延迟BIOS时,如果检测到元数据操作失败,会调用dm_pool_abort_metadata,该函数需要获取pmd->root_lock的写锁(LOCK B),进而调用dm_bufio_client_destroy和unregister_shrinker,后者需要获取shrinker_rwsem的写锁。与此同时,在shrink_slab路径中,ext4_read_block_bitmap_nowait通过submit_bh提交新的BIO,该BIO在dm层经过thin_map处理时,需要获取pmd->root_lock的读锁。由于shrinker_rwsem的读锁和写锁形成循环等待,导致系统出现ABBA死锁。触发该死锁后,受影响的进程将进入D状态(不可中断睡眠),系统会报出hung task警告,严重时导致系统无响应。该漏洞影响Linux 6.1.0-rc4及之前的多个稳定版本内核,需要本地低权限用户通过触发drop_caches或类似内存回收路径来利用。
该漏洞的核心是Linux内核dm thin模块中存在的锁顺序倒置问题。具体技术原理如下:
1. **锁竞争路径**:P1进程(drop cache路径)通过shrink_slab获取shrinker_rwsem读锁后,在ext4_evict_inode → ext4_discard_preallocations → ext4_mb_load_buddy_gfp → ext4_mb_init_cache → ext4_read_block_bitmap_nowait → submit_bh路径中提交BIO请求。
2. **死锁形成**:P2进程(kworker)在do_worker中处理process_deferred_bios,调用commit时若检测到metadata_operation_failed,则执行dm_pool_abort_metadata,获取pmd->root_lock写锁后调用dm_bufio_client_destroy,进而调用unregister_shrinker尝试获取shrinker_rwsem写锁。
3. **ABBA模式**:P1持有shrinker_rwsem读锁,等待pmd->root_lock读锁(通过thin_map → dm_thin_find_block);P2持有pmd->root_lock写锁,等待shrinker_rwsem写锁。形成典型的ABBA死锁。
4. **触发条件**:需要dm thin设备上存在ext4文件系统,且系统执行drop_caches操作或类似触发内存回收的路径,同时dm thin的元数据操作发生失败。
5. **修复方案**:通过调整锁的获取顺序或使用trylock机制避免死锁。修复提交通过重构dm_bufio_client_destroy和unregister_shrinker的调用顺序来解决该问题。