Question

I am using dtruss on MacOS X 10.8.5 in an attempt to see the conversation between a running application and an SSL server it talks to. Unlike strace on Linux, I'm not seeing full strings of data in the output, like I would expect to find as the program does send and recv on the file descriptor.

How can I get dtruss to show me the data which the app is sending and receiving with the SSL server?

Before anyone tells me to proxy the connections to an SSL server I control, yes I know this trick, and no this particular app is too smart to fall for it.

Was it helpful?

Solution

dtruss is both an elegant example of a script written for DTrace and a demonstration of what DTrace can accomplish. However, although its similarity to truss or strace is deeply welcome on the relatively barren OS X, I suspect that dtruss was never intended to be a complete substitute for either.

In any case, your question is a bit ambiguous: I'm not sure whether you are concerned that the strings that you see are truncated or that you don't see any strings at all for sendto() or recvfrom() (the underlying interfaces revealed by DTrace). I'll address both.

Firstly, DTrace collects data in the kernel; user-land buffers are obtained with the D language's copyin() or copyinstr() before being recorded and transmitted back to the consumer --- typically the dtrace(1) command. DTrace requires that its kernel buffer size be known at compile-time and therefore imposes a limit on the otherwise unpredictable length of a string. This limit is 256 bytes by default; if you are seeing truncation then you could change the limit by adding, e.g.,

#pragma D option strsize=512

below dtruss's existing pragma.

Secondly, dtruss is hard-coded to know about the formatting requirements of a variety of system calls. You don't see any buffer interpretation for sendto() or recvfrom() in its output because they're not handled explicitly in the source. There's nothing to stop you finding somewhere suitable to add them but you could instead write your own script:

bash-3.2# cat sr.d
#pragma D option rawbytes

syscall::sendto:entry,
syscall::recvfrom:entry
/pid == $target/
{
    self->bufp = arg1;
    self->size = arg2;
}

syscall::sendto:return,
syscall::recvfrom:return
/pid == $target && self->bufp && self->size/
{
    printf("%s():\n", probefunc);
    tracemem(copyin(self->bufp, self->size), 64);
    printf("\n");
    self->bufp = self->size = NULL;
}
bash-3.2# dtrace -qs ./sr.d -p 16988
sendto():

             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
         0: 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00  hello...........
        10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

^C

bash-3.2#

Note that, as for strings, we're obliged to provide a hard limit on tracemem()'s use of DTrace's data-recording buffer. If the limit is rarely approached then this has the irritating result that the output can be overwhelming and mostly redundant. If you know that you're looking for strings then you could simply use copyinstr() instead; if you have a more modern DTrace implementation than my OS X 10.6.8 then you may find that you can write

tracemem(copyin(self->bufp, self->size), 64, self->size);

where the second argument is still a hard limit on the number of bytes recorded but the number of bytes displayed is limited by the optional third argument.

Finally, note that the user-land address is recorded on entry to the system call but used only on exit. This is a common idiom that allows the system call to fault-in the data if necessary --- DTrace won't do so itself and will produce an error at run-time if asked to trace a non-resident address.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top