#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <seccomp.h>
#include <errno.h>
// Функция для установки seccomp-фильтра
int apply_seccomp_filter() {
scmp_filter_ctx ctx;
// Создаём контекст с действием по умолчанию KILL (убивать процесс)
ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
perror("seccomp_init");
return -1;
}
// Разрешаем базовые системные вызовы, необходимые для работы C-программы
// Основные syscall'ы для ввода/вывода и управления процессом
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); // Для malloc
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
// Необходимы для работы динамического линковщика и открытия файлов
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(arch_prctl), 0); // Для TLS на x86_64
// Для вывода в консоль (используется printf)
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 0);
// Разрешаем доступ к /etc/ld.so.cache и другим служебным файлам
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getdents64), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(newfstatat), 0);
// Иногда требуется при старте
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
// Загружаем фильтр в ядро
if (seccomp_load(ctx) < 0) {
perror("seccomp_load");
seccomp_release(ctx);
return -1;
}
seccomp_release(ctx);
return 0;
}
int main() {
printf("До применения seccomp-фильтра\n");
// Применяем фильтр
if (apply_seccomp_filter() != 0) {
fprintf(stderr, "Не удалось установить seccomp фильтр\n");
return 1;
}
printf("Seccomp фильтр установлен. Разрешены только ограниченные syscall'ы.\n");
// Тестируем разрешённые операции
FILE *f = fopen("/etc/hostname", "r");
if (f) {
char buf[256];
if (fgets(buf, sizeof(buf), f)) {
printf("Прочитано из файла: %s", buf);
}
fclose(f);
} else {
perror("fopen");
}
// Эта строка отработает нормально, так как write разрешён
printf("Завершаем работу\n");
// Попытка запрещённого syscall'а (например, fork)
pid_t pid = fork();
if (pid == -1) {
perror("fork (должен упасть)");
} else if (pid == 0) {
printf("Дочерний процесс (не должен выполниться)\n");
} else {
wait(NULL);
}
return 0;
}