Tìm hiểu lỗ hổng Use-After-Free trong bộ thu gom rác AF_UNIX của Linux Kernel

10 tháng 6, 2026·4 phút đọc

Bài viết phân tích quá trình tái thiết bộ thu gom rác AF_UNIX trong nhân Linux sử dụng mô hình đồ thị và thuật toán Tarjan để tối ưu hóa hiệu suất. Đồng thời, tác giả cũng đi sâu vào chi tiết của một lỗ hổng bảo mật nghiêm trọng kiểu Use-After-Free (CVE-2025-40214) xuất hiện trong quá trình triển khai mới này.

Tìm hiểu lỗ hổng Use-After-Free trong bộ thu gom rác AF_UNIX của Linux Kernel

Bộ thu gom rác (Garbage Collector - GC) của AF_UNIX là một thành phần thú vị nhưng phức tạp trong nhân Linux. Nó ra đời để giải quyết vấn đề rò rỉ bộ nhớ khi các socket được gửi đi thông qua SCM_RIGHTS nhưng không còn thể tiếp cận được từ không gian người dùng (user-space), dù vẫn được nhân duy trì. Gần đây, hệ thống con này đã được viết lại hoàn toàn dựa trên mô hình đồ thị và các thành phần liên thông mạnh (Strongly Connected Components - SCC). Tuy nhiên, quá trình tái thiết này lại vô tình sinh ra một lỗ hổng bảo mật nghiêm trọng.

Mô hình đồ thị các socketMô hình đồ thị các socket

Tại sao cần bộ thu gom rác AF_UNIX?

Trong Linux, khi một socket được gửi từ tiến trình A sang tiến trình B bằng cách sử dụng SCM_RIGHTS, nó được đánh dấu là "inflight" (đang trên đường). Nếu cả hai tiến trình đóng socket của mình mà không nhận lại socket đã gửi, các tham chiếu trong nhân vẫn còn tồn tại, khiến bộ nhớ không bao giờ được giải phóng.

Trước đây, cơ chế GC cũ hoạt động bằng cách khóa từng hàng đợi nhận của socket, gây ra hiệu suất kém và các lỗi khó lường. Phiên bản mới được thiết kế để không khóa từng socket mà thay vào đó xây dựng một đồ thị có hướng để quản lý các mối quan hệ này.

Mô hình đồ thị và thuật toán Tarjan

Trong thiết kế mới, mỗi socket inflight trở thành một đỉnh (vertex), và mỗi con trỏ struct file được gửi đi trở thành một cạnh (edge) có hướng. Mục tiêu là tìm ra các chu trình (cycles) trong đồ thị này, nơi các socket giữ lẫn nhau và không thể tiếp cận từ bên ngoài.

Thuật toán TarjanThuật toán Tarjan

Nhân Linux sử dụng thuật toán Tarjan để phân chia đồ thị thành các thành phần liên thông mạnh (SCC). Bất kỳ SCC nào có nhiều hơn một đỉnh chắc chắn chứa một chu trình. Nếu một chu trình thỏa mãn điều kiện file_count == out_degree (số lượng tham chiếu bằng số lượng cạnh đi ra), nó sẽ được coi là "rác" và bị giải phóng.

Quá trình này có độ phức tạp là O(|V| + |E|), giúp cải thiện hiệu suất đáng kể so với phương pháp cũ.

Lỗ hổng Use-After-Free (CVE-2025-40214)

Mặc dù được thiết kế kỹ lưỡng, bản viết lại lại chứa một lỗi khởi tạo biến dẫn đến lỗ hổng Use-After-Free nghiêm trọng.

Vấn đề nằm ở cấu trúc struct unix_vertex, đại diện cho một đỉnh trong đồ thị. Hàm unix_add_edge() cấp phát bộ nhớ cho cấu trúc này nhưng lại quên khởi tạo trường scc_index. Trên kiến trúc x86_64, struct unix_vertex có kích thước 72 byte và nằm trong cache kmalloc-96.

Sơ đồ luồng dữ liệuSơ đồ luồng dữ liệu

Khi một vertex được giải phóng, nó quay lại danh sách tự do (freelist) của kmalloc nhưng vẫn giữ lại dữ liệu cũ. Nếu một vertex mới được cấp phát ngay sau đó tại cùng vị trí bộ nhớ, trường scc_index có thể kế thừa giá trị cũ này.

Kẻ tấn công có thể khai thác tình huống này bằng cách tạo ra một chu trình socket, kích hoạt GC để gán scc_index = 2 cho các vertex trong chu trình đó, sau đó giải phóng chúng. Khi vertex mới được cấp phát từ bộ nhớ đã giải phóng này, nó mang theo scc_index = 2.

Nếu một socket đang hoạt động (live socket) cũng có scc_index = 2, hàm kiểm tra nhanh unix_vertex_dead() sẽ nhầm lẫn, cho rằng socket đang hoạt động này đã chết và xóa sạch hàng đợi nhận của nó. Điều này dẫn đến lỗi Use-After-Free, cho phép kẻ tấn công ghi đè bộ nhớ hoặc leo thang đặc quyền.

Giải pháp và kết luận

Bản vá sửa lỗi đã được đưa ra bằng cách sử dụng một bộ đếm unix_vertex_max_scc_index tăng đơn điệu. Mỗi khi một vertex mới được cấp phát, trường scc_index sẽ được gán một giá trị duy nhất từ bộ đếm này, đảm bảo không có sự trùng lặp ngẫu nhiên nào xảy ra giữa các vertex cũ và mới.

Vụ việc này một lần nữa nhắc nhở chúng ta về sự khó khăn trong lập trình nhân: ngay cả những thuật toán đã được kiểm chứng kỹ lưỡng như Tarjan cũng có thể gây ra rủi ro bảo mật nghiêm trọng nếu việc quản lý bộ nhớ không được thực hiện cẩn trọng.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗