github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap-confine/seccomp-support-ext.c (about) 1 /* 2 * Copyright (C) 2019 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include "seccomp-support-ext.h" 22 23 #include <errno.h> 24 #include <linux/seccomp.h> 25 #include <stdio.h> 26 #include <sys/prctl.h> 27 #include <sys/syscall.h> 28 #include <sys/types.h> 29 #include <unistd.h> 30 31 #include "../libsnap-confine-private/utils.h" 32 33 #ifndef SECCOMP_FILTER_FLAG_LOG 34 #define SECCOMP_FILTER_FLAG_LOG 2 35 #endif 36 37 #ifndef seccomp 38 // prototype because we build with -Wstrict-prototypes 39 int seccomp(unsigned int operation, unsigned int flags, void *args); 40 41 int seccomp(unsigned int operation, unsigned int flags, void *args) { 42 errno = 0; 43 return syscall(__NR_seccomp, operation, flags, args); 44 } 45 #endif 46 47 size_t sc_read_seccomp_filter(const char *filename, char *buf, size_t buf_size) { 48 if (buf_size == 0) { 49 die("seccomp load buffer cannot be empty"); 50 } 51 FILE *file = fopen(filename, "rb"); 52 if (file == NULL) { 53 die("cannot open seccomp filter %s", filename); 54 } 55 size_t num_read = fread(buf, 1, buf_size - 1, file); 56 buf[num_read] = '\0'; 57 if (ferror(file) != 0) { 58 die("cannot read seccomp profile %s", filename); 59 } 60 if (feof(file) == 0) { 61 die("cannot fit seccomp profile %s to memory buffer", filename); 62 } 63 fclose(file); 64 debug("read %zu bytes from %s", num_read, filename); 65 return num_read; 66 } 67 68 void sc_apply_seccomp_filter(struct sock_fprog *prog) { 69 int err; 70 71 // Load filter into the kernel (by this point we have dropped to the 72 // calling user but still retain CAP_SYS_ADMIN). 73 // 74 // Importantly we are intentionally *not* setting NO_NEW_PRIVS because it 75 // interferes with exec transitions in AppArmor with certain snapd 76 // interfaces. Not setting NO_NEW_PRIVS does mean that applications can 77 // adjust their sandbox if they have CAP_SYS_ADMIN or, if running on < 4.8 78 // kernels, break out of the seccomp via ptrace. Both CAP_SYS_ADMIN and 79 // 'ptrace (trace)' are blocked by AppArmor with typical snapd interfaces. 80 err = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, prog); 81 if (err != 0) { 82 /* The profile may fail to load using the "modern" interface. 83 * In such case use the older prctl-based interface instead. */ 84 switch (errno) { 85 case ENOSYS: 86 debug("kernel doesn't support the seccomp(2) syscall"); 87 break; 88 case EINVAL: 89 debug("kernel may not support the SECCOMP_FILTER_FLAG_LOG flag"); 90 break; 91 } 92 debug("falling back to prctl(2) syscall to load seccomp filter"); 93 err = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog); 94 if (err != 0) { 95 die("cannot apply seccomp profile"); 96 } 97 } 98 }