From: Dmitry V. Levin Date: Wed, 26 Jul 2017 10:28:25 +0000 (+0000) Subject: bpf: print unused fields of union bpf_attr if one of them is non-zero X-Git-Tag: v4.19~206 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=78de224180b26d45c45a6de3c11a3e8344ee09eb;p=strace bpf: print unused fields of union bpf_attr if one of them is non-zero When the size argument specifies more data than necessary for the given command, kernel checks that all unused fields of union bpf_attr are zero. Print this extra data when it contains non-zero bytes to enhance debugging experience. * bpf.c (decode_attr_extra_data): New function. (decode_BPF_MAP_CREATE, decode_BPF_MAP_UPDATE_ELEM, decode_BPF_MAP_DELETE_ELEM, bpf_map_io, decode_BPF_PROG_LOAD, decode_BPF_OBJ_PIN, decode_BPF_OBJ_GET, decode_BPF_PROG_ATTACH, decode_BPF_PROG_DETACH): Use it to print extra data passed via bpf_attr pointer. (bpf_obj_manage, bpf_prog_attach_detach): Remove. * tests/bpf.c (map_delete_elem): New function. (main): Use it. --- diff --git a/bpf.c b/bpf.c index 60f1655e..676ab85e 100644 --- a/bpf.c +++ b/bpf.c @@ -56,6 +56,34 @@ bpf_cmd_decoder(struct tcb *const tcp, \ typedef DECL_BPF_CMD_DECODER((*bpf_cmd_decoder_t)); +static int +decode_attr_extra_data(struct tcb *const tcp, + const char *data, + unsigned int size, + const size_t attr_size) +{ + if (size <= attr_size) + return 0; + + data += attr_size; + size -= attr_size; + + unsigned int i; + for (i = 0; i < size; ++i) { + if (data[i]) { + tprints(", "); + if (abbrev(tcp)) + tprints("..."); + else + print_quoted_string(data, size, + QUOTE_FORCE_HEX); + return RVAL_DECODED; + } + } + + return 0; +} + DEF_BPF_CMD_DECODER(BPF_MAP_CREATE) { struct { @@ -70,6 +98,7 @@ DEF_BPF_CMD_DECODER(BPF_MAP_CREATE) PRINT_FIELD_U(", ", attr, key_size); PRINT_FIELD_U(", ", attr, value_size); PRINT_FIELD_U(", ", attr, max_entries); + decode_attr_extra_data(tcp, data, size, sizeof(attr)); tprints("}"); return RVAL_DECODED | RVAL_FD; @@ -92,6 +121,7 @@ DEF_BPF_CMD_DECODER(BPF_MAP_UPDATE_ELEM) PRINT_FIELD_X(", ", attr, value); PRINT_FIELD_XVAL(", ", attr, flags, bpf_map_update_elem_flags, "BPF_???"); + decode_attr_extra_data(tcp, data, size, sizeof(attr)); tprints("}"); return RVAL_DECODED; @@ -109,6 +139,7 @@ DEF_BPF_CMD_DECODER(BPF_MAP_DELETE_ELEM) PRINT_FIELD_FD("{", attr, map_fd, tcp); PRINT_FIELD_X(", ", attr, key); + decode_attr_extra_data(tcp, data, size, sizeof(attr)); tprints("}"); return RVAL_DECODED; @@ -147,7 +178,11 @@ bpf_map_io(struct tcb *const tcp, PRINT_FIELD_FD("{", attr, map_fd, tcp); PRINT_FIELD_X(", ", attr, key); - return 0; + int rc = decode_attr_extra_data(tcp, data, size, sizeof(attr)); + if (rc & RVAL_DECODED) + tprints("}"); + + return rc; } DEF_BPF_CMD_DECODER(BPF_MAP_LOOKUP_ELEM) @@ -162,14 +197,16 @@ DEF_BPF_CMD_DECODER(BPF_MAP_GET_NEXT_KEY) DEF_BPF_CMD_DECODER(BPF_PROG_LOAD) { - struct { + struct bpf_prog_load { uint32_t prog_type, insn_cnt; uint64_t ATTRIBUTE_ALIGNED(8) insns, license; uint32_t log_level, log_size; uint64_t ATTRIBUTE_ALIGNED(8) log_buf; uint32_t kern_version; } attr = {}; - const unsigned int len = size < sizeof(attr) ? size : sizeof(attr); + const size_t attr_size = + offsetofend(struct bpf_prog_load, kern_version); + const unsigned int len = size < attr_size ? size : attr_size; memcpy(&attr, data, len); @@ -182,41 +219,35 @@ DEF_BPF_CMD_DECODER(BPF_PROG_LOAD) PRINT_FIELD_U(", ", attr, log_size); PRINT_FIELD_X(", ", attr, log_buf); PRINT_FIELD_U(", ", attr, kern_version); + decode_attr_extra_data(tcp, data, size, attr_size); tprints("}"); return RVAL_DECODED | RVAL_FD; } -static DECL_BPF_CMD_DECODER(bpf_obj_manage) +DEF_BPF_CMD_DECODER(BPF_OBJ_PIN) { - struct { + struct bpf_obj { uint64_t ATTRIBUTE_ALIGNED(8) pathname; uint32_t bpf_fd; } attr = {}; - const unsigned int len = size < sizeof(attr) ? size : sizeof(attr); + const size_t attr_size = + offsetofend(struct bpf_obj, bpf_fd); + const unsigned int len = size < attr_size ? size : attr_size; memcpy(&attr, data, len); PRINT_FIELD_PATH("{", attr, pathname, tcp); PRINT_FIELD_FD(", ", attr, bpf_fd, tcp); + decode_attr_extra_data(tcp, data, size, attr_size); tprints("}"); return RVAL_DECODED | RVAL_FD; } -DEF_BPF_CMD_DECODER(BPF_OBJ_PIN) -{ - return bpf_obj_manage(tcp, addr, size, data); -} - -DEF_BPF_CMD_DECODER(BPF_OBJ_GET) -{ - return bpf_obj_manage(tcp, addr, size, data); -} +#define decode_BPF_OBJ_GET decode_BPF_OBJ_PIN -static int -bpf_prog_attach_detach(struct tcb *const tcp, void *const data, - unsigned int size, bool print_attach) +DEF_BPF_CMD_DECODER(BPF_PROG_ATTACH) { struct { uint32_t target_fd, attach_bpf_fd, attach_type, attach_flags; @@ -226,25 +257,31 @@ bpf_prog_attach_detach(struct tcb *const tcp, void *const data, memcpy(&attr, data, len); PRINT_FIELD_FD("{", attr, target_fd, tcp); - if (print_attach) - PRINT_FIELD_FD(", ", attr, attach_bpf_fd, tcp); + PRINT_FIELD_FD(", ", attr, attach_bpf_fd, tcp); PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type, "BPF_???"); - if (print_attach) - PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags, - "BPF_F_???"); + PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags, + "BPF_F_???"); + decode_attr_extra_data(tcp, data, size, sizeof(attr)); tprints("}"); return RVAL_DECODED; } -DEF_BPF_CMD_DECODER(BPF_PROG_ATTACH) -{ - return bpf_prog_attach_detach(tcp, data, size, true); -} - DEF_BPF_CMD_DECODER(BPF_PROG_DETACH) { - return bpf_prog_attach_detach(tcp, data, size, false); + struct { + uint32_t target_fd, dummy, attach_type; + } attr = {}; + const unsigned int len = size < sizeof(attr) ? size : sizeof(attr); + + memcpy(&attr, data, len); + + PRINT_FIELD_FD("{", attr, target_fd, tcp); + PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type, "BPF_???"); + decode_attr_extra_data(tcp, data, size, sizeof(attr)); + tprints("}"); + + return RVAL_DECODED; } SYS_FUNC(bpf) diff --git a/tests/bpf.c b/tests/bpf.c index 40f96a78..36599bee 100644 --- a/tests/bpf.c +++ b/tests/bpf.c @@ -73,6 +73,18 @@ map_any(int cmd) return sys_bpf(cmd, (unsigned long) t_attr, sizeof(attr)); } +static int +map_delete_elem(void) +{ + union bpf_attr attr = { + .map_fd = -1, + .key = 0xdeadbeef, + }; + void *const t_attr = tail_memdup(&attr, sizeof(attr)); + return sys_bpf(BPF_MAP_DELETE_ELEM, + (unsigned long) t_attr, sizeof(attr)); +} + static int prog_load(void) { @@ -172,7 +184,7 @@ main(void) (unsigned) sizeof(union bpf_attr), errstr); BOGUS_BPF(BPF_MAP_UPDATE_ELEM); - map_any(BPF_MAP_DELETE_ELEM); + map_delete_elem(); printf("bpf(BPF_MAP_DELETE_ELEM" ", {map_fd=-1, key=0xdeadbeef}, %u) = %s\n", (unsigned) sizeof(union bpf_attr), errstr);