github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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 FILE *file = fopen(filename, "rb"); 49 if (file == NULL) { 50 die("cannot open seccomp filter %s", filename); 51 } 52 size_t num_read = fread(buf, 1, buf_size, file); 53 if (ferror(file) != 0) { 54 die("cannot read seccomp profile %s", filename); 55 } 56 if (feof(file) == 0) { 57 die("cannot fit seccomp profile %s to memory buffer", filename); 58 } 59 fclose(file); 60 debug("read %zu bytes from %s", num_read, filename); 61 return num_read; 62 } 63 64 void sc_apply_seccomp_filter(struct sock_fprog *prog) { 65 int err; 66 67 // Load filter into the kernel (by this point we have dropped to the 68 // calling user but still retain CAP_SYS_ADMIN). 69 // 70 // Importantly we are intentionally *not* setting NO_NEW_PRIVS because it 71 // interferes with exec transitions in AppArmor with certain snapd 72 // interfaces. Not setting NO_NEW_PRIVS does mean that applications can 73 // adjust their sandbox if they have CAP_SYS_ADMIN or, if running on < 4.8 74 // kernels, break out of the seccomp via ptrace. Both CAP_SYS_ADMIN and 75 // 'ptrace (trace)' are blocked by AppArmor with typical snapd interfaces. 76 err = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, prog); 77 if (err != 0) { 78 /* The profile may fail to load using the "modern" interface. 79 * In such case use the older prctl-based interface instead. */ 80 switch (errno) { 81 case ENOSYS: 82 debug("kernel doesn't support the seccomp(2) syscall"); 83 break; 84 case EINVAL: 85 debug("kernel may not support the SECCOMP_FILTER_FLAG_LOG flag"); 86 break; 87 } 88 debug("falling back to prctl(2) syscall to load seccomp filter"); 89 err = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog); 90 if (err != 0) { 91 die("cannot apply seccomp profile"); 92 } 93 } 94 }