MFC r328015:

Decode msghdr argument of sendmsg() and recvmsg().
This commit is contained in:
Michael Tuexen 2018-04-07 21:05:39 +00:00
parent ecccab8667
commit f4f87ff118
2 changed files with 398 additions and 131 deletions

View File

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

View File

@ -385,7 +385,7 @@ static struct syscall decoded_syscalls[] = {
{ Msgflags, 3 }, { Sockaddr | OUT, 4 }, { Msgflags, 3 }, { Sockaddr | OUT, 4 },
{ Ptr | OUT, 5 } } }, { Ptr | OUT, 5 } } },
{ .name = "recvmsg", .ret_type = 1, .nargs = 3, { .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, { .name = "rename", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Name, 1 } } }, .args = { { Name, 0 }, { Name, 1 } } },
{ .name = "renameat", .ret_type = 1, .nargs = 4, { .name = "renameat", .ret_type = 1, .nargs = 4,
@ -428,7 +428,7 @@ static struct syscall decoded_syscalls[] = {
.args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
{ Timeval, 4 } } }, { Timeval, 4 } } },
{ .name = "sendmsg", .ret_type = 1, .nargs = 3, { .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, { .name = "sendto", .ret_type = 1, .nargs = 6,
.args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 }, .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
{ Msgflags, 3 }, { Sockaddr | IN, 4 }, { Msgflags, 3 }, { Sockaddr | IN, 4 },
@ -1142,6 +1142,378 @@ print_utrace(FILE *fp, void *utrace_addr, size_t len)
fprintf(fp, " }"); 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 * Converts a syscall argument into a string. Said string is
* allocated via malloc(), so needs to be free()'d. sc is * allocated via malloc(), so needs to be free()'d. sc is
@ -1596,13 +1968,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
break; break;
case Sockaddr: { case Sockaddr: {
char addr[64];
struct sockaddr_in *lsin;
struct sockaddr_in6 *lsin6;
struct sockaddr_un *sun;
struct sockaddr *sa;
socklen_t len; socklen_t len;
u_char *q;
if (args[sc->offset] == 0) { if (args[sc->offset] == 0) {
fputs("NULL", fp); fputs("NULL", fp);
@ -1624,56 +1990,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
} else } else
len = args[sc->offset + 1]; len = args[sc->offset + 1];
/* If the length is too small, just bail. */ print_sockaddr(fp, trussinfo, (void *)args[sc->offset], len);
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);
break; break;
} }
case Sigaction: { case Sigaction: {
@ -2073,68 +2390,15 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
fprintf(fp, "0x%lx", args[sc->offset]); fprintf(fp, "0x%lx", args[sc->offset]);
break; break;
} }
#define IOV_LIMIT 16 case Iovec:
case Iovec: {
/* /*
* Print argument as an array of struct iovec, where the next * Print argument as an array of struct iovec, where the next
* syscall argument is the number of elements of the array. * 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]; print_iovec(fp, trussinfo, (void *)args[sc->offset],
if (iovcnt <= 0) { (int)args[sc->offset + 1]);
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 ? ",..." : "", "]");
break; break;
}
case Sctpsndrcvinfo: { case Sctpsndrcvinfo: {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
@ -2143,23 +2407,26 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
fprintf(fp, "0x%lx", args[sc->offset]); fprintf(fp, "0x%lx", args[sc->offset]);
break; break;
} }
fprintf(fp, "{sid=%u,", info.sinfo_stream); print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
if (sc->type & OUT) { break;
fprintf(fp, "ssn=%u,", info.sinfo_ssn); }
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); fputs("{", fp);
sysdecode_sctp_sinfo_flags(fp, info.sinfo_flags); print_sockaddr(fp, trussinfo, msghdr.msg_name, msghdr.msg_namelen);
fprintf(fp, ",ppid=%u,", ntohl(info.sinfo_ppid)); fprintf(fp, ",%d,", msghdr.msg_namelen);
/* Can't use IN here, since IN is 0 */ print_iovec(fp, trussinfo, msghdr.msg_iov, msghdr.msg_iovlen);
if ((sc->type & OUT) == 0) { fprintf(fp, ",%d,", msghdr.msg_iovlen);
fprintf(fp, "ctx=%u,", info.sinfo_context); print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
fprintf(fp, "ttl=%u,", info.sinfo_timetolive); fprintf(fp, ",%u,", msghdr.msg_controllen);
} print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
if (sc->type & OUT) { fputs("}", fp);
fprintf(fp, "tsn=%u,", info.sinfo_tsn);
fprintf(fp, "cumtsn=%u,", info.sinfo_cumtsn);
}
fprintf(fp, "id=%u}", info.sinfo_assoc_id);
break; break;
} }