craftwa.re

A walk outside the sandbox

Home Blog Cheat Sheets MacOS Tips Area 51 About

DTrace on Sierra

|

Overview

  • In this short post I’ll test a few handy examples of the very powerful dtrace utility. For in-depth explanation check the awesome DTrace Book.

The dtrace command is a generic front-end to the DTrace facility. The command implements a simple interface to invoke the D language compiler, the ability to retrieve buffered trace data from the DTrace kernel facility, and a set of basic routines to format and print traced data.

DTrace man page
  • To enable all features of DTrace on macOS Sierra, boot into recovery mode and disable SIP, or enable with dtrace:
$ csrutil enable --without dtrace
  • This will enable a custom system configuration:
$ csrutil status
System Integrity Protection status: enabled (Custom Configuration).

Configuration:
	Apple Internal: disabled
	Kext Signing: enabled
	Filesystem Protections: enabled
	Debugging Restrictions: enabled
	DTrace Restrictions: disabled
	NVRAM Protections: enabled
	BaseSystem Verification: enabled
  • A very important security aspect of DTrace on macOS Sierra is that even with DTrace restrictions disabled, we still won’t be able to trace system binaries. More on this below.

Examples

The examples above are adapted for macOS Sierra from The Mac Hacker’s Handbook (2009).

1. Hello World!

BEGIN
{
    printf("Hello world");
}
$ sudo dtrace -s hello.d
dtrace: script 'hello.d' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0      1                           :BEGIN Hello world

2. File monitoring

The following script traces all executables to find out who opens a specific file. DTrace doesn’t support conditional constructs so we need a workaround to check the name of the file being opened:

syscall::open:entry
{
    found = copyinstr(arg0) == "/tmp/secret" ? 1 : 0;
    printf("Found: [%d] File: %s Exe: %s", found,  copyinstr(arg0), execname);
}

Run it and grep the output for matches:

$ sudo dtrace -s filefind.d | grep "\[1\]"
dtrace: script 'filefind.d' matched 1 probe
  1    157                       open:entry Found: [1] File: /tmp/secret Exe: vim
  0    157                       open:entry Found: [1] File: /tmp/secret Exe: cat

We could easily add a predicate to the script above to monitor all files opened by a specifc PID:

syscall::open:entry
/pid == $1 /
{
    printf("%s(%s)", probefunc, copyinstr(arg0));
}

3. Trace memory allocations

The script below watches for memory allocations performed by malloc, valloc (which allocates aligned memory, as I’ve just found out), calloc and realloc. We’ll compute the size of the chunk being allocated for each of these function separately, depending on their definitions:

  void* malloc (size_t size);
  void* valloc(size_t size);
  void* realloc(void *ptr, size_t size);
  void* calloc(size_t nmemb, size_t size);

And the script:

pid$target::malloc:entry,
pid$target::valloc:entry
{
    allocation = arg0;
}

pid$target::realloc:entry
{
    allocation = arg1;
}

pid$target::calloc:entry
{
    allocation = arg0 * arg1;
}

pid$target::calloc:return,
pid$target::malloc:return,
pid$target::valloc:return,
pid$target::realloc:return
/allocation > 300 && allocation < 9000/
{
    printf("Address:0x%x Size:%d bytes\n", arg1, allocation);
    mallocs[arg1] = allocation;
}

The PID traced below is a iTerm process:

$ sudo dtrace -s memalloc.d -p 601
dtrace: script 'memalloc.d' matched 16 probes
CPU     ID                    FUNCTION:NAME
  1  78995                    malloc:return Address:0x7fab6840aea0 Size:320 bytes
  1  78995                    malloc:return Address:0x7fab6840aea0 Size:320 bytes
  1  78995                    malloc:return Address:0x7fab68801000 Size:1024 bytes

4. Trace a system binary

If we attempt the previous script and try to trace memory allocations done by a system binary, let’s say Safari, we have the following error, even with DTrace restrictions disabled:

$ sudo dtrace -s memalloc.d -p 585
dtrace: failed to grab pid 585: the current security restriction (system integrity protection enabled) prevents dtrace from attaching to an executable not signed with the [com.apple.security.get-task-allow] entitlement

We need to disable SIP completely to be able to execute the above script on system binaries, like the Apple Safari browser for example!

References