Hệ điều hành · 03/10/2026

Linux Landlock thực chiến: Sandbox ứng dụng không cần quyền root

Một công cụ chuyển đổi ảnh chỉ cần đọc thư mục input, ghi thư mục output và nạp vài thư viện hệ thống. Nếu parser bị khai thác, tại sao tiến trình vẫn có thể đọc SSH key, quét toàn filesystem hoặc kết nối tới dịch vụ khác? Linux Landlock cho phép chính ứng dụng — kể cả tiến trình không đặc quyền — tự thu hẹp quyền truy cập của mình trước khi xử lý dữ liệu không tin cậy.

Linux Landlock thực chiến: Sandbox ứng dụng không cần quyền root

Một công cụ chuyển đổi ảnh chỉ cần đọc thư mục input, ghi thư mục output và nạp vài thư viện hệ thống. Nếu parser bị khai thác, tại sao tiến trình vẫn có thể đọc SSH key, quét toàn filesystem hoặc kết nối tới dịch vụ khác? Linux Landlock cho phép chính ứng dụng — kể cả tiến trình không đặc quyền — tự thu hẹp quyền truy cập của mình trước khi xử lý dữ liệu không tin cậy.

Bài này xây dựng mô hình triển khai Landlock thực tế: kiểm tra ABI lúc chạy, tạo ruleset deny-by-default cho các quyền được quản lý, allowlist cây thư mục, áp policy trước khi sinh thread, mở rộng sang port mạng và kiểm thử fail-closed. Nội dung được đối chiếu với tài liệu Landlock của Linux kernel, landlock(7) và ba system call create_ruleset, add_rule, restrict_self.

1. Landlock là gì?

Landlock là một Linux Security Module (LSM) có thể xếp chồng với các cơ chế kiểm soát khác. Mục tiêu của nó là cho phép tiến trình tự hạn chế ambient rights — những quyền mà tiến trình vốn có qua UID/GID, file mode và môi trường hiện tại. Landlock xuất hiện từ Linux 5.13 và tiếp tục được mở rộng qua các phiên bản ABI.

Ba system call tạo nên luồng chính:

  1. landlock_create_ruleset(): khai báo nhóm loại truy cập mà sandbox sẽ quản lý.
  2. landlock_add_rule(): thêm object và quyền được phép, ví dụ một cây thư mục hoặc port.
  3. landlock_restrict_self(): áp ruleset lên thread gọi và các tiến trình con tương lai.

Policy chỉ có thể làm quyền hẹp hơn, không cấp thêm quyền vượt DAC, ACL, SELinux hay AppArmor. Sau khi áp, tiến trình không thể gỡ policy; ruleset xếp chồng sau đó chỉ có thể hạn chế thêm.

2. Landlock không thay thế những lớp nào?

Cơ chếPhạm vi chínhQuan hệ với Landlock
DAC/ACLQuyền user/group trên fileLandlock chỉ thu hẹp kết quả đã được DAC/ACL cho phép.
SELinux/AppArmorMandatory policy toàn hệ thốngTiếp tục áp dụng; quyết định cuối phải qua mọi lớp.
seccompLọc system call và argumentBổ sung nhau: seccomp lọc syscall, Landlock kiểm soát object.
namespace/containerTách view tài nguyênLandlock thêm lớp giới hạn bên trong namespace.
systemd sandboxHạn chế service qua unit settingsCó thể xếp chồng với policy tích hợp trong ứng dụng.
chrootĐổi root path resolutionKhông phải security boundary hoàn chỉnh; khác mô hình Landlock.

Landlock đặc biệt hữu ích khi developer biết chính xác ứng dụng cần object nào và muốn policy đi cùng binary. Quản trị viên vẫn nên giữ hardening ở cấp service/container vì ứng dụng có thể chạy trên kernel không hỗ trợ hoặc policy tích hợp có lỗi.

3. Mô hình handled access và allowed access

Đây là phần dễ hiểu sai nhất. Khi tạo ruleset, ứng dụng khai báo các access right mà ruleset handled. Với các loại đó, hành vi mặc định là từ chối; sau đó từng rule cho phép một tập con trên object cụ thể.

Ví dụ ứng dụng quản lý các quyền đọc, ghi và execute:

handled_access_fs =
    LANDLOCK_ACCESS_FS_EXECUTE |
    LANDLOCK_ACCESS_FS_READ_FILE |
    LANDLOCK_ACCESS_FS_READ_DIR |
    LANDLOCK_ACCESS_FS_WRITE_FILE |
    LANDLOCK_ACCESS_FS_TRUNCATE;

Sau đó rule cho /usr có thể chỉ allow read/execute, rule cho /srv/converter/output allow read/write/truncate. Một access right không nằm trong handled_access_fs không tự nhiên bị Landlock chặn. Vì vậy khai báo thiếu không phải deny-by-default toàn filesystem; nó chỉ bỏ loại hành động đó ra khỏi contract của ruleset.

Landlock dùng allowlist cho các quyền đã chọn quản lý. “Không thêm rule deny” không có nghĩa là cho phép; object không có rule phù hợp sẽ bị từ chối với các handled access.

4. Kiểm tra kernel và ABI lúc chạy

Đừng suy luận từ tên distribution hoặc version kernel do vendor có thể backport hay tắt LSM. Quản trị viên có thể xem log boot:

sudo dmesg | grep -i landlock
# hoặc
sudo journalctl -kb -g landlock

Ứng dụng nên hỏi ABI bằng system call:

int abi = syscall(
    SYS_landlock_create_ruleset,
    NULL,
    0,
    LANDLOCK_CREATE_RULESET_VERSION
);

Kết quả không âm là version ABI khả dụng. Các lỗi cần phân biệt:

  • ENOSYS: kernel không có system call.
  • EOPNOTSUPP: kernel có Landlock nhưng bị tắt lúc boot.
  • EPERM ở bước enforce: thường liên quan no_new_privs/capability hoặc trạng thái caller.
  • EINVAL: flag/access không được ABI hỗ trợ hoặc cấu trúc không hợp lệ.

Policy production phải xác định rõ hai chế độ:

  • Best effort: dùng tập tính năng mà ABI hiện tại hỗ trợ và ghi metric cảnh báo khi giảm bảo vệ.
  • Fail closed: từ chối khởi động nếu thiếu ABI/quyền tối thiểu bắt buộc.

Không silently continue nếu tài liệu bảo mật tuyên bố Landlock là ranh giới bắt buộc.

5. ABI là contract tương thích, không phải số phiên bản để hardcode

Mỗi ABI bổ sung khả năng. Một số mốc quan trọng trong tài liệu kernel hiện hành:

ABIKhả năng tiêu biểuÝ nghĩa
1Filesystem access cơ bảnNền tảng read/write/execute và tạo/xóa object.
2REFERKiểm soát rename/link giữa hierarchy.
3TRUNCATEChặn truncate file rõ ràng.
4TCP bind/connect theo portBắt đầu kiểm soát network.
5Device ioctlHạn chế ioctl trên character/block device.
6Scope signal và abstract UNIX socketGiới hạn IPC theo domain.
8Thread synchronizationÁp domain đồng bộ lên các thread.
9Pathname UNIX socketKiểm soát resolve/connect socket theo path.
10UDP và quiet rulesKiểm soát port UDP, tinh chỉnh log deny.
11Flag thiết lập no_new_privsEnforce ruleset và NNP theo contract mới.

Ứng dụng nên bắt đầu với mask quyền mong muốn, rồi loại các bit không được ABI hỗ trợ trước khi tạo ruleset. Không gửi flag tương lai vào kernel cũ vì lời gọi sẽ thất bại; cũng không tự động thêm quyền mới sau khi kernel nâng cấp vì điều đó có thể làm ứng dụng bị chặn bất ngờ.

6. Xây ruleset filesystem theo nhu cầu thật

Một image converter có thể cần:

  • read/execute runtime dưới /usr và thư viện dưới /lib*;
  • read input ở /srv/converter/input;
  • read/write/create/truncate ở /srv/converter/output;
  • read một số file cấu hình/CA ở /etc;
  • không truy cập /home, SSH key, backup hoặc socket quản trị.

Luồng thêm một path rule ở mức C:

int parent_fd = open(path, O_PATH | O_CLOEXEC);

struct landlock_path_beneath_attr rule = {
    .parent_fd = parent_fd,
    .allowed_access = allowed_access,
};

syscall(
    SYS_landlock_add_rule,
    ruleset_fd,
    LANDLOCK_RULE_PATH_BENEATH,
    &rule,
    0
);

close(parent_fd);

Mở path bằng O_PATH trước khi enforce để lấy file descriptor đại diện hierarchy. Chuẩn hóa cấu hình, từ chối symlink/path ngoài dự kiến và log rule đã áp. Đừng nhận một danh sách path tùy ý từ input không tin cậy rồi biến nó thành allowlist.

Quyền cho thư mục output cần đủ cho workflow thực tế: ứng dụng có thể tạo file tạm, rename atomic, chmod hoặc xóa file cũ. Test bằng syscall thực, không chỉ test “ghi một file mới”.

7. Áp policy đúng thời điểm

Trình tự an toàn thường là:

  1. Parse và validate cấu hình tin cậy.
  2. Mở resource tối thiểu cần để xây ruleset.
  3. Đóng file descriptor, socket và TTY không cần thiết.
  4. Tạo ruleset và thêm mọi rule.
  5. Thiết lập no_new_privs hoặc dùng cơ chế ABI phù hợp.
  6. Enforce Landlock.
  7. Chỉ sau đó mới parse file/upload/request không tin cậy và sinh worker.

Với ABI truyền thống, tiến trình không có CAP_SYS_ADMIN cần:

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
syscall(SYS_landlock_restrict_self, ruleset_fd, 0);

no_new_privs ngăn execve giành thêm privilege qua setuid/file capability. ABI mới có flag giúp gắn bước này vào enforce, nhưng code vẫn phải query ABI và chọn đường tương thích.

Policy áp lên calling thread và con tương lai. Ứng dụng đa luồng nên sandbox trước khi tạo thread. Tính năng TSYNC ở ABI mới có thể đồng bộ domain lên mọi thread, nhưng phải kiểm tra support và xử lý failure như một lỗi security, không bỏ qua.

8. File descriptor mở sẵn và TOCTOU

Sandbox muộn là một lỗi thiết kế phổ biến. File descriptor/socket đã mở có thể tiếp tục mang quyền truy cập hữu ích sau khi policy áp, tùy operation. Vì vậy hãy coi descriptor là capability:

  • liệt kê và đóng descriptor không cần trước sandbox;
  • dùng O_CLOEXEC mặc định;
  • không thừa kế stdin/stdout/stderr trỏ tới TTY hoặc file nhạy cảm nếu worker không cần;
  • tránh mở toàn bộ filesystem rồi mới “khóa cửa”;
  • không dựa vào path string đã kiểm tra nếu sau đó attacker có thể đổi symlink/hierarchy.

Landlock dựa trên object/hierarchy và xử lý nhiều vấn đề path tốt hơn một bộ lọc string tự viết, nhưng ứng dụng vẫn cần mở file an toàn, kiểm soát symlink và thiết kế ownership directory hợp lý.

9. Network rules kiểm soát port, không thay firewall

Từ ABI 4, Landlock có thể hạn chế TCP bind/connect theo port. ABI mới hơn bổ sung UDP bind và connect/send. Ví dụ policy worker chỉ được kết nối TCP tới port 443:

struct landlock_net_port_attr net_rule = {
    .port = 443,
    .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
};

syscall(
    SYS_landlock_add_rule,
    ruleset_fd,
    LANDLOCK_RULE_NET_PORT,
    &net_rule,
    0
);

Đây không phải allowlist IP/domain. Nếu cho connect port 443, tiến trình có thể kết nối nhiều địa chỉ dùng port đó, tùy các lớp mạng khác. Dùng firewall, network namespace, proxy egress hoặc policy của orchestrator để giới hạn destination; Landlock thêm một lớp theo hành động/port.

DNS cũng phải được tính đến: resolver có thể cần UDP/TCP 53 hoặc UNIX socket của local resolver. Đừng mở rộng policy mù khi thấy lỗi; trace syscall và xác định dependency thật.

10. Scope signal và UNIX socket

Landlock ABI mới có thể scope signal và abstract UNIX socket theo domain; pathname UNIX socket có quyền resolve riêng. Các cơ chế này hữu ích để worker bị xâm nhập không signal hoặc kết nối tới process/socket ngoài sandbox.

Scope không hoạt động như path/port allowlist có exception tùy ý. Khi thiết kế IPC, xác định process nào cùng domain, thời điểm fork/exec và socket nào cần dùng. Một kiến trúc supervisor mở resource đặc quyền rồi truyền descriptor có kiểm soát cho worker thường dễ audit hơn việc cho worker tự khám phá mọi socket.

11. Logging, audit và chẩn đoán EACCES

Khi ứng dụng bắt đầu fail với EACCES, đừng nới toàn bộ /. Ghi lại ABI, handled masks, từng rule, binary version và phase enforce. Kernel mới có audit/tracepoint Landlock và các flag kiểm soát logging; khả năng cụ thể phụ thuộc ABI/kernel.

Quy trình debug:

  1. Tái hiện bằng input vô hại trong staging.
  2. Dùng strace để xác định syscall, path/port và errno.
  3. Đọc audit/trace event nếu kernel hỗ trợ.
  4. Xác định access right thiếu, không chỉ path thiếu.
  5. Thêm rule hẹp nhất và tạo regression test.

Logging deny có thể bị spam bởi process lỗi hoặc bị khai thác. Rate limit và retention phải được thiết kế, nhưng không tắt toàn bộ telemetry trước khi có cách quan sát thay thế.

12. Những giới hạn phải đưa vào threat model

  • Kernel/ABI cũ không kiểm soát một số action mới như truncate, network, ioctl hoặc UDP.
  • Filesystem đặc biệt và object không biểu diễn như file/path thông thường có giới hạn riêng.
  • Landlock không giới hạn CPU, RAM, số process hay disk quota; dùng cgroup/resource limits.
  • Network rule theo port không phải destination firewall.
  • Landlock không sửa lỗ hổng kernel và không bảo vệ khỏi mọi side channel.
  • Policy tích hợp sai có thể fail open hoặc phá chức năng ứng dụng.
  • Descriptor/resource được cấp trước sandbox cần được audit riêng.

Đọc mục “Current limitations”, ABI versions và errata trong tài liệu kernel cho đúng phiên bản production; không sao chép một policy cũ rồi mặc định mọi access đã được quản lý.

13. Kiểm thử policy như một API contract

Bộ test cần cả positive và negative cases:

TestKỳ vọng
Đọc input hợp lệThành công.
Ghi file tạm và rename vào outputThành công nếu workflow yêu cầu.
Đọc ~/.ssh/id_ed25519EACCES.
Ghi ra ngoài outputEACCES.
Execute binary ngoài runtime allowlistBị từ chối.
Connect port không được phépBị từ chối khi ABI network được yêu cầu.
Kernel thiếu ABI tối thiểuFail closed hoặc degrade có metric đúng policy.
Worker/con sinh sau enforceKế thừa hạn chế.

Chạy test trên kernel thấp nhất và cao nhất được hỗ trợ. CI container có thể không phản ánh LSM/boot config của host, nên cần runner/kernel integration thật cho security test.

14. Checklist production

  • Viết threat model và danh sách filesystem/network access tối thiểu.
  • Query ABI runtime, không suy luận từ distro version.
  • Chọn rõ best-effort hay fail-closed và phát metric khi giảm bảo vệ.
  • Chỉ khai báo access bit được ABI hỗ trợ.
  • Dùng allowlist hẹp cho runtime, input, output, config và port.
  • Đóng descriptor không cần và enforce trước input không tin cậy/thread.
  • Xếp chồng Landlock với DAC, seccomp, systemd/container và firewall.
  • Test cả allow và deny trên kernel production.
  • Quan sát audit/trace/EACCES và giữ rollback policy có kiểm soát.
  • Theo dõi ABI mới và errata thay vì tự động bật tính năng mới.

Kết luận

Landlock đưa nguyên tắc least privilege vào bên trong ứng dụng: process không root có thể tự tuyên bố “từ thời điểm này, tôi chỉ cần những cây thư mục và port này”. Giá trị lớn nhất không nằm ở một syscall riêng lẻ mà ở trình tự thiết kế: query ABI, quản lý đúng access bits, allowlist object, đóng capability cũ và enforce trước dữ liệu không tin cậy. Khi được xếp chồng với các lớp hardening hệ thống, Landlock giúp biến một lỗi parser hoặc plugin thành sự cố bị giới hạn thay vì quyền truy cập lan ra toàn server.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.