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