Is there a workaround for: "dtrace cannot control executables signed with restricted entitlements"?

It looks like in OS X 10.11 El Capitan, dtruss and dtrace can no longer do what they're meant to do. This is the error I get when I try to run sudo dtruss curl ...:

dtrace: failed to execute curl: dtrace cannot control executables signed with restricted entitlements

I've come across people noticing this problem but so far no solutions.

Is there a way to fix this or work around this?

36672 次浏览

As Andrew notices it's because of System Integrity Protection, also known as "rootless".

You can disable it completely or partially (enable just dtrace with some limitations).

Completely disable SIP

Although not recommended by Apple, you can entirely disable System Integrity Protection on you Mac. Here's how:

  1. Boot your Mac into Recovery Mode: reboot it and hold cmd+R until a progress bar appears.
  2. Go to Utilities menu. Choose Terminal there.
  3. Enter this command to disable System Integrity Protection:

$ csrutil disable

It will ask you to reboot — do so and you're free from SIP!

Partially disable SIP

Fortunately, SIP is not monolithic: it's built from many different modules we can disable/enable separately.

Repeat steps 1 and 2 from «Completely disable SIP» section above. Now in Terminal enter these commands:

$ csrutil clear # restore the default configuration first
$ csrutil enable --without dtrace # disable dtrace restrictions *only*

Reboot and enjoy your OS again.

Dtrace starts to work but you're still unable to attach dtrace to restricted processes

Looks like completely disabling SIP still blocks dtruss for restricted processes:

$ /usr/bin/csrutil status
System Integrity Protection status: disabled.
$ sudo dtruss /bin/echo "blah"
dtrace: failed to execute /bin/echo: dtrace cannot control executables signed with restricted entitlements
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.11.2
BuildVersion:   15C50

For those who want to dtrace system shipped binary after csrutil disable, copyit to a directory that is not "restricted", for example, /tmp

CC@~ $ csrutil status
System Integrity Protection status: disabled.
CC@~ $ cp /bin/echo /tmp
CC@~ $ sudo dtruss /tmp/echo


SYSCALL(args)        = return
thread_selfid(0x0, 0x0, 0x0)         = 46811 0
csops(0x0, 0x0, 0x7FFF51B6CA20)      = 0 0
issetugid(0x0, 0x0, 0x7FFF51B6CA20)      = 0 0
shared_region_check_np(0x7FFF51B6A918, 0x0, 0x7FFF51B6CA20)      = 0 0
stat64("/usr/lib/dtrace/libdtrace_dyld.dylib\0", 0x7FFF51B6BEA8, 0x7FFF51B6CA20      = 0 0

See @J.J's comment: https://apple.stackexchange.com/questions/208762/now-that-el-capitan-is-rootless-is-there-any-way-to-get-dtrace-working/224731#224731

Following up to Alexander Ushakov and Charles' answers:

Once you csrutil enable --without dtrace, there is an alternative to copying the binary: run the binary in one Terminal window and trace the Terminal process itself in another Terminal window.

In the first terminal window, find its PID:

$ echo $$
1154

In the second terminal window, begin the trace:

$ sudo dtruss -p 1154 -f

Back, in the first terminal window, run the process you want to trace:

$ ls

At this point, you should see the trace in the second window. Ignore the entries for the PID you are tracing (e.g., 1154), and the rest are for the process (and its descendants) you are interested in.

1154/0x1499:  sigprocmask(0x3, 0x7FFF53E5C608, 0x0)      = 0x0 0
1154/0x1499:  sigprocmask(0x1, 0x7FFF53E5C614, 0x7FFF53E5C610)       = 0x0 0
3100/0xa9f3:  getpid(0x7FFF82A35344, 0x7FFF82A35334, 0x2000)         = 3100 0
3100/0xa9f3:  sigprocmask(0x3, 0x10BE32EF8, 0x0)         = 0x0 0

See my answer on related question "How can get dtrace to run the traced command with non-root priviledges?" [sic].

DTrace can snoop processes that are already running. So, start a background process which waits 1sec for DTrace to start up (sorry for race condition), and snoop the PID of that process.

sudo true && \
(sleep 1; ps) & \
sudo dtrace -n 'syscall:::entry /pid == $1/ {@[probefunc] = count();}' $! \
&& kill $!

Full explanation in linked answer.

I would post this as a comment but I'm not allowed.

Disabling SIP is not necessary. Just copy the binary to an alternate location and it works just fine:

$ sudo dtruss ping google.com
dtrace: system integrity protection is on, some features will not be available


dtrace: failed to execute ping: dtrace cannot control executables signed with restricted entitlements
$ sudo cp $(which ping) .
$ sudo dtruss ./ping google.com
dtrace: system integrity protection is on, some features will not be available


SYSCALL(args)        = return
PING google.com (172.217.10.78): 56 data bytes
^C
$ csrutil status
System Integrity Protection status: enabled.

For binaries that can still function normally after being copied, this is the best option as it captures the entire lifetime of the process and doesn't require disabling any protections.