]> granicus.if.org Git - strace/commitdiff
netlink: decode NLMSG_ERROR messages
authorDmitry V. Levin <ldv@altlinux.org>
Mon, 17 Apr 2017 04:37:41 +0000 (04:37 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 17 Apr 2017 04:37:41 +0000 (04:37 +0000)
* netlink.c (decode_nlmsgerr, decode_payload): New functions.
(decode_nlmsghdr_with_payload): Use decode_payload.
* tests/netlink_protocol.c (send_query): Check decoding
of NLMSG_ERROR messages.
* NEWS: Mention this change.

NEWS
netlink.c
tests/netlink_protocol.c

diff --git a/NEWS b/NEWS
index ba3e36a2c991b31a3f33423fcca92eaadf80364a..12cc5932831378a426299e724f629ef732f783cd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@ Noteworthy changes in release ?.?? (????-??-??)
   * Implemented decoding of statx syscall.
   * Implemented decoding of NS_* ioctl commands.
   * Implemented decoding of the remaining V4L2_BUF_TYPE_* types.
+  * Implemented decoding of NLMSG_ERROR netlink messages.
   * Updated lists of ioctl commands from Linux 4.11.
 
 * Bug fixes
index dcd24629558530ce4f12a7cf0b375c0ea73612e6..16550d6cb1a32bfdb12772ebc426648d158960f0 100644 (file)
--- a/netlink.c
+++ b/netlink.c
@@ -69,6 +69,55 @@ print_nlmsghdr(struct tcb *tcp, const struct nlmsghdr *const nlmsghdr)
                nlmsghdr->nlmsg_pid);
 }
 
+static void
+decode_nlmsghdr_with_payload(struct tcb *const tcp,
+                            const struct nlmsghdr *const nlmsghdr,
+                            const kernel_ulong_t addr,
+                            const kernel_ulong_t len);
+
+static void
+decode_nlmsgerr(struct tcb *const tcp,
+              kernel_ulong_t addr,
+              kernel_ulong_t len)
+{
+       struct nlmsgerr err;
+
+       if (umove_or_printaddr(tcp, addr, &err.error))
+               return;
+
+       tprints("{error=");
+       if (err.error < 0 && (unsigned) -err.error < nerrnos) {
+               tprintf("-%s", errnoent[-err.error]);
+       } else {
+               tprintf("%d", err.error);
+       }
+
+       addr += offsetof(struct nlmsgerr, msg);
+       len -= offsetof(struct nlmsgerr, msg);
+
+       if (len) {
+               tprints(", msg=");
+               if (fetch_nlmsghdr(tcp, &err.msg, addr, len)) {
+                       decode_nlmsghdr_with_payload(tcp, &err.msg, addr, len);
+               }
+       }
+
+       tprints("}");
+}
+
+static void
+decode_payload(struct tcb *const tcp,
+              const struct nlmsghdr *const nlmsghdr,
+              const kernel_ulong_t addr,
+              const kernel_ulong_t len)
+{
+       if (nlmsghdr->nlmsg_type == NLMSG_ERROR && len >= sizeof(int)) {
+               decode_nlmsgerr(tcp, addr, len);
+       } else {
+               printstrn(tcp, addr, len);
+       }
+}
+
 static void
 decode_nlmsghdr_with_payload(struct tcb *const tcp,
                             const struct nlmsghdr *const nlmsghdr,
@@ -83,9 +132,8 @@ decode_nlmsghdr_with_payload(struct tcb *const tcp,
                nlmsghdr->nlmsg_len > len ? len : nlmsghdr->nlmsg_len;
        if (nlmsg_len > NLMSG_HDRLEN) {
                tprints(", ");
-
-               printstrn(tcp, addr + NLMSG_HDRLEN,
-                         nlmsg_len - NLMSG_HDRLEN);
+               decode_payload(tcp, nlmsghdr, addr + NLMSG_HDRLEN,
+                                        nlmsg_len - NLMSG_HDRLEN);
        }
 
        tprints("}");
index 34e114be25bf8539d15db02ecbef2833c14115c8..03cff929e541bb046abbef16f3279c96d7b61a01 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Check decoding of netlink protocol.
  *
- * Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
+ * Copyright (c) 2014-2017 Dmitry V. Levin <ldv@altlinux.org>
  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
  * All rights reserved.
  *
@@ -199,6 +199,124 @@ send_query(const int fd)
        printf(", ...], %u, MSG_DONTWAIT, NULL, 0) = %s\n", msg_len, errstr);
 }
 
+static void
+test_nlmsgerr(const int fd)
+{
+       struct nlmsgerr *err;
+       struct nlmsghdr *nlh;
+       void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
+       long rc;
+
+       /* error message without enough room for the error code */
+       nlh = nlh0;
+       nlh->nlmsg_len = NLMSG_HDRLEN + 4;
+       nlh->nlmsg_type = NLMSG_ERROR;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+       nlh->nlmsg_seq = 0;
+       nlh->nlmsg_pid = 0;
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, %p}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
+              fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN,
+              nlh->nlmsg_len, sprintrc(rc));
+
+       nlh = nlh0 - 2;
+       nlh->nlmsg_len = NLMSG_HDRLEN + 2;
+       nlh->nlmsg_type = NLMSG_ERROR;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+       nlh->nlmsg_seq = 0;
+       nlh->nlmsg_pid = 0;
+       memcpy(NLMSG_DATA(nlh), "42", 2);
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, \"42\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
+              fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc));
+
+       /* error message with room for the error code only */
+       nlh = nlh0 - sizeof(err->error);
+       nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(err->error);
+       nlh->nlmsg_type = NLMSG_ERROR;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+       nlh->nlmsg_seq = 0;
+       nlh->nlmsg_pid = 0;
+       err = NLMSG_DATA(nlh);
+       err->error = 42;
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, {error=42}}, %u, MSG_DONTWAIT, NULL, 0)"
+              " = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc));
+
+       err->error = -1;
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, {error=-EPERM}}, %u, MSG_DONTWAIT, NULL, 0)"
+              " = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc));
+
+       err->error = -32767;
+       nlh->nlmsg_len += sizeof(err->msg.nlmsg_len);
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, {error=-32767, msg=%p}}"
+              ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
+              fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN,
+              nlh->nlmsg_len, sprintrc(rc));
+
+       /* error message with room for the error code and a header */
+       nlh = nlh0 - sizeof(*err);
+       nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err);
+       nlh->nlmsg_type = NLMSG_ERROR;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+       nlh->nlmsg_seq = 0;
+       nlh->nlmsg_pid = 0;
+       err = NLMSG_DATA(nlh);
+       err->error = -13;
+       err->msg.nlmsg_len = NLMSG_HDRLEN;
+       err->msg.nlmsg_type = NLMSG_NOOP;
+       err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+       err->msg.nlmsg_seq = 42;
+       err->msg.nlmsg_pid = 1234;
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, {error=-EACCES"
+              ", msg={{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+              ", seq=%u, pid=%u}}}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
+              fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
+              err->msg.nlmsg_seq, err->msg.nlmsg_pid,
+              nlh->nlmsg_len, sprintrc(rc));
+
+       /* error message with room for the error code, a header, and some data */
+       nlh = nlh0 - sizeof(*err) - 4;
+       nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err) + 4;
+       nlh->nlmsg_type = NLMSG_ERROR;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+       nlh->nlmsg_seq = 0;
+       nlh->nlmsg_pid = 0;
+       err = NLMSG_DATA(nlh);
+       err->error = -13;
+       err->msg.nlmsg_len = NLMSG_HDRLEN + 4;
+       err->msg.nlmsg_type = NLMSG_NOOP;
+       err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+       err->msg.nlmsg_seq = 421;
+       err->msg.nlmsg_pid = 12345;
+       memcpy(NLMSG_DATA(&err->msg), "abcd", 4);
+
+       rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
+       printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
+              ", seq=0, pid=0}, {error=-EACCES"
+              ", msg={{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+              ", seq=%u, pid=%u}, \"abcd\"}}}, %u, MSG_DONTWAIT, NULL, 0)"
+              " = %s\n",
+              fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
+              err->msg.nlmsg_seq, err->msg.nlmsg_pid,
+              nlh->nlmsg_len, sprintrc(rc));
+}
+
 int main(void)
 {
        struct sockaddr_nl addr;
@@ -227,6 +345,7 @@ int main(void)
        free(path);
 
        send_query(fd);
+       test_nlmsgerr(fd);
 
        printf("+++ exited with 0 +++\n");