From: Fabien Siron Date: Wed, 6 Jul 2016 15:49:22 +0000 (+0000) Subject: Add a general netlink socket parser X-Git-Tag: v4.13~65 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2850f745ca49f52b4b1266a6a1b1ec0c58f77c66;p=strace Add a general netlink socket parser Introduce a general socket netlink parser which prints the header and a string for the remaining part of the buffer. It doesn't handle all the netlink flags and types yet because the parser needs more information, this will be implemented later. * net.c (decode_sockbuf): New function. (SYS_FUNC(send), SYS_FUNC(sendto), SYS_FUNC(recv), SYS_FUNC(recvfrom)): Use it instead of printstr. * msghdr.c (print_msghdr): Pass IOV_DECODE_NETLINK to tprint_iov_upto() for netlink sockets. * netlink.c: New file. * Makefile.am (strace_SOURCES): Add it. * defs.h (decode_netlink, getfdproto): New prototypes. (iov_decode): Add IOV_DECODER_NETLINK. * io.c (print_iovec): Use decode_netlink(). * util.c (getfdproto): Remove static keyword. * xlat/netlink_flags.in: New file. * xlat/netlink_types.in: New file. --- diff --git a/Makefile.am b/Makefile.am index 9241e1e7..97f0b306 100644 --- a/Makefile.am +++ b/Makefile.am @@ -160,6 +160,7 @@ strace_SOURCES = \ mtd.c \ native_defs.h \ net.c \ + netlink.c \ numa.c \ open.c \ or1k_atomic.c \ diff --git a/defs.h b/defs.h index bda74a34..62e6414d 100644 --- a/defs.h +++ b/defs.h @@ -452,7 +452,8 @@ extern enum sock_proto get_proto_by_name(const char *); enum iov_decode { IOV_DECODE_ADDR, - IOV_DECODE_STR + IOV_DECODE_STR, + IOV_DECODE_NETLINK }; typedef enum { @@ -567,6 +568,7 @@ extern const char *signame(const int); extern void pathtrace_select(const char *); extern int pathtrace_match(struct tcb *); extern int getfdpath(struct tcb *, int, char *, unsigned); +extern enum sock_proto getfdproto(struct tcb *, int); extern const char *xlookup(const struct xlat *, const uint64_t); extern const char *xlat_search(const struct xlat *, const size_t, const uint64_t); @@ -679,6 +681,7 @@ extern void printsignal(int); extern void tprint_iov(struct tcb *, unsigned long, unsigned long, enum iov_decode); extern void tprint_iov_upto(struct tcb *, unsigned long, unsigned long, enum iov_decode, unsigned long); +extern void decode_netlink(struct tcb *, unsigned long, unsigned long); extern void tprint_open_modes(unsigned int); extern const char *sprint_open_modes(unsigned int); extern void print_seccomp_filter(struct tcb *, unsigned long); diff --git a/io.c b/io.c index da8b9d25..7ddeb78c 100644 --- a/io.c +++ b/io.c @@ -88,6 +88,12 @@ print_iovec(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) c->data_size -= len; printstr(tcp, iov[0], len); break; + case IOV_DECODE_NETLINK: + if (len > c->data_size) + len = c->data_size; + c->data_size -= len; + decode_netlink(tcp, iov[0], iov[1]); + break; default: printaddr(iov[0]); break; diff --git a/msghdr.c b/msghdr.c index 3db95fa7..d93ab82e 100644 --- a/msghdr.c +++ b/msghdr.c @@ -335,13 +335,22 @@ decode_msg_control(struct tcb *tcp, unsigned long addr, static void print_msghdr(struct tcb *tcp, struct msghdr *msg, unsigned long data_size) { + int family; + enum iov_decode decode; + tprints("{msg_name="); - decode_sockaddr(tcp, (long)msg->msg_name, msg->msg_namelen); + family = decode_sockaddr(tcp, (long)msg->msg_name, msg->msg_namelen); tprintf(", msg_namelen=%d", msg->msg_namelen); tprints(", msg_iov="); + + if (family == AF_NETLINK) + decode = IOV_DECODE_NETLINK; + else + decode = IOV_DECODE_STR; + tprint_iov_upto(tcp, (unsigned long) msg->msg_iovlen, - (unsigned long) msg->msg_iov, IOV_DECODE_STR, data_size); + (unsigned long) msg->msg_iov, decode, data_size); tprintf(", msg_iovlen=%lu", (unsigned long) msg->msg_iovlen); decode_msg_control(tcp, (unsigned long) msg->msg_control, diff --git a/net.c b/net.c index 75113dc6..bcb9e4f6 100644 --- a/net.c +++ b/net.c @@ -108,6 +108,19 @@ print_ifindex(unsigned int ifindex) tprintf("%u", ifindex); } +static void +decode_sockbuf(struct tcb *tcp, int fd, long addr, long addrlen) +{ + + switch (verbose(tcp) ? getfdproto(tcp, fd) : SOCK_PROTO_UNKNOWN) { + case SOCK_PROTO_NETLINK: + decode_netlink(tcp, addr, addrlen); + break; + default: + printstr(tcp, addr, addrlen); + } +} + /* * low bits of the socket type define real socket type, * other bits are socket type flags. @@ -220,7 +233,7 @@ SYS_FUNC(send) { printfd(tcp, tcp->u_arg[0]); tprints(", "); - printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); + decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]); tprintf(", %lu, ", tcp->u_arg[2]); /* flags */ printflags(msg_flags, tcp->u_arg[3], "MSG_???"); @@ -232,7 +245,7 @@ SYS_FUNC(sendto) { printfd(tcp, tcp->u_arg[0]); tprints(", "); - printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); + decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]); tprintf(", %lu, ", tcp->u_arg[2]); /* flags */ printflags(msg_flags, tcp->u_arg[3], "MSG_???"); @@ -287,10 +300,12 @@ SYS_FUNC(recv) printfd(tcp, tcp->u_arg[0]); tprints(", "); } else { - if (syserror(tcp)) + if (syserror(tcp)) { printaddr(tcp->u_arg[1]); - else - printstr(tcp, tcp->u_arg[1], tcp->u_rval); + } else { + decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], + tcp->u_rval); + } tprintf(", %lu, ", tcp->u_arg[2]); printflags(msg_flags, tcp->u_arg[3], "MSG_???"); @@ -310,7 +325,8 @@ SYS_FUNC(recvfrom) if (syserror(tcp)) { printaddr(tcp->u_arg[1]); } else { - printstr(tcp, tcp->u_arg[1], tcp->u_rval); + decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], + tcp->u_rval); } /* len */ tprintf(", %lu, ", tcp->u_arg[2]); diff --git a/netlink.c b/netlink.c new file mode 100644 index 00000000..c43f6e74 --- /dev/null +++ b/netlink.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Fabien Siron + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" +#include +#include +#include "xlat/netlink_flags.h" +#include "xlat/netlink_types.h" + +void +decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long size) +{ + struct nlmsghdr nlmsghdr; + + if (size < sizeof(struct nlmsghdr)) { + printstr(tcp, addr, size); + return; + } + if (umove_or_printaddr(tcp, addr, &nlmsghdr)) + return; + + tprintf("{{len=%u, type=", nlmsghdr.nlmsg_len); + + printxval(netlink_types, nlmsghdr.nlmsg_type, "NLMSG_???"); + + tprints(", flags="); + printflags(netlink_flags, nlmsghdr.nlmsg_flags, "NLM_F_???"); + /* manage get/new requests */ + + tprintf(", seq=%u, pid=%u}", nlmsghdr.nlmsg_seq, + nlmsghdr.nlmsg_pid); + + if (size - sizeof(struct nlmsghdr) > 0) { + tprints(", "); + printstr(tcp, addr + sizeof(struct nlmsghdr), + size - sizeof(struct nlmsghdr)); + } + + tprints("}"); +} diff --git a/util.c b/util.c index c99136d2..782b4146 100644 --- a/util.c +++ b/util.c @@ -472,7 +472,7 @@ sprinttime(time_t t) return buf; } -static enum sock_proto +enum sock_proto getfdproto(struct tcb *tcp, int fd) { #ifdef HAVE_SYS_XATTR_H diff --git a/xlat/netlink_flags.in b/xlat/netlink_flags.in new file mode 100644 index 00000000..d84f4ddb --- /dev/null +++ b/xlat/netlink_flags.in @@ -0,0 +1,6 @@ +NLM_F_REQUEST 0x1 +NLM_F_MULTI 0x2 +NLM_F_ACK 0x4 +NLM_F_ECHO 0x8 +NLM_F_DUMP_INTR 0x10 +NLM_F_DUMP_FILTERED 0x20 diff --git a/xlat/netlink_types.in b/xlat/netlink_types.in new file mode 100644 index 00000000..9cb52973 --- /dev/null +++ b/xlat/netlink_types.in @@ -0,0 +1,4 @@ +NLMSG_NOOP 0x1 +NLMSG_ERROR 0x2 +NLMSG_DONE 0x3 +NLMSG_OVERRUN 0x4