Reputation: 323
I would like to know what calls are made to open(2)
in a bash script.
I wrote the following program which intercepts syscalls:
#include <fcntl.h>
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
static
int
my_open(const char *filename, int oflag, mode_t mode)
{
printf("$jason$ open: %s\n", filename);
return open(filename, oflag, mode);
}
DYLD_INTERPOSE(my_open, open)
Which I then ran using:
clang -dynamiclib libfile.c -o libfile.dylib
export DYLD_INSERT_LIBRARIES=libfile.dylib
touch /tmp/testingtesting
It doesn't work.
I tried it with a program that I compiled and it works fine. I tried it with programs compiled by brew and it works fine. I read the source code for touch.c. It calls open(2)
.
I then disabled SIP and it worked fine. So, I concluded that it was SIP that was causing the problem. I don't want to disable SIP though.
What should I do? I was thinking about just allowing dtrace: csrutil enable --without dtrace
. Because I think dtrace can track syscalls but I'm not sure if that is a safe option.
Upvotes: 5
Views: 1365
Reputation: 23438
General library injection has become essentially unsupported on recent versions of macOS.
You can however indeed do this with dtrace
as you suspect, specifically the dtruss
script. Unfortunately, the version of this script that ships with macOS is rather stale, so I'd recommend using my updated version of dtruss
¹ as this will let you trace all sub-processes, which is pretty essential if you're tracing shell scripts. It also avoids having to run the command you're trying to trace with sudo
, which might make it behave differently.
This command…
path/to/dtruss -d -e -f -t open touch /tmp/testingtesting
…should work fine with the linked version. Explanation of the command line:
-d
and -e
show call timings. (Optional)-f
enables "follow" mode for also tracing spawned sub-processes - this isn't really interesting for the touch
command, but you'll probably need it for tracing a bash script.-t open
limits tracing to the open
syscall. (Leave this off to trace all syscalls. Caution: this could produce a LOT of output.)With the stock version of dtruss
, you can fall back to:
sudo dtruss -d -e -t open touch /tmp/testingtesting
- but notice that touch
will be run as the root user in this case, and tracing sub-processes is not supported.sudo dtruss -d -e -t open -n touch
, and then run touch /tmp/testingtesting
in another terminal. This avoids running touch
as root, but it will trace all processes named touch
.The output of the traced syscalls will probably also be less clear when using the original version of dtruss
as the updated version does a better job of formatting syscall arguments, particularly strings. (For open()
specifically, the updated version prints the 'mode' argument for created file permisions as octal, which is usually what you want.)
And yes, you'll need to disable the dtrace portion of SIP for all features of dtrace to work, and this probably does open a small security risk, but I've not heard of any malware that attempts to exploit this.
Footnotes:
¹ I am not trying to self-promote my code. I simply don't know of a better solution - I had a very similar problem to the asker, and the built-in tool was not good enough, so I fixed it.
Upvotes: 6
Reputation: 1384
What you are doing is called library injection, and Apple works hard to remove this ability from their system.
As a result of their efforts, with SIP enabled, you can do the DYLD_INSERT magic only to the apps that are not hardened (or hardened with several specific exceptions), which I suppose are the apps you built and brew ships. Apple binaries, one of which is touch, are usually hardened or protected in other ways.
You don't have a big number of options here:
All these options are for Intel-based macs, for m1 it could be even harder.
Regarding the safety: cut the machine with SIP disabled from the external sources of data (Internet, USB-drives etc), do your research, then enable SIP back and connect mac again to the world.
Upvotes: 2