Những gì bạn có ở đây chính xác là trường hợp sử dụng của seccomp .
Sử dụng seccomp, bạn có thể lọc các tòa nhà cao tầng theo nhiều cách khác nhau. Những gì bạn muốn làm trong tình huống này là, ngay sau khi fork()
, để cài đặt một seccomp
bộ lọc không cho phép việc sử dụng open(2)
, openat(2)
, socket(2)
(và nhiều hơn nữa). Để thực hiện điều này, bạn có thể làm như sau:
- Đầu tiên, tạo một bối cảnh seccomp sử dụng
seccomp_init(3)
với hành vi mặc định của SCMP_ACT_ALLOW
.
- Sau đó, thêm một quy tắc vào bối cảnh sử dụng
seccomp_rule_add(3)
cho mỗi tòa nhà mà bạn muốn từ chối. Bạn có thể sử dụng SCMP_ACT_KILL
để tiêu diệt quá trình nếu cố gắng tòa nhà, SCMP_ACT_ERRNO(val)
để làm cho tòa nhà không trả lại errno
giá trị được chỉ định hoặc bất kỳ action
giá trị nào khác được xác định trong trang thủ công.
- Tải bối cảnh sử dụng
seccomp_load(3)
để làm cho nó hiệu quả.
Trước khi tiếp tục, LƯU Ý rằng cách tiếp cận danh sách đen như thế này nói chung yếu hơn so với cách tiếp cận danh sách trắng. Nó cho phép bất kỳ tòa nhà chọc trời nào không được phép rõ ràng và có thể dẫn đến bỏ qua bộ lọc . Nếu bạn tin rằng quy trình con bạn muốn thực thi có thể đang cố gắng tránh bộ lọc hoặc nếu bạn đã biết những tòa nhà nào sẽ cần cho trẻ em, thì cách tiếp cận danh sách trắng sẽ tốt hơn và bạn nên làm ngược lại với điều trên: tạo bộ lọc với hành động mặc định của SCMP_ACT_KILL
và cho phép các tòa nhà chọc trời cần thiết với SCMP_ACT_ALLOW
. Về mặt mã, sự khác biệt là tối thiểu (danh sách trắng có thể dài hơn, nhưng các bước là như nhau).
Đây là một ví dụ về những điều trên (Tôi đang làm exit(-1)
trong trường hợp có lỗi chỉ vì đơn giản):
#include <stdlib.h>
#include <seccomp.h>
static void secure(void) {
int err;
scmp_filter_ctx ctx;
int blacklist[] = {
SCMP_SYS(open),
SCMP_SYS(openat),
SCMP_SYS(creat),
SCMP_SYS(socket),
SCMP_SYS(open_by_handle_at),
// ... possibly more ...
};
// Create a new seccomp context, allowing every syscall by default.
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL)
exit(-1);
/* Now add a filter for each syscall that you want to disallow.
In this case, we'll use SCMP_ACT_KILL to kill the process if it
attempts to execute the specified syscall. */
for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
if (err)
exit(-1);
}
// Load the context making it effective.
err = seccomp_load(ctx);
if (err)
exit(-1);
}
Bây giờ, trong chương trình của bạn, bạn có thể gọi hàm trên để áp dụng bộ lọc seccomp ngay sau fork()
, như thế này:
child_pid = fork();
if (child_pid == -1)
exit(-1);
if (child_pid == 0) {
secure();
// Child code here...
exit(0);
} else {
// Parent code here...
}
Một vài lưu ý quan trọng trên seccomp:
- Một bộ lọc seccomp, một khi được áp dụng, không thể được loại bỏ hoặc thay đổi bởi quy trình.
- Nếu
fork(2)
hoặc clone(2)
được bộ lọc cho phép, mọi tiến trình con sẽ bị ràng buộc bởi cùng một bộ lọc.
- Nếu
execve(2)
được cho phép, bộ lọc hiện tại sẽ được duy trì trong suốt cuộc gọi đến execve(2)
.
- Nếu tòa nhà
prctl(2)
được cho phép, quy trình có thể áp dụng các bộ lọc tiếp theo.