1 /* 2 * Check verbose decoding of seccomp SECCOMP_SET_MODE_FILTER. 3 * 4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) altlinux.org> 5 * Copyright (c) 2016-2017 The strace developers. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "tests.h" 32 33 #include <errno.h> 34 #include <stddef.h> 35 #include <stdio.h> 36 #include <asm/unistd.h> 37 #include <unistd.h> 38 39 #ifdef HAVE_PRCTL 40 # include <sys/prctl.h> 41 #endif 42 #ifdef HAVE_LINUX_SECCOMP_H 43 # include <linux/seccomp.h> 44 #endif 45 #ifdef HAVE_LINUX_FILTER_H 46 # include <linux/filter.h> 47 #endif 48 49 #if defined __NR_seccomp \ 50 && defined PR_SET_NO_NEW_PRIVS \ 51 && defined SECCOMP_SET_MODE_FILTER \ 52 && defined SECCOMP_RET_ERRNO \ 53 && defined BPF_JUMP \ 54 && defined BPF_STMT 55 56 #define SOCK_FILTER_ALLOW_SYSCALL(nr) \ 57 BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, __NR_ ## nr, 0, 1), \ 58 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW) 59 60 #define SOCK_FILTER_DENY_SYSCALL(nr, err) \ 61 BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, __NR_ ## nr, 0, 1), \ 62 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|(SECCOMP_RET_DATA & (err))) 63 64 #define SOCK_FILTER_KILL_PROCESS \ 65 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL) 66 67 #define PRINT_ALLOW_SYSCALL(nr) \ 68 tprintf("BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#x, 0, 0x1), " \ 69 "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), ", \ 70 __NR_ ## nr) 71 72 #define PRINT_DENY_SYSCALL(nr, err) \ 73 tprintf("BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#x, 0, 0x1), " \ 74 "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|%#x), ", \ 75 __NR_ ## nr, err) 76 77 static const struct sock_filter filter_c[] = { 78 /* load syscall number */ 79 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), 80 81 /* allow syscalls */ 82 SOCK_FILTER_ALLOW_SYSCALL(close), 83 SOCK_FILTER_ALLOW_SYSCALL(exit), 84 SOCK_FILTER_ALLOW_SYSCALL(exit_group), 85 86 /* deny syscalls */ 87 SOCK_FILTER_DENY_SYSCALL(sync, EBUSY), 88 SOCK_FILTER_DENY_SYSCALL(setsid, EPERM), 89 90 /* kill process */ 91 SOCK_FILTER_KILL_PROCESS 92 }; 93 94 #ifndef BPF_MAXINSNS 95 # define BPF_MAXINSNS 4096 96 #endif 97 98 int 99 main(void) 100 { 101 tprintf("%s", ""); 102 103 static const char kill_stmt_txt[] = 104 "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL)"; 105 struct sock_filter *const filter = 106 tail_memdup(filter_c, sizeof(filter_c)); 107 struct sock_filter *const big_filter = 108 tail_alloc(sizeof(*big_filter) * (BPF_MAXINSNS + 1)); 109 TAIL_ALLOC_OBJECT_CONST_PTR(struct sock_fprog, prog); 110 111 int fds[2]; 112 if (pipe(fds)) 113 perror_msg_and_fail("pipe"); 114 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) 115 perror_msg_and_skip("PR_SET_NO_NEW_PRIVS"); 116 117 prog->filter = filter + ARRAY_SIZE(filter_c); 118 prog->len = 1; 119 syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, prog); 120 tprintf("seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=1, filter=%p})" 121 " = -1 EFAULT (%m)\n", prog->filter); 122 123 prog->filter = filter + ARRAY_SIZE(filter_c) - 1; 124 prog->len = 3; 125 syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, prog); 126 tprintf("seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=%u" 127 ", filter=[%s, %p]}) = -1 EFAULT (%m)\n", 128 prog->len, kill_stmt_txt, filter + ARRAY_SIZE(filter_c)); 129 130 prog->len = 0; 131 syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, prog); 132 tprintf("seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=0, filter=[]})" 133 " = -1 EINVAL (%m)\n"); 134 135 unsigned int i; 136 for (i = 0; i <= BPF_MAXINSNS; ++i) { 137 const struct sock_filter stmt = 138 BPF_STMT(BPF_CLASS(i), i << 16); 139 big_filter[i] = stmt; 140 } 141 142 prog->filter = big_filter; 143 prog->len = BPF_MAXINSNS + 1; 144 tprintf("seccomp(SECCOMP_SET_MODE_FILTER, %s, {len=%u, filter=[", 145 "SECCOMP_FILTER_FLAG_TSYNC|0xfffffffe", prog->len); 146 for (i = 0; i < BPF_MAXINSNS; ++i) { 147 if (i) 148 tprintf(", "); 149 switch (BPF_CLASS(i)) { 150 case BPF_LD: 151 tprintf("BPF_STMT(BPF_LD|BPF_W|BPF_IMM, %#x)", i << 16); 152 break; 153 case BPF_LDX: 154 tprintf("BPF_STMT(BPF_LDX|BPF_W|BPF_IMM, %#x)", i << 16); 155 break; 156 case BPF_ST: 157 tprintf("BPF_STMT(BPF_ST, %#x)", i << 16); 158 break; 159 case BPF_STX: 160 tprintf("BPF_STMT(BPF_STX, %#x)", i << 16); 161 break; 162 case BPF_ALU: 163 tprintf("BPF_STMT(BPF_ALU|BPF_K|BPF_ADD, %#x)", i << 16); 164 break; 165 case BPF_JMP: 166 tprintf("BPF_STMT(BPF_JMP|BPF_K|BPF_JA, %#x)", i << 16); 167 break; 168 case BPF_RET: 169 tprintf("BPF_STMT(BPF_RET|BPF_K, %#x" 170 " /* SECCOMP_RET_??? */)", i << 16); 171 break; 172 case BPF_MISC: 173 tprintf("BPF_STMT(BPF_MISC|BPF_TAX, %#x)", i << 16); 174 break; 175 } 176 } 177 tprintf(", ...]})"); 178 syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, -1, prog); 179 tprintf(" = -1 EINVAL (%m)\n"); 180 181 prog->filter = filter; 182 prog->len = ARRAY_SIZE(filter_c); 183 184 tprintf("seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=%u, filter=[", 185 prog->len); 186 187 tprintf("BPF_STMT(BPF_LD|BPF_W|BPF_ABS, %#x), ", 188 (unsigned) offsetof(struct seccomp_data, nr)); 189 190 PRINT_ALLOW_SYSCALL(close); 191 PRINT_ALLOW_SYSCALL(exit); 192 PRINT_ALLOW_SYSCALL(exit_group); 193 194 PRINT_DENY_SYSCALL(sync, EBUSY), 195 PRINT_DENY_SYSCALL(setsid, EPERM), 196 197 tprintf("%s]}) = 0\n+++ exited with 0 +++\n", kill_stmt_txt); 198 199 if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, prog)) 200 perror_msg_and_skip("SECCOMP_SET_MODE_FILTER"); 201 202 if (close(0) || close(1)) 203 _exit(77); 204 205 _exit(0); 206 } 207 208 #else 209 210 SKIP_MAIN_UNDEFINED("__NR_seccomp && PR_SET_NO_NEW_PRIVS" 211 " && SECCOMP_SET_MODE_FILTER && SECCOMP_RET_ERRNO" 212 " && BPF_JUMP && BPF_STMT") 213 214 #endif 215