1/* 2 * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org> 3 * Copyright (c) 2015-2017 The strace developers. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "defs.h" 30 31#ifdef HAVE_LINUX_SECCOMP_H 32# include <linux/seccomp.h> 33#endif 34#include "xlat/seccomp_ops.h" 35#include "xlat/seccomp_filter_flags.h" 36 37#ifdef HAVE_LINUX_FILTER_H 38# include <linux/filter.h> 39# include "xlat/bpf_class.h" 40# include "xlat/bpf_miscop.h" 41# include "xlat/bpf_mode.h" 42# include "xlat/bpf_op_alu.h" 43# include "xlat/bpf_op_jmp.h" 44# include "xlat/bpf_rval.h" 45# include "xlat/bpf_size.h" 46# include "xlat/bpf_src.h" 47 48# ifndef SECCOMP_RET_ACTION 49# define SECCOMP_RET_ACTION 0x7fff0000U 50# endif 51# include "xlat/seccomp_ret_action.h" 52#endif 53 54struct bpf_filter { 55 uint16_t code; 56 uint8_t jt; 57 uint8_t jf; 58 uint32_t k; 59}; 60 61#ifdef HAVE_LINUX_FILTER_H 62 63static void 64decode_bpf_code(uint16_t code) 65{ 66 uint16_t i = code & ~BPF_CLASS(code); 67 68 printxval(bpf_class, BPF_CLASS(code), "BPF_???"); 69 switch (BPF_CLASS(code)) { 70 case BPF_LD: 71 case BPF_LDX: 72 tprints("|"); 73 printxval(bpf_size, BPF_SIZE(code), "BPF_???"); 74 tprints("|"); 75 printxval(bpf_mode, BPF_MODE(code), "BPF_???"); 76 break; 77 case BPF_ST: 78 case BPF_STX: 79 if (i) { 80 tprintf("|%#x", i); 81 tprints_comment("BPF_???"); 82 } 83 break; 84 case BPF_ALU: 85 tprints("|"); 86 printxval(bpf_src, BPF_SRC(code), "BPF_???"); 87 tprints("|"); 88 printxval(bpf_op_alu, BPF_OP(code), "BPF_???"); 89 break; 90 case BPF_JMP: 91 tprints("|"); 92 printxval(bpf_src, BPF_SRC(code), "BPF_???"); 93 tprints("|"); 94 printxval(bpf_op_jmp, BPF_OP(code), "BPF_???"); 95 break; 96 case BPF_RET: 97 tprints("|"); 98 printxval(bpf_rval, BPF_RVAL(code), "BPF_???"); 99 i &= ~BPF_RVAL(code); 100 if (i) { 101 tprintf("|%#x", i); 102 tprints_comment("BPF_???"); 103 } 104 break; 105 case BPF_MISC: 106 tprints("|"); 107 printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???"); 108 i &= ~BPF_MISCOP(code); 109 if (i) { 110 tprintf("|%#x", i); 111 tprints_comment("BPF_???"); 112 } 113 break; 114 } 115 116} 117 118#endif /* HAVE_LINUX_FILTER_H */ 119 120static void 121decode_bpf_stmt(const struct bpf_filter *filter) 122{ 123#ifdef HAVE_LINUX_FILTER_H 124 tprints("BPF_STMT("); 125 decode_bpf_code(filter->code); 126 tprints(", "); 127 if (BPF_CLASS(filter->code) == BPF_RET) { 128 unsigned int action = SECCOMP_RET_ACTION & filter->k; 129 unsigned int data = filter->k & ~action; 130 131 printxval(seccomp_ret_action, action, "SECCOMP_RET_???"); 132 if (data) 133 tprintf("|%#x)", data); 134 else 135 tprints(")"); 136 } else { 137 tprintf("%#x)", filter->k); 138 } 139#else 140 tprintf("BPF_STMT(%#x, %#x)", filter->code, filter->k); 141#endif /* HAVE_LINUX_FILTER_H */ 142} 143 144static void 145decode_bpf_jump(const struct bpf_filter *filter) 146{ 147#ifdef HAVE_LINUX_FILTER_H 148 tprints("BPF_JUMP("); 149 decode_bpf_code(filter->code); 150 tprintf(", %#x, %#x, %#x)", 151 filter->k, filter->jt, filter->jf); 152#else 153 tprintf("BPF_JUMP(%#x, %#x, %#x, %#x)", 154 filter->code, filter->k, filter->jt, filter->jf); 155#endif /* HAVE_LINUX_FILTER_H */ 156} 157 158#ifndef BPF_MAXINSNS 159# define BPF_MAXINSNS 4096 160#endif 161 162static bool 163print_bpf_filter(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) 164{ 165 const struct bpf_filter *filter = elem_buf; 166 unsigned int *pn = data; 167 168 if ((*pn)++ >= BPF_MAXINSNS) { 169 tprints("..."); 170 return false; 171 } 172 173 if (filter->jt || filter->jf) 174 decode_bpf_jump(filter); 175 else 176 decode_bpf_stmt(filter); 177 178 return true; 179} 180 181void 182print_seccomp_fprog(struct tcb *const tcp, const kernel_ulong_t addr, 183 const unsigned short len) 184{ 185 if (abbrev(tcp)) { 186 printaddr(addr); 187 } else { 188 unsigned int insns = 0; 189 struct bpf_filter filter; 190 191 print_array(tcp, addr, len, &filter, sizeof(filter), 192 umoven_or_printaddr, print_bpf_filter, &insns); 193 } 194} 195 196#include "seccomp_fprog.h" 197 198void 199print_seccomp_filter(struct tcb *const tcp, const kernel_ulong_t addr) 200{ 201 struct seccomp_fprog fprog; 202 203 if (fetch_seccomp_fprog(tcp, addr, &fprog)) { 204 tprintf("{len=%hu, filter=", fprog.len); 205 print_seccomp_fprog(tcp, fprog.filter, fprog.len); 206 tprints("}"); 207 } 208} 209 210static void 211decode_seccomp_set_mode_strict(const unsigned int flags, 212 const kernel_ulong_t addr) 213{ 214 tprintf("%u, ", flags); 215 printaddr(addr); 216} 217 218SYS_FUNC(seccomp) 219{ 220 unsigned int op = tcp->u_arg[0]; 221 222 printxval(seccomp_ops, op, "SECCOMP_SET_MODE_???"); 223 tprints(", "); 224 225 if (op == SECCOMP_SET_MODE_FILTER) { 226 printflags(seccomp_filter_flags, tcp->u_arg[1], 227 "SECCOMP_FILTER_FLAG_???"); 228 tprints(", "); 229 print_seccomp_filter(tcp, tcp->u_arg[2]); 230 } else { 231 decode_seccomp_set_mode_strict(tcp->u_arg[1], 232 tcp->u_arg[2]); 233 } 234 235 return RVAL_DECODED; 236} 237