From d8f77cdf42bf7215e7e7615b617a1de3d01188fd Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 13 Jul 2016 21:56:16 +0000 Subject: [PATCH] Fix decoding of struct msghdr.msg_name* arguments of recvmsg syscall As the msghdr.msg_namelen argument of recvmsg syscall has the same read-write semantics as the address length argument of recvfrom syscall, parser of recvmsg syscall needs a similar fix. * defs.h (fetch_msghdr_namelen): New prototype. (decode_msghdr): Add "int *" argument. * msghdr.c (print_msghdr): Likewise. Treat it as a pointer to struct msghdr.msg_namelen passed to the kernel. Pass to decode_sockaddr the size of socket address actually returned by the kernel. Print both user and kernel address lengths when the value changes. (decode_msghdr, decode_mmsghdr): Add "int *" argument, forward it to print_msghdr. (decode_mmsgvec): Update decode_mmsghdr invocation. (fetch_msghdr_namelen): New function. * net.c (SYS_FUNC(sendmsg)): Update decode_msghdr invocation. (SYS_FUNC(recvmsg)): Use fetch_msghdr_namelen on entering to save struct msghdr.msg_namelen. On exiting, pass the saved value to decode_msghdr. --- defs.h | 3 ++- msghdr.c | 51 ++++++++++++++++++++++++++++++++++++--------------- net.c | 28 +++++++++++++++++++++------- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/defs.h b/defs.h index 62e6414d..5b537cbe 100644 --- a/defs.h +++ b/defs.h @@ -609,7 +609,8 @@ extern int printflags64(const struct xlat *, uint64_t, const char *); extern const char *sprintflags(const char *, const struct xlat *, uint64_t); extern const char *sprintmode(unsigned int); extern const char *sprinttime(time_t); -extern void decode_msghdr(struct tcb *, long, unsigned long); +extern bool fetch_msghdr_namelen(struct tcb *, long, int *); +extern void decode_msghdr(struct tcb *, const int *, long, unsigned long); extern void decode_mmsgvec(struct tcb *, unsigned long, unsigned int, bool); extern void dumpiov_in_msghdr(struct tcb *, long, unsigned long); extern void dumpiov_in_mmsghdr(struct tcb *, long); diff --git a/msghdr.c b/msghdr.c index d93ab82e..316e0ef6 100644 --- a/msghdr.c +++ b/msghdr.c @@ -333,22 +333,27 @@ decode_msg_control(struct tcb *tcp, unsigned long addr, } static void -print_msghdr(struct tcb *tcp, struct msghdr *msg, unsigned long data_size) +print_msghdr(struct tcb *tcp, const struct msghdr *msg, + const int *const p_user_msg_namelen, + const unsigned long data_size) { - int family; - enum iov_decode decode; + const int msg_namelen = + p_user_msg_namelen && (int) msg->msg_namelen > *p_user_msg_namelen + ? *p_user_msg_namelen : (int) msg->msg_namelen; tprints("{msg_name="); - family = decode_sockaddr(tcp, (long)msg->msg_name, msg->msg_namelen); - tprintf(", msg_namelen=%d", msg->msg_namelen); + const int family = + decode_sockaddr(tcp, (long) msg->msg_name, msg_namelen); + const enum iov_decode decode = + (family == AF_NETLINK) ? IOV_DECODE_NETLINK : IOV_DECODE_STR; + + tprints(", msg_namelen="); + if (p_user_msg_namelen && *p_user_msg_namelen != (int) msg->msg_namelen) + tprintf("%d->", *p_user_msg_namelen); + tprintf("%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, decode, data_size); tprintf(", msg_iovlen=%lu", (unsigned long) msg->msg_iovlen); @@ -362,13 +367,27 @@ print_msghdr(struct tcb *tcp, struct msghdr *msg, unsigned long data_size) tprints("}"); } +bool +fetch_msghdr_namelen(struct tcb *tcp, const long addr, int *const p_msg_namelen) +{ + struct msghdr msg; + + if (addr && verbose(tcp) && fetch_struct_msghdr(tcp, addr, &msg)) { + *p_msg_namelen = msg.msg_namelen; + return true; + } else { + return false; + } +} + void -decode_msghdr(struct tcb *tcp, long addr, unsigned long data_size) +decode_msghdr(struct tcb *tcp, const int *const p_user_msg_namelen, + const long addr, const unsigned long data_size) { struct msghdr msg; if (addr && verbose(tcp) && fetch_struct_msghdr(tcp, addr, &msg)) - print_msghdr(tcp, &msg, data_size); + print_msghdr(tcp, &msg, p_user_msg_namelen, data_size); else printaddr(addr); } @@ -383,14 +402,16 @@ dumpiov_in_msghdr(struct tcb *tcp, long addr, unsigned long data_size) } static int -decode_mmsghdr(struct tcb *tcp, long addr, bool use_msg_len) +decode_mmsghdr(struct tcb *tcp, const int *const p_user_msg_namelen, + const long addr, const bool use_msg_len) { struct mmsghdr mmsg; int fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg); if (fetched) { tprints("{msg_hdr="); - print_msghdr(tcp, &mmsg.msg_hdr, use_msg_len ? mmsg.msg_len : -1UL); + print_msghdr(tcp, &mmsg.msg_hdr, p_user_msg_namelen, + use_msg_len ? mmsg.msg_len : -1UL); tprintf(", msg_len=%u}", mmsg.msg_len); } else { printaddr(addr); @@ -412,7 +433,7 @@ decode_mmsgvec(struct tcb *tcp, unsigned long addr, unsigned int len, for (i = 0; i < len; ++i, addr += fetched) { if (i) tprints(", "); - fetched = decode_mmsghdr(tcp, addr, use_msg_len); + fetched = decode_mmsghdr(tcp, 0, addr, use_msg_len); if (!fetched) break; } diff --git a/net.c b/net.c index 16b42b5b..c3f4dbfb 100644 --- a/net.c +++ b/net.c @@ -286,7 +286,7 @@ SYS_FUNC(sendmsg) { printfd(tcp, tcp->u_arg[0]); tprints(", "); - decode_msghdr(tcp, tcp->u_arg[1], (unsigned long) -1L); + decode_msghdr(tcp, 0, tcp->u_arg[1], (unsigned long) -1L); /* flags */ tprints(", "); printflags(msg_flags, tcp->u_arg[2], "MSG_???"); @@ -393,19 +393,33 @@ SYS_FUNC(recvfrom) SYS_FUNC(recvmsg) { + int msg_namelen; + if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); tprints(", "); + if (fetch_msghdr_namelen(tcp, tcp->u_arg[1], &msg_namelen)) { + /* abuse of auxstr to retain state */ + tcp->auxstr = (void *) (long) msg_namelen; + return 0; + } + printaddr(tcp->u_arg[1]); } else { + msg_namelen = (long) tcp->auxstr; + tcp->auxstr = NULL; + if (syserror(tcp)) - printaddr(tcp->u_arg[1]); + tprintf("{msg_namelen=%d}", msg_namelen); else - decode_msghdr(tcp, tcp->u_arg[1], tcp->u_rval); - /* flags */ - tprints(", "); - printflags(msg_flags, tcp->u_arg[2], "MSG_???"); + decode_msghdr(tcp, &msg_namelen, tcp->u_arg[1], + tcp->u_rval); } - return 0; + + /* flags */ + tprints(", "); + printflags(msg_flags, tcp->u_arg[2], "MSG_???"); + + return RVAL_DECODED; } SYS_FUNC(recvmmsg)