]> granicus.if.org Git - strace/commitdiff
bpf: print unused fields of union bpf_attr if one of them is non-zero
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 26 Jul 2017 10:28:25 +0000 (10:28 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 26 Jul 2017 10:28:25 +0000 (10:28 +0000)
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.

bpf.c
tests/bpf.c

diff --git a/bpf.c b/bpf.c
index 60f1655eb305256dc75694649dcdf513be6614ce..676ab85e1272efa872e1030f45756ddd8b44bc08 100644 (file)
--- 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)
index 40f96a7887af650f1eb7ba47768596bbcc33316c..36599beeb1f58d116fb595a13aa0745c983fb7ec 100644 (file)
@@ -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);