/* * Copyright (C) 2014-2021 Firejail Authors * * This file is part of firejail project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* struct sock_filter filter[] = { VALIDATE_ARCHITECTURE, EXAMINE_SYSCALL, ONLY(SYS_socket), EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else WHITELIST(AF_INET), WHITELIST(AF_INET6), WHITELIST(AF_PACKET), RETURN_ERRNO(ENOTSUP) }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("prctl(NO_NEW_PRIVS)"); return 1; } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { perror("prctl"); return 1; } */ #include "fseccomp.h" #include "../include/seccomp.h" #include #include #include static char *protocol[] = { "unix", "inet", "inet6", "netlink", "packet", "bluetooth", NULL }; #ifdef SYS_socket static struct sock_filter protocol_filter_command[] = { WHITELIST(AF_UNIX), WHITELIST(AF_INET), WHITELIST(AF_INET6), WHITELIST(AF_NETLINK), WHITELIST(AF_PACKET), WHITELIST(AF_BLUETOOTH) }; #endif // Note: protocol[] and protocol_filter_command are synchronized // command length struct sock_filter whitelist[] = { WHITELIST(AF_UNIX) }; unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter); #ifdef SYS_socket static struct sock_filter *find_protocol_domain(const char *p) { int i = 0; while (protocol[i] != NULL) { if (strcmp(protocol[i], p) == 0) return &protocol_filter_command[i * whitelist_len]; i++; } return NULL; } #endif void protocol_print(void) { #ifndef SYS_socket if (!arg_quiet) fprintf(stderr, "Warning fseccomp: firejail --protocol not supported on this platform\n"); return; #endif int i = 0; while (protocol[i] != NULL) { printf("%s, ", protocol[i]); i++; } printf("\n"); } // install protocol filter void protocol_build_filter(const char *prlist, const char *fname) { assert(prlist); assert(fname); #ifndef SYS_socket if (!arg_quiet) fprintf(stderr, "Warning fseccomp: --protocol not supported on this platform\n"); return; #else // build the filter struct sock_filter filter[32]; // big enough memset(&filter[0], 0, sizeof(filter)); uint8_t *ptr = (uint8_t *) &filter[0]; // header struct sock_filter filter_start[] = { #if defined __x86_64__ /* check for native arch */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1 + 2 + 1, 0), /* i386 filter */ EXAMINE_SYSCALL, // 1 // checking SYS_socket only: filtering SYS_socketcall not possible with seccomp ONLY(359), // 1 + 2 BPF_JUMP(BPF_JMP+BPF_JA+BPF_K, (3 + 1 + 2), 0, 0), // 1 + 2 + 1 #else #warning 32 bit protocol filter not implemented yet for your architecture #endif VALIDATE_ARCHITECTURE, // 3 EXAMINE_SYSCALL, // 3 + 1 ONLY(SYS_socket), // 3 + 1 + 2 EXAMINE_ARGUMENT(0) // 3 + 1 + 2 + 1 }; memcpy(ptr, &filter_start[0], sizeof(filter_start)); ptr += sizeof(filter_start); // parse list and add commands char *tmplist = strdup(prlist); if (!tmplist) errExit("strdup"); char *token = strtok(tmplist, ","); if (!token) errExit("strtok"); while (token) { struct sock_filter *domain = find_protocol_domain(token); if (domain == NULL) { fprintf(stderr, "Error fseccomp: %s is not a valid protocol\n", token); exit(1); } memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter)); ptr += whitelist_len * sizeof(struct sock_filter); token = strtok(NULL, ","); } free(tmplist); // add end of filter struct sock_filter filter_end[] = { RETURN_ERRNO(ENOTSUP) }; memcpy(ptr, &filter_end[0], sizeof(filter_end)); ptr += sizeof(filter_end); // save filter to file int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (dst < 0) { fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); exit(1); } int size = (int) ((uintptr_t) ptr - (uintptr_t) (filter)); int written = 0; while (written < size) { int rv = write(dst, (unsigned char *) filter + written, size - written); if (rv == -1) { fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); exit(1); } written += rv; } close(dst); #endif // SYS_socket }