From: Dmitry V. Levin Date: Mon, 17 Apr 2017 04:37:41 +0000 (+0000) Subject: netlink: decode NLMSG_ERROR messages X-Git-Tag: v4.17~74 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1be0e27b0bb30a23a597b6d5c2b68e13c657650b;p=strace netlink: decode NLMSG_ERROR messages * 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. --- diff --git a/NEWS b/NEWS index ba3e36a2..12cc5932 100644 --- 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 diff --git a/netlink.c b/netlink.c index dcd24629..16550d6c 100644 --- 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("}"); diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c index 34e114be..03cff929 100644 --- a/tests/netlink_protocol.c +++ b/tests/netlink_protocol.c @@ -1,7 +1,7 @@ /* * Check decoding of netlink protocol. * - * Copyright (c) 2014-2016 Dmitry V. Levin + * Copyright (c) 2014-2017 Dmitry V. Levin * Copyright (c) 2016 Fabien Siron * 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");