1. 코드 분석
1. tlpi-dist/seccomp/dump_seccomp_filter.c
1. 코드
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include <fcntl.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
static struct sock_filter *
fetchFilter(pid_t pid, int filterIndex, int *instrCnt, bool quiet)
{
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
if (!quiet)
fprintf(stderr, "%ld: could not PTRACE_ATTACH (%s)\n", (long) pid,
strerror(errno));
exit(EXIT_FAILURE);
}
if (waitpid(pid, NULL, 0) == -1)
errExit("waitpid");
int icnt = ptrace(PTRACE_SECCOMP_GET_FILTER, pid, filterIndex, NULL);
if (icnt == -1) {
if (errno == EINVAL) {
if (!quiet)
fprintf(stderr, "%ld: does not have any BPF filters\n",
(long) pid);
exit(EXIT_FAILURE);
} else if (errno == ENOENT) {
if (!quiet)
fprintf(stderr, "%ld: no BPF program exists at index %d\n",
(long) pid, filterIndex);
exit(EXIT_FAILURE);
} else if (errno == EACCES) {
fprintf(stderr, "You lack the CAP_SYS_ADMIN capability; "
"run this program as root\n");
exit(EXIT_FAILURE);
} else {
errExit("ptrace - PTRACE_SECCOMP_GET_FILTER-1");
}
}
struct sock_filter *filterProg;
filterProg = calloc(icnt, sizeof(struct sock_filter));
if (filterProg == NULL)
errExit("calloc");
icnt = ptrace(PTRACE_SECCOMP_GET_FILTER, pid, filterIndex, filterProg);
if (icnt == -1)
errExit("ptrace - PTRACE_SECCOMP_GET_FILTER-2");
if (instrCnt != NULL)
*instrCnt = icnt;
return filterProg;
}
static void
dumpFilter(char *pathname, struct sock_filter *filterProg, int instrCnt)
{
int fd = open(pathname, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
if (fd == -1)
errExit("open");
if (write(fd, filterProg, instrCnt * sizeof(struct sock_filter)) == -1)
errExit("write");
if (close(fd) == -1)
errExit("close");
}
static void
usageError(char *pname, char *msg)
{
fprintf(stderr, "%s", msg);
fprintf(stderr, "Usage: %s [-q] PID dump-file [filter-index]\n", pname);
fprintf(stderr, " <filter-index> defaults to 0 (the most recently "
"installed filter)\n");
fprintf(stderr, " -q Quiet mode; don't print messages on success "
"or on expected errors\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
bool quiet = false;
int opt;
while ((opt = getopt(argc, argv, "q")) != -1) {
switch (opt) {
case 'q':
quiet = true;
break;
default:
usageError(argv[0], "Bad option\n");
}
}
if (optind + 2 > argc)
usageError(argv[0], "Missing arguments\n");
pid_t pid = atoi(argv[optind]);
int filterIndex = (argc > optind + 2) ? atoi(argv[optind + 2]) : 0;
int instrCnt;
struct sock_filter *filterProg = fetchFilter(pid, filterIndex, &instrCnt,
quiet);
dumpFilter(argv[optind + 1], filterProg, instrCnt);
free(filterProg);
if (!quiet)
printf("%ld: dumped %d BPF instructions from filter %d\n", (long) pid,
instrCnt, filterIndex);
exit(EXIT_SUCCESS);
}
2. 동작 모습
- 응용 프로그램이 시스템 콜의 허락/거절 정책을 결정
- 내가 만든 프로그램 안에서 어떤 시스템 콜은 막고 다른 것은 허용하는 식으로 활용 가능
- 프로그래머가 자유롭게 권한을 제어할 수 있기 때문에 보안을 강화
- STRIC_MODE
-> read, write, exit, sigreturn 시스템 콜의 호출만 허용
-> 외의 시스템 콜은 SIGKILL 시그널 전송
- FILTER_MODE
-> 어플리케이션 기능에 맞춰 유연하게 시스템 콜 실행 허용 및 거부
3. 디버깅 및 분석