Decode msghdr argument of sendmsg() and recvmsg().

Sponsored by:		Netflix, Inc.
This commit is contained in:
Michael Tuexen 2018-01-15 20:39:42 +00:00
parent 0faae8b922
commit a2674e031c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=328015
2 changed files with 398 additions and 131 deletions

View File

@ -82,7 +82,7 @@ enum Argtype { None = 1, Hex, Octal, Int, UInt, LongHex, Name, Ptr, Stat, Stat11
Sockoptname, Msgflags, CapRights, PUInt, PQuadHex, Acltype,
Extattrnamespace, Minherit, Mlockall, Mountflags, Msync, Priowhich,
Ptraceop, Quotactlcmd, Reboothowto, Rtpriofunc, Schedpolicy, Schedparam,
PSig, Siginfo, Kevent11, Iovec, Sctpsndrcvinfo,
PSig, Siginfo, Kevent11, Iovec, Sctpsndrcvinfo, Msghdr,
CloudABIAdvice, CloudABIClockID, ClouduABIFDSFlags,
CloudABIFDStat, CloudABIFileStat, CloudABIFileType,

View File

@ -401,7 +401,7 @@ static struct syscall decoded_syscalls[] = {
{ Msgflags, 3 }, { Sockaddr | OUT, 4 },
{ Ptr | OUT, 5 } } },
{ .name = "recvmsg", .ret_type = 1, .nargs = 3,
.args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
.args = { { Int, 0 }, { Msghdr | OUT, 1 }, { Msgflags, 2 } } },
{ .name = "rename", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Name, 1 } } },
{ .name = "renameat", .ret_type = 1, .nargs = 4,
@ -444,7 +444,7 @@ static struct syscall decoded_syscalls[] = {
.args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
{ Timeval, 4 } } },
{ .name = "sendmsg", .ret_type = 1, .nargs = 3,
.args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
.args = { { Int, 0 }, { Msghdr | IN, 1 }, { Msgflags, 2 } } },
{ .name = "sendto", .ret_type = 1, .nargs = 6,
.args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
{ Msgflags, 3 }, { Sockaddr | IN, 4 },
@ -1159,6 +1159,378 @@ print_utrace(FILE *fp, void *utrace_addr, size_t len)
fprintf(fp, " }");
}
static void
print_sockaddr(FILE *fp, struct trussinfo *trussinfo, void *arg, socklen_t len)
{
char addr[64];
struct sockaddr_in *lsin;
struct sockaddr_in6 *lsin6;
struct sockaddr_un *sun;
struct sockaddr *sa;
u_char *q;
pid_t pid = trussinfo->curthread->proc->pid;
if (arg == NULL) {
fputs("NULL", fp);
return;
}
/* If the length is too small, just bail. */
if (len < sizeof(*sa)) {
fprintf(fp, "0x%p", arg);
return;
}
sa = calloc(1, len);
if (get_struct(pid, arg, sa, len) == -1) {
free(sa);
fprintf(fp, "0x%p", arg);
return;
}
switch (sa->sa_family) {
case AF_INET:
if (len < sizeof(*lsin))
goto sockaddr_short;
lsin = (struct sockaddr_in *)(void *)sa;
inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
fprintf(fp, "{ AF_INET %s:%d }", addr,
htons(lsin->sin_port));
break;
case AF_INET6:
if (len < sizeof(*lsin6))
goto sockaddr_short;
lsin6 = (struct sockaddr_in6 *)(void *)sa;
inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
sizeof(addr));
fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
htons(lsin6->sin6_port));
break;
case AF_UNIX:
sun = (struct sockaddr_un *)sa;
fprintf(fp, "{ AF_UNIX \"%.*s\" }",
(int)(len - offsetof(struct sockaddr_un, sun_path)),
sun->sun_path);
break;
default:
sockaddr_short:
fprintf(fp,
"{ sa_len = %d, sa_family = %d, sa_data = {",
(int)sa->sa_len, (int)sa->sa_family);
for (q = (u_char *)sa->sa_data;
q < (u_char *)sa + len; q++)
fprintf(fp, "%s 0x%02x",
q == (u_char *)sa->sa_data ? "" : ",",
*q);
fputs(" } }", fp);
}
free(sa);
}
#define IOV_LIMIT 16
static void
print_iovec(FILE *fp, struct trussinfo *trussinfo, void *arg, int iovcnt)
{
struct iovec iov[IOV_LIMIT];
size_t max_string = trussinfo->strsize;
char tmp2[max_string + 1], *tmp3;
size_t len;
pid_t pid = trussinfo->curthread->proc->pid;
int i;
bool buf_truncated, iov_truncated;
if (iovcnt <= 0) {
fprintf(fp, "0x%p", arg);
return;
}
if (iovcnt > IOV_LIMIT) {
iovcnt = IOV_LIMIT;
iov_truncated = true;
} else {
iov_truncated = false;
}
if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
fprintf(fp, "0x%p", arg);
return;
}
fputs("[", fp);
for (i = 0; i < iovcnt; i++) {
len = iov[i].iov_len;
if (len > max_string) {
len = max_string;
buf_truncated = true;
} else {
buf_truncated = false;
}
fprintf(fp, "%s{", (i > 0) ? "," : "");
if (len && get_struct(pid, iov[i].iov_base, &tmp2, len) != -1) {
tmp3 = malloc(len * 4 + 1);
while (len) {
if (strvisx(tmp3, tmp2, len,
VIS_CSTYLE|VIS_TAB|VIS_NL) <=
(int)max_string)
break;
len--;
buf_truncated = true;
}
fprintf(fp, "\"%s\"%s", tmp3,
buf_truncated ? "..." : "");
free(tmp3);
} else {
fprintf(fp, "0x%p", iov[i].iov_base);
}
fprintf(fp, ",%zu}", iov[i].iov_len);
}
fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
}
static void
print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr)
{
u_char *q;
fputs("{", fp);
for (q = CMSG_DATA(cmsghdr);
q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) {
fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q);
}
fputs("}", fp);
}
static void
print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init)
{
fprintf(fp, "{out=%u,", init->sinit_num_ostreams);
fprintf(fp, "in=%u,", init->sinit_max_instreams);
fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts);
fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo);
}
static void
print_sctp_sndrcvinfo(FILE *fp, bool recv, struct sctp_sndrcvinfo *info)
{
fprintf(fp, "{sid=%u,", info->sinfo_stream);
if (recv) {
fprintf(fp, "ssn=%u,", info->sinfo_ssn);
}
fputs("flgs=", fp);
sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags);
fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid));
if (!recv) {
fprintf(fp, "ctx=%u,", info->sinfo_context);
fprintf(fp, "ttl=%u,", info->sinfo_timetolive);
}
if (recv) {
fprintf(fp, "tsn=%u,", info->sinfo_tsn);
fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn);
}
fprintf(fp, "id=%u}", info->sinfo_assoc_id);
}
static void
print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info)
{
fprintf(fp, "{sid=%u,", info->snd_sid);
fputs("flgs=", fp);
print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags);
fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid));
fprintf(fp, "ctx=%u,", info->snd_context);
fprintf(fp, "id=%u}", info->snd_assoc_id);
}
static void
print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info)
{
fprintf(fp, "{sid=%u,", info->rcv_sid);
fprintf(fp, "ssn=%u,", info->rcv_ssn);
fputs("flgs=", fp);
print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags);
fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid));
fprintf(fp, "tsn=%u,", info->rcv_tsn);
fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn);
fprintf(fp, "ctx=%u,", info->rcv_context);
fprintf(fp, "id=%u}", info->rcv_assoc_id);
}
static void
print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info)
{
fprintf(fp, "{sid=%u,", info->nxt_sid);
fputs("flgs=", fp);
print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags);
fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid));
fprintf(fp, "len=%u,", info->nxt_length);
fprintf(fp, "id=%u}", info->nxt_assoc_id);
}
static void
print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info)
{
fputs("{pol=", fp);
print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy);
fprintf(fp, ",val=%u}", info->pr_value);
}
static void
print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
{
fprintf(fp, "{num=%u}", info->auth_keynumber);
}
static void
print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr)
{
char buf[INET_ADDRSTRLEN];
const char *s;
s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
if (s != NULL)
fprintf(fp, "{addr=%s}", s);
else
fputs("{addr=???}", fp);
}
static void
print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr)
{
char buf[INET6_ADDRSTRLEN];
const char *s;
s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
if (s != NULL)
fprintf(fp, "{addr=%s}", s);
else
fputs("{addr=???}", fp);
}
static void
print_sctp_cmsg(FILE *fp, bool recv, struct cmsghdr *cmsghdr)
{
void *data;
socklen_t len;
len = cmsghdr->cmsg_len;
data = CMSG_DATA(cmsghdr);
switch (cmsghdr->cmsg_type) {
case SCTP_INIT:
if (len == CMSG_LEN(sizeof(struct sctp_initmsg)))
print_sctp_initmsg(fp, (struct sctp_initmsg *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_SNDRCV:
if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
print_sctp_sndrcvinfo(fp, recv,
(struct sctp_sndrcvinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
#if 0
case SCTP_EXTRCV:
if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo)))
print_sctp_extrcvinfo(fp,
(struct sctp_extrcvinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
#endif
case SCTP_SNDINFO:
if (len == CMSG_LEN(sizeof(struct sctp_sndinfo)))
print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_RCVINFO:
if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo)))
print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_NXTINFO:
if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo)))
print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_PRINFO:
if (len == CMSG_LEN(sizeof(struct sctp_prinfo)))
print_sctp_prinfo(fp, (struct sctp_prinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_AUTHINFO:
if (len == CMSG_LEN(sizeof(struct sctp_authinfo)))
print_sctp_authinfo(fp, (struct sctp_authinfo *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_DSTADDRV4:
if (len == CMSG_LEN(sizeof(struct in_addr)))
print_sctp_ipv4_addr(fp, (struct in_addr *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
case SCTP_DSTADDRV6:
if (len == CMSG_LEN(sizeof(struct in6_addr)))
print_sctp_ipv6_addr(fp, (struct in6_addr *)data);
else
print_gen_cmsg(fp, cmsghdr);
break;
default:
print_gen_cmsg(fp, cmsghdr);
}
}
static void
print_cmsgs(FILE *fp, pid_t pid, bool recv, struct msghdr *msghdr)
{
struct cmsghdr *cmsghdr;
char *cmsgbuf;
const char *temp;
socklen_t len;
int level, type;
bool first;
len = msghdr->msg_controllen;
cmsgbuf = calloc(1, len);
if (get_struct(pid, msghdr->msg_control, cmsgbuf, len) == -1) {
fprintf(fp, "0x%p", msghdr);
free(cmsgbuf);
}
msghdr->msg_control = cmsgbuf;
first = true;
fputs("{", fp);
for (cmsghdr = CMSG_FIRSTHDR(msghdr);
cmsghdr != NULL;
cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) {
level = cmsghdr->cmsg_level;
type = cmsghdr->cmsg_type;
len = cmsghdr->cmsg_len;
fprintf(fp, "%s{level=", first ? "" : ",");
print_integer_arg(sysdecode_sockopt_level, fp, level);
fputs(",type=", fp);
temp = sysdecode_cmsg_type(level, type);
if (temp) {
fputs(temp, fp);
} else {
fprintf(fp, "%d", type);
}
fputs(",data=", fp);
switch (level) {
case IPPROTO_SCTP:
print_sctp_cmsg(fp, recv, cmsghdr);
break;
default:
print_gen_cmsg(fp, cmsghdr);
break;
}
fputs("}", fp);
}
fputs("}", fp);
free(cmsgbuf);
}
/*
* Converts a syscall argument into a string. Said string is
* allocated via malloc(), so needs to be free()'d. sc is
@ -1613,13 +1985,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
break;
case Sockaddr: {
char addr[64];
struct sockaddr_in *lsin;
struct sockaddr_in6 *lsin6;
struct sockaddr_un *sun;
struct sockaddr *sa;
socklen_t len;
u_char *q;
if (args[sc->offset] == 0) {
fputs("NULL", fp);
@ -1641,56 +2007,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
} else
len = args[sc->offset + 1];
/* If the length is too small, just bail. */
if (len < sizeof(*sa)) {
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
sa = calloc(1, len);
if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
free(sa);
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
switch (sa->sa_family) {
case AF_INET:
if (len < sizeof(*lsin))
goto sockaddr_short;
lsin = (struct sockaddr_in *)(void *)sa;
inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
fprintf(fp, "{ AF_INET %s:%d }", addr,
htons(lsin->sin_port));
break;
case AF_INET6:
if (len < sizeof(*lsin6))
goto sockaddr_short;
lsin6 = (struct sockaddr_in6 *)(void *)sa;
inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
sizeof(addr));
fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
htons(lsin6->sin6_port));
break;
case AF_UNIX:
sun = (struct sockaddr_un *)sa;
fprintf(fp, "{ AF_UNIX \"%.*s\" }",
(int)(len - offsetof(struct sockaddr_un, sun_path)),
sun->sun_path);
break;
default:
sockaddr_short:
fprintf(fp,
"{ sa_len = %d, sa_family = %d, sa_data = {",
(int)sa->sa_len, (int)sa->sa_family);
for (q = (u_char *)sa->sa_data;
q < (u_char *)sa + len; q++)
fprintf(fp, "%s 0x%02x",
q == (u_char *)sa->sa_data ? "" : ",",
*q);
fputs(" } }", fp);
}
free(sa);
print_sockaddr(fp, trussinfo, (void *)args[sc->offset], len);
break;
}
case Sigaction: {
@ -2148,68 +2465,15 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
#define IOV_LIMIT 16
case Iovec: {
case Iovec:
/*
* Print argument as an array of struct iovec, where the next
* syscall argument is the number of elements of the array.
*/
struct iovec iov[IOV_LIMIT];
size_t max_string = trussinfo->strsize;
char tmp2[max_string + 1], *tmp3;
size_t len;
int i, iovcnt;
bool buf_truncated, iov_truncated;
iovcnt = args[sc->offset + 1];
if (iovcnt <= 0) {
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
if (iovcnt > IOV_LIMIT) {
iovcnt = IOV_LIMIT;
iov_truncated = true;
} else {
iov_truncated = false;
}
if (get_struct(pid, (void *)args[sc->offset],
&iov, iovcnt * sizeof(struct iovec)) == -1) {
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
fprintf(fp, "%s", "[");
for (i = 0; i < iovcnt; i++) {
len = iov[i].iov_len;
if (len > max_string) {
len = max_string;
buf_truncated = true;
} else {
buf_truncated = false;
}
fprintf(fp, "%s{", (i > 0) ? "," : "");
if (len && get_struct(pid, iov[i].iov_base, &tmp2, len)
!= -1) {
tmp3 = malloc(len * 4 + 1);
while (len) {
if (strvisx(tmp3, tmp2, len,
VIS_CSTYLE|VIS_TAB|VIS_NL) <=
(int)max_string)
break;
len--;
buf_truncated = true;
}
fprintf(fp, "\"%s\"%s", tmp3,
buf_truncated ? "..." : "");
free(tmp3);
} else {
fprintf(fp, "0x%p", iov[i].iov_base);
}
fprintf(fp, ",%zu}", iov[i].iov_len);
}
fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
print_iovec(fp, trussinfo, (void *)args[sc->offset],
(int)args[sc->offset + 1]);
break;
}
case Sctpsndrcvinfo: {
struct sctp_sndrcvinfo info;
@ -2218,23 +2482,26 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
fprintf(fp, "{sid=%u,", info.sinfo_stream);
if (sc->type & OUT) {
fprintf(fp, "ssn=%u,", info.sinfo_ssn);
print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
break;
}
case Msghdr: {
struct msghdr msghdr;
if (get_struct(pid, (void *)args[sc->offset],
&msghdr, sizeof(struct msghdr)) == -1) {
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
fputs("flgs=", fp);
sysdecode_sctp_sinfo_flags(fp, info.sinfo_flags);
fprintf(fp, ",ppid=%u,", ntohl(info.sinfo_ppid));
/* Can't use IN here, since IN is 0 */
if ((sc->type & OUT) == 0) {
fprintf(fp, "ctx=%u,", info.sinfo_context);
fprintf(fp, "ttl=%u,", info.sinfo_timetolive);
}
if (sc->type & OUT) {
fprintf(fp, "tsn=%u,", info.sinfo_tsn);
fprintf(fp, "cumtsn=%u,", info.sinfo_cumtsn);
}
fprintf(fp, "id=%u}", info.sinfo_assoc_id);
fputs("{", fp);
print_sockaddr(fp, trussinfo, msghdr.msg_name, msghdr.msg_namelen);
fprintf(fp, ",%d,", msghdr.msg_namelen);
print_iovec(fp, trussinfo, msghdr.msg_iov, msghdr.msg_iovlen);
fprintf(fp, ",%d,", msghdr.msg_iovlen);
print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
fprintf(fp, ",%u,", msghdr.msg_controllen);
print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
fputs("}", fp);
break;
}