1/* 2 * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "defs.h" 29 30#ifdef HAVE_LINUX_BPF_H 31# include <linux/bpf.h> 32#endif 33 34#include "xlat/bpf_commands.h" 35#include "xlat/bpf_map_types.h" 36#include "xlat/bpf_prog_types.h" 37#include "xlat/bpf_map_update_elem_flags.h" 38 39static int 40bpf_map_create(struct tcb *tcp, const long addr, unsigned int size) 41{ 42 struct { 43 uint32_t map_type, key_size, value_size, max_entries; 44 } attr = {}; 45 46 if (!size) { 47 printaddr(addr); 48 return RVAL_DECODED | RVAL_FD; 49 } 50 if (size > sizeof(attr)) 51 size = sizeof(attr); 52 if (umoven_or_printaddr(tcp, addr, size, &attr)) 53 return RVAL_DECODED | RVAL_FD; 54 55 tprints("{map_type="); 56 printxval(bpf_map_types, attr.map_type, "BPF_MAP_TYPE_???"); 57 tprintf(", key_size=%u, value_size=%u, max_entries=%u}", 58 attr.key_size, attr.value_size, attr.max_entries); 59 60 return RVAL_DECODED | RVAL_FD; 61} 62 63static void 64bpf_map_update_elem(struct tcb *tcp, const long addr, unsigned int size) 65{ 66 struct { 67 uint32_t map_fd; 68 uint64_t ATTRIBUTE_ALIGNED(8) key; 69 uint64_t ATTRIBUTE_ALIGNED(8) value; 70 uint64_t flags; 71 } attr = {}; 72 73 if (!size) { 74 printaddr(addr); 75 return; 76 } 77 if (size > sizeof(attr)) 78 size = sizeof(attr); 79 if (umoven_or_printaddr(tcp, addr, size, &attr)) 80 return; 81 82 tprints("{map_fd="); 83 printfd(tcp, attr.map_fd); 84 tprintf(", key=%#" PRIx64 ", value=%#" PRIx64 ", flags=", 85 attr.key, attr.value); 86 printxval(bpf_map_update_elem_flags, attr.flags, "BPF_???"); 87 tprints("}"); 88} 89 90static void 91bpf_map_delete_elem(struct tcb *tcp, const long addr, unsigned int size) 92{ 93 struct { 94 uint32_t map_fd; 95 uint64_t ATTRIBUTE_ALIGNED(8) key; 96 } attr = {}; 97 98 if (!size) { 99 printaddr(addr); 100 return; 101 } 102 if (size > sizeof(attr)) 103 size = sizeof(attr); 104 if (umoven_or_printaddr(tcp, addr, size, &attr)) 105 return; 106 107 tprints("{map_fd="); 108 printfd(tcp, attr.map_fd); 109 tprintf(", key=%#" PRIx64 "}", attr.key); 110} 111 112static int 113bpf_map_io(struct tcb *tcp, const long addr, unsigned int size, const char *text) 114{ 115 struct bpf_io_elem_struct { 116 uint32_t map_fd; 117 uint64_t ATTRIBUTE_ALIGNED(8) key; 118 uint64_t ATTRIBUTE_ALIGNED(8) value; 119 } attr = {}; 120 121 if (exiting(tcp)) { 122 if (!syserror(tcp) && !umove_or_printaddr(tcp, addr, &attr)) 123 tprintf(", %s=%#" PRIx64, text, attr.value); 124 tprints("}"); 125 return RVAL_DECODED; 126 } 127 128 if (!size) { 129 printaddr(addr); 130 return RVAL_DECODED; 131 } 132 if (size > sizeof(attr)) 133 size = sizeof(attr); 134 if (umoven_or_printaddr(tcp, addr, size, &attr)) 135 return RVAL_DECODED; 136 137 tprints("{map_fd="); 138 printfd(tcp, attr.map_fd); 139 tprintf(", key=%#" PRIx64, attr.key); 140 141 return 0; 142} 143 144static int 145bpf_prog_load(struct tcb *tcp, const long addr, unsigned int size) 146{ 147 struct { 148 uint32_t prog_type, insn_cnt; 149 uint64_t ATTRIBUTE_ALIGNED(8) insns, license; 150 uint32_t log_level, log_size; 151 uint64_t ATTRIBUTE_ALIGNED(8) log_buf; 152 uint32_t kern_version; 153 } attr = {}; 154 155 if (!size) { 156 printaddr(addr); 157 return RVAL_DECODED | RVAL_FD; 158 } 159 if (size > sizeof(attr)) 160 size = sizeof(attr); 161 if (umoven_or_printaddr(tcp, addr, size, &attr)) 162 return RVAL_DECODED | RVAL_FD; 163 164 tprints("{prog_type="); 165 printxval(bpf_prog_types, attr.prog_type, "BPF_PROG_TYPE_???"); 166 tprintf(", insn_cnt=%u, insns=%#" PRIx64 ", license=", 167 attr.insn_cnt, attr.insns); 168 printstr(tcp, attr.license, -1); 169 tprintf(", log_level=%u, log_size=%u, log_buf=%#" PRIx64 ", kern_version=%u}", 170 attr.log_level, attr.log_size, attr.log_buf, attr.kern_version); 171 172 return RVAL_DECODED | RVAL_FD; 173} 174 175SYS_FUNC(bpf) 176{ 177 const int cmd = tcp->u_arg[0]; 178 const long addr = tcp->u_arg[1]; 179 const unsigned int size = tcp->u_arg[2]; 180 int rc = RVAL_DECODED; 181 182 if (entering(tcp)) { 183 printxval(bpf_commands, cmd, "BPF_???"); 184 tprints(", "); 185 } 186 187 switch (cmd) { 188 case BPF_MAP_CREATE: 189 rc = bpf_map_create(tcp, addr, size); 190 break; 191 case BPF_MAP_LOOKUP_ELEM: 192 rc = bpf_map_io(tcp, addr, size, "value"); 193 break; 194 case BPF_MAP_UPDATE_ELEM: 195 bpf_map_update_elem(tcp, addr, size); 196 break; 197 case BPF_MAP_DELETE_ELEM: 198 bpf_map_delete_elem(tcp, addr, size); 199 break; 200 case BPF_MAP_GET_NEXT_KEY: 201 rc = bpf_map_io(tcp, addr, size, "next_key"); 202 break; 203 case BPF_PROG_LOAD: 204 rc = bpf_prog_load(tcp, addr, size); 205 break; 206 default: 207 printaddr(addr); 208 break; 209 } 210 211 if (rc & RVAL_DECODED) 212 tprintf(", %u", size); 213 214 return rc; 215} 216