Search code examples
system-callsbpfebpfbcc-bpf

bpftrace and sys_read syscall


I'm attempting to write a single bpftrace script which grab the strings passing from a postfix process and a saslauthd for the authentication part. The goal is detect compromise account of my company. The strace command give me some good results:

strace -p PID -s 100 -e 'read'
read(7, "\0\20", 2)                     = 2
read(7, "xxxxxxxxxx", 10)               = 10
read(7, "\0\t", 2)                      = 2
read(7, "YYYYYYYYY", 9)                 = 9
read(7, "\0\4", 2)                      = 2
read(7, "smtp", 4)                      = 4

I can recover login/password and detect if there is a bruteforce running.

but I try to have the same results with bpftrace with:

$ bpftrace -e 'kprobe:sys_read /comm=="saslauthd"/ {printf("%<%s>\n",str(arg1,arg2));}'
<>
<login>
<>
<>
<>
<smtp>

In this case, I can read some sys_read syscall strings but not all. I don't understand why my bpftrace doesn't have the same result. I also think about the null character and that why i use str(arg1,arg2) to force the size of the array. I'v also tried to use tracepoint and this is the same result.

Maybe someone can help me to understand where is my error ? So any input will be appreciated


Solution

  • TL;DR. That's actually the expected behavior of str(buf, len). It retrieves the string pointed to by buf, with a limit to len characters including the NULL character. Thus, since in your case some strings start with a NULL character, str() will copy an empty string.


    Sources. bpftrace translates str() into a call to the BPF_FUNC_probe_read_str BPF helper. In the kernel, that helper itself calls strncpy_from_unsafe.

    I don't think bpftrace already has a function implementing what you're looking for. If you want your described semantics, you could ask for a copy() function in bpftrace. Though, looking at the commit that introduced str(), it shouldn't be too hard to write a patch for that. Don't hesitate to send a pull request!