Безопасность компьютерных систем 2019/SECCOMP
Материал из Wiki - Факультет компьютерных наук
Версия от 13:09, 25 ноября 2019; Gamajun (обсуждение | вклад)
Содержание
Linux seccomp
Ссылки для изучения:
- Рекомендуемая основная презентация (пригодится для выполнения бонусного задания к заданию 3): http://events.linuxfoundation.org/sites/events/files/slides/limiting_kernel_attack_surface_with_seccomp-ContainerCon.eu_2016-Kerrisk.pdf
- https://eigenstate.org/notes/seccomp
- Kafel - язык для конструирования политик seccomp (not an official Google product) https://github.com/google/kafel
Тестовый пример 1
#include <stdio.h> #include <unistd.h> #include <linux/seccomp.h> #include <sys/prctl.h> int main () { pid_t pid; printf("Step 1: no restrictions yet\n"); prctl (PR_SET_SECCOMP, SECCOMP_MODE_STRICT); printf ("Step 2: entering the strict mode. Only read(), write(), exit() and sigreturn() syscalls are allowed\n"); pid = getpid (); printf ("!!YOU SHOULD NOT SEE THIS!! My PID = %d", pid); return 0; }
Тестовый пример 2
#include <stdio.h> #include <seccomp.h> #include <unistd.h> #include <sys/fcntl.h> #include <errno.h> int main() { pid_t pid; scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP); 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(sigreturn), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); printf ("No restrictions yet\n"); seccomp_load(ctx); pid = getpid(); printf("!! YOU SHOULD NOT SEE THIS!! My PID is%d\n", pid); return 0; }
Тестовый пример 3
/*************************************************************************\ * Copyright (C) Michael Kerrisk, 2016. * * * * This program is free software. You may use, modify, and redistribute it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation, either version 3 or (at your option) any * * later version. This program is distributed without any warranty. See * * the file COPYING.gpl-v3 for details. * \*************************************************************************/ /* Supplementary program for Chapter Z */ /* seccomp_deny.c A simple seccomp filter example. Install a filter that kills the process if open() is called. */ #define _GNU_SOURCE #include <stddef.h> #include <fcntl.h> #include <linux/audit.h> #include <sys/syscall.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <sys/prctl.h> #include <sys/types.h> /* Type definitions used by many programs */ #include <stdio.h> /* Standard I/O functions */ #include <stdlib.h> /* Prototypes of commonly used library functions, plus EXIT_SUCCESS and EXIT_FAILURE constants */ #include <unistd.h> /* Prototypes for many system calls */ #include <errno.h> /* Declares errno and defines error constants */ #include <string.h> /* Commonly used string-handling functions */ static int seccomp(unsigned int operation, unsigned int flags, void *args) { return syscall(__NR_seccomp, operation, flags, args); } static void install_filter(void) { struct sock_filter filter[] = { /* Load architecture */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Kill process if the architecture is not what we expect */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), /* Load system call number */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), /* Allow system calls other than open() */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /* Kill process on open() */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) == -1) perror("seccomp"); /* On Linux 3.16 and earlier, we must instead use: if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) errExit("prctl-PR_SET_SECCOMP"); */ } int main(int argc, char **argv) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) perror("prctl"); install_filter(); if (open("/tmp/a", O_RDONLY) == -1) perror("open"); printf("We shouldn't see this message\n"); exit(EXIT_SUCCESS); }
Тестовый пример 4
#include <stdlib.h> #include <stdio.h> #include <stddef.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/prctl.h> #include <sys/syscall.h> #include <sys/socket.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <linux/audit.h> #define ArchField offsetof(struct seccomp_data, arch) #define Allow(syscall) \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_##syscall, 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) struct sock_filter filter[] = { /* validate arch */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ArchField), BPF_JUMP( BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP), /* load syscall */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), /* list of allowed syscalls */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_brk, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_mmap, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_munmap, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_write, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_exit, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), /* and if we don't match above, die */ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), }; struct sock_fprog filterprog = { .len = sizeof(filter)/sizeof(filter[0]), .filter = filter }; int main(int argc, char **argv) { char buf[1024]; /* set up the restricted environment */ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("Could not start seccomp:"); exit(1); } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &filterprog) == -1) { perror("Could not start seccomp:"); exit(1); } /* printf only writes to stdout, but for some reason it stats it. */ printf("hello there!\n"); if (argc > 1 && strcmp(argv[1], "haxor") == 0) { int fd = socket(AF_INET6, SOCK_STREAM, 0); /* ...and start sending spam */ } }