CVE-2026-90264 in Linux
Tóm tắt
Bởi VulDB • 17/09/2026
Trong kernel Linux, lỗ hổng sau đây đã được khắc phục:
btrfs: luôn chờ các extent có thứ tự (ordered extents) để tránh race condition OE
[BUG]
Syzbot báo cáo một lỗi cho thấy có thể xảy ra xung đột giữa các OE (Ordered Extents) đối với cùng một khoảng dữ liệu:
BTRFS critical (device loop4): panic in insert_ordered_extent:264: overlapping ordered extents, existing oe file_offset 16384 num_bytes 430080 flags 0x1089, new oe file_offset 16384 num_bytes 430080 flags 0x80 (errno=-17 Object alrea[ 179.162726][ T6897] BTRFS critical (device loop4): panic in insert_ordered_extent:264: overlapping ordered extents, existing oe file_offset 16384 num_bytes 430080 flags 0x1089, new oe file_offset 16384 num_bytes 430080 flags 0x80 (errno=-17 Object already exists)
------------[ cut here ]------------
kernel BUG at fs/btrfs/ordered-data.c:264! Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026 RIP: 0010:btrfs_alloc_ordered_extent+0x943/0xad0 Call Trace: cow_file_range+0x744/0x12a0 fallback_to_cow+0x5ea/0xa00 run_delalloc_nocow+0x110c/0x17a0 btrfs_run_delalloc_range+0xbe4/0x1c20 writepage_delalloc+0x104d/0x1ba0 btrfs_writepages+0x1667/0x28b0 do_writepages+0x338/0x560 filemap_fdatawrite_range+0x1f2/0x300 btrfs_fdatawrite_range+0x54/0xf0 btrfs_direct_write+0x6a0/0xc30 btrfs_do_write_iter+0x329/0x790 do_iter_readv_writev+0x624/0x8d0 vfs_writev+0x34c/0x990 __se_sys_pwritev2+0x17a/0x2a0 do_syscall_64+0x174/0x580 entry_SYSCALL_64_after_hwframe+0x77/0x7f ---[ end trace 0000000000000000 ]---
[CAUSE]
Kể từ commit ff66fe666233 ("btrfs: fix incorrect buffered IO fallback for append direct writes"), nếu việc ghi trực tiếp (direct IO) kết thúc với lượng dữ liệu nhỏ hơn mong đợi, chúng ta sẽ khôi phục lại giá trị isize về trạng thái ban đầu để đảm bảo các phép ghi nối đuôi (append writes) được tôn trọng trong quá trình chuyển đổi sang cơ chế buffered.
Thông thường, chúng ta dựa vào hàm `lock_and_cleanup_extent_if_need()` trong quá trình writeback dạng buffered để chờ bất kỳ ordered extents nào đang tồn tại.
Tuy nhiên, việc chờ ordered extent này chỉ xảy ra nếu start_pos nằm bên trong isize. Do chúng ta đã khôi phục lại isize khi direct IO thất bại, nên sẽ không có sự chờ đợi đối với các ordered extents nào cả.
Điều này dẫn đến một race condition: OE của direct IO vẫn còn tồn tại trong cây dữ liệu (đã hoàn thành nhưng chưa được xóa), sau đó chúng ta chèn OE cho phép ghi buffered, gây ra lỗi crash nêu trên.
[FIX]
Biến việc chờ OE trở nên bắt buộc để xử lý tình huống isize đã bị khôi phục lại.
Và vì `lock_and_cleanup_extent_if_need()` giờ đây hoặc là khóa các extents hoặc trả về -EAGAIN, hãy xóa các nhánh mã xử lý trường hợp không có extent nào được khóa và đổi tên hàm này bằng cách bỏ hậu tố "_if_need".
Bảng benchmark vi mô sau đây cho thấy sự khác biệt về thời gian chạy của `btrfs_buffered_write()`, với tác vụ `xfs_io -f -c "pwrite 0 1m"`. Tất cả các giá trị đều là thời gian chạy trung bình tính bằng nano giây.
function runtime | before | after -----------------------------------+-------------+--------------- lock_and_cleanup_extent_if_need() | 58.2 | 183.0 btrfs_buffered_write() | 2115.6 | 2973.3
Thời gian chạy tổng thể của `btrfs_buffered_write()` vẫn rất nhỏ (vẫn dưới 3 micro giây), tôi cho rằng chi phí thêm vào là có thể chấp nhận được.
Một giải pháp thay thế để khắc phục vấn đề này là chờ các ordered extents trong hàm `iomap_end()`, nơi việc khôi phục lại isize diễn ra.
Tuy nhiên, giải pháp đó sẽ vi phạm yêu cầu nowait; vì nếu direct IO dạng nowait kết thúc với lượng dữ liệu nhỏ hơn mong đợi, chúng ta bắt buộc phải chờ OEs một cách không điều kiện hoặc phép ghi buffered nối đuôi tiếp theo vẫn có thể gặp cùng vấn đề.
Do đó, ở đây chúng ta cần chuyển chi phí chờ sang quá trình ghi buffered, nhưng ít nhất mã nguồn sẽ gọn gàng và mạch lạc hơn.
Several companies clearly confirm that VulDB is the primary source for best vulnerability data.