1 /* 2 * Copyright (c) 2015 Dmitry V. Levin <ldv (at) altlinux.org> 3 * Copyright (c) 2017 Quentin Monnet <quentin.monnet (at) 6wind.com> 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_BPF_H 32 # include <linux/bpf.h> 33 #endif 34 35 #include "xlat/bpf_commands.h" 36 #include "xlat/bpf_map_types.h" 37 #include "xlat/bpf_prog_types.h" 38 #include "xlat/bpf_map_update_elem_flags.h" 39 #include "xlat/bpf_attach_type.h" 40 41 static int 42 bpf_map_create(struct tcb *const tcp, const kernel_ulong_t addr, 43 unsigned int size) 44 { 45 struct { 46 uint32_t map_type, key_size, value_size, max_entries; 47 } attr = {}; 48 49 if (!size) { 50 printaddr(addr); 51 return RVAL_DECODED | RVAL_FD; 52 } 53 if (size > sizeof(attr)) 54 size = sizeof(attr); 55 if (umoven_or_printaddr(tcp, addr, size, &attr)) 56 return RVAL_DECODED | RVAL_FD; 57 58 tprints("{map_type="); 59 printxval(bpf_map_types, attr.map_type, "BPF_MAP_TYPE_???"); 60 tprintf(", key_size=%u, value_size=%u, max_entries=%u}", 61 attr.key_size, attr.value_size, attr.max_entries); 62 63 return RVAL_DECODED | RVAL_FD; 64 } 65 66 static void 67 bpf_map_update_elem(struct tcb *const tcp, const kernel_ulong_t addr, 68 unsigned int size) 69 { 70 struct { 71 uint32_t map_fd; 72 uint64_t ATTRIBUTE_ALIGNED(8) key; 73 uint64_t ATTRIBUTE_ALIGNED(8) value; 74 uint64_t flags; 75 } attr = {}; 76 77 if (!size) { 78 printaddr(addr); 79 return; 80 } 81 if (size > sizeof(attr)) 82 size = sizeof(attr); 83 if (umoven_or_printaddr(tcp, addr, size, &attr)) 84 return; 85 86 tprints("{map_fd="); 87 printfd(tcp, attr.map_fd); 88 tprintf(", key=%#" PRIx64 ", value=%#" PRIx64 ", flags=", 89 attr.key, attr.value); 90 printxval64(bpf_map_update_elem_flags, attr.flags, "BPF_???"); 91 tprints("}"); 92 } 93 94 static void 95 bpf_map_delete_elem(struct tcb *const tcp, const kernel_ulong_t addr, 96 unsigned int size) 97 { 98 struct { 99 uint32_t map_fd; 100 uint64_t ATTRIBUTE_ALIGNED(8) key; 101 } attr = {}; 102 103 if (!size) { 104 printaddr(addr); 105 return; 106 } 107 if (size > sizeof(attr)) 108 size = sizeof(attr); 109 if (umoven_or_printaddr(tcp, addr, size, &attr)) 110 return; 111 112 tprints("{map_fd="); 113 printfd(tcp, attr.map_fd); 114 tprintf(", key=%#" PRIx64 "}", attr.key); 115 } 116 117 static int 118 bpf_map_io(struct tcb *const tcp, const kernel_ulong_t addr, unsigned int size, 119 const char *const text) 120 { 121 struct bpf_io_elem_struct { 122 uint32_t map_fd; 123 uint64_t ATTRIBUTE_ALIGNED(8) key; 124 uint64_t ATTRIBUTE_ALIGNED(8) value; 125 } attr = {}; 126 127 if (exiting(tcp)) { 128 if (!syserror(tcp) && !umove_or_printaddr(tcp, addr, &attr)) 129 tprintf(", %s=%#" PRIx64, text, attr.value); 130 tprints("}"); 131 return RVAL_DECODED; 132 } 133 134 if (!size) { 135 printaddr(addr); 136 return RVAL_DECODED; 137 } 138 if (size > sizeof(attr)) 139 size = sizeof(attr); 140 if (umoven_or_printaddr(tcp, addr, size, &attr)) 141 return RVAL_DECODED; 142 143 tprints("{map_fd="); 144 printfd(tcp, attr.map_fd); 145 tprintf(", key=%#" PRIx64, attr.key); 146 147 return 0; 148 } 149 150 static int 151 bpf_prog_load(struct tcb *const tcp, const kernel_ulong_t addr, 152 unsigned int size) 153 { 154 struct { 155 uint32_t prog_type, insn_cnt; 156 uint64_t ATTRIBUTE_ALIGNED(8) insns, license; 157 uint32_t log_level, log_size; 158 uint64_t ATTRIBUTE_ALIGNED(8) log_buf; 159 uint32_t kern_version; 160 } attr = {}; 161 162 if (!size) { 163 printaddr(addr); 164 return RVAL_DECODED | RVAL_FD; 165 } 166 if (size > sizeof(attr)) 167 size = sizeof(attr); 168 if (umoven_or_printaddr(tcp, addr, size, &attr)) 169 return RVAL_DECODED | RVAL_FD; 170 171 tprints("{prog_type="); 172 printxval(bpf_prog_types, attr.prog_type, "BPF_PROG_TYPE_???"); 173 tprintf(", insn_cnt=%u, insns=%#" PRIx64 ", license=", 174 attr.insn_cnt, attr.insns); 175 printstr(tcp, attr.license); 176 tprintf(", log_level=%u, log_size=%u, log_buf=%#" PRIx64 ", kern_version=%u}", 177 attr.log_level, attr.log_size, attr.log_buf, attr.kern_version); 178 179 return RVAL_DECODED | RVAL_FD; 180 } 181 182 static int 183 bpf_obj_manage(struct tcb *const tcp, const kernel_ulong_t addr, 184 unsigned int size) 185 { 186 struct { 187 uint64_t ATTRIBUTE_ALIGNED(8) pathname; 188 uint32_t bpf_fd; 189 } attr = {}; 190 191 if (!size) { 192 printaddr(addr); 193 return RVAL_DECODED | RVAL_FD; 194 } 195 if (size > sizeof(attr)) 196 size = sizeof(attr); 197 if (umoven_or_printaddr(tcp, addr, size, &attr)) 198 return RVAL_DECODED | RVAL_FD; 199 200 tprintf("{pathname="); 201 printpath(tcp, attr.pathname); 202 tprints(", bpf_fd="); 203 printfd(tcp, attr.bpf_fd); 204 tprintf("}"); 205 206 return RVAL_DECODED | RVAL_FD; 207 } 208 209 static int 210 bpf_prog_attach_detach(struct tcb *const tcp, const kernel_ulong_t addr, 211 unsigned int size, bool print_attach_bpf_fd) 212 { 213 struct { 214 uint32_t target_fd, attach_bpf_fd, attach_type; 215 } attr = {}; 216 217 if (!size) { 218 printaddr(addr); 219 return RVAL_DECODED; 220 } 221 if (size > sizeof(attr)) 222 size = sizeof(attr); 223 if (umoven_or_printaddr(tcp, addr, size, &attr)) 224 return RVAL_DECODED; 225 226 tprintf("{target_fd="); 227 printfd(tcp, attr.target_fd); 228 if (print_attach_bpf_fd) { 229 tprintf(", attach_bpf_fd="); 230 printfd(tcp, attr.attach_bpf_fd); 231 } 232 tprintf(", attach_type="); 233 printxval(bpf_attach_type, attr.attach_type, "BPF_???"); 234 tprintf("}"); 235 236 return RVAL_DECODED; 237 } 238 239 static int 240 bpf_prog_attach(struct tcb *const tcp, const kernel_ulong_t addr, 241 unsigned int size) 242 { 243 return bpf_prog_attach_detach(tcp, addr, size, true); 244 } 245 246 static int 247 bpf_prog_detach(struct tcb *const tcp, const kernel_ulong_t addr, 248 unsigned int size) 249 { 250 return bpf_prog_attach_detach(tcp, addr, size, false); 251 } 252 253 SYS_FUNC(bpf) 254 { 255 const unsigned int cmd = tcp->u_arg[0]; 256 const kernel_ulong_t addr = tcp->u_arg[1]; 257 const unsigned int size = tcp->u_arg[2]; 258 int rc = RVAL_DECODED; 259 260 if (entering(tcp)) { 261 printxval(bpf_commands, cmd, "BPF_???"); 262 tprints(", "); 263 } 264 265 switch (cmd) { 266 case BPF_MAP_CREATE: 267 rc = bpf_map_create(tcp, addr, size); 268 break; 269 case BPF_MAP_LOOKUP_ELEM: 270 rc = bpf_map_io(tcp, addr, size, "value"); 271 break; 272 case BPF_MAP_UPDATE_ELEM: 273 bpf_map_update_elem(tcp, addr, size); 274 break; 275 case BPF_MAP_DELETE_ELEM: 276 bpf_map_delete_elem(tcp, addr, size); 277 break; 278 case BPF_MAP_GET_NEXT_KEY: 279 rc = bpf_map_io(tcp, addr, size, "next_key"); 280 break; 281 case BPF_PROG_LOAD: 282 rc = bpf_prog_load(tcp, addr, size); 283 break; 284 case BPF_OBJ_PIN: 285 rc = bpf_obj_manage(tcp, addr, size); 286 break; 287 case BPF_OBJ_GET: 288 rc = bpf_obj_manage(tcp, addr, size); 289 break; 290 case BPF_PROG_ATTACH: 291 rc = bpf_prog_attach(tcp, addr, size); 292 break; 293 case BPF_PROG_DETACH: 294 rc = bpf_prog_detach(tcp, addr, size); 295 break; 296 default: 297 printaddr(addr); 298 break; 299 } 300 301 if (rc & RVAL_DECODED) 302 tprintf(", %u", size); 303 304 return rc; 305 } 306