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.
This commit is contained in:
Дмитрий Левин 2016-07-13 21:56:16 +00:00
parent 766e1d9928
commit d8f77cdf42
3 changed files with 59 additions and 23 deletions

3
defs.h
View File

@ -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);

View File

@ -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;
}

28
net.c
View File

@ -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)