summaryrefslogtreecommitdiffstats
path: root/usr.bin/truss
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/truss')
-rw-r--r--usr.bin/truss/syscalls.c68
1 files changed, 35 insertions, 33 deletions
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 02ae868..ab163d8 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
+#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -1288,12 +1289,12 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp);
break;
case Sockaddr: {
- struct sockaddr_storage ss;
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) {
@@ -1301,70 +1302,71 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
break;
}
- /* yuck: get ss_len */
- if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
- sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) {
- fprintf(fp, "0x%lx", args[sc->offset]);
- break;
- }
-
/*
- * If ss_len is 0, then try to guess from the sockaddr type.
- * AF_UNIX may be initialized incorrectly, so always frob
- * it by using the "right" size.
+ * Extract the address length from the next argument. If
+ * this is an output sockaddr (OUT is set), then the
+ * next argument is a pointer to a socklen_t. Otherwise
+ * the next argument contains a socklen_t by value.
*/
- if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) {
- switch (ss.ss_family) {
- case AF_INET:
- ss.ss_len = sizeof(*lsin);
- break;
- case AF_INET6:
- ss.ss_len = sizeof(*lsin6);
- break;
- case AF_UNIX:
- ss.ss_len = sizeof(*sun);
- break;
- default:
+ if (sc->type & OUT) {
+ if (get_struct(pid, (void *)args[sc->offset + 1],
+ &len, sizeof(len)) == -1) {
+ fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
+ } 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;
}
- if (ss.ss_len != 0 &&
- get_struct(pid, (void *)args[sc->offset], (void *)&ss,
- ss.ss_len) == -1) {
+
+ 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 (ss.ss_family) {
+ switch (sa->sa_family) {
case AF_INET:
- lsin = (struct sockaddr_in *)&ss;
+ 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:
- lsin6 = (struct sockaddr_in6 *)&ss;
+ 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 *)&ss;
- fprintf(fp, "{ AF_UNIX \"%s\" }", sun->sun_path);
+ sun = (struct sockaddr_un *)sa;
+ fprintf(fp, "{ AF_UNIX \"%.*s\" }",
+ (int)(len - offsetof(struct sockaddr_un, sun_path)),
+ sun->sun_path);
break;
default:
- sa = (struct sockaddr *)&ss;
+ 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 + sa->sa_len; q++)
+ q < (u_char *)sa + len; q++)
fprintf(fp, "%s 0x%02x",
q == (u_char *)sa->sa_data ? "" : ",",
*q);
fputs(" } }", fp);
}
+ free(sa);
break;
}
case Sigaction: {
OpenPOWER on IntegriCloud