How to force dtrace to run a monitored command with non-root privileges?

OS X lacks linux strace , but has dtrace , which should be much better.

However, I am missing out on the simple tracking of individual teams. For example, in linux, I can write strace -f gcc hello.c to caputre all system calls, which gives me a list of all the file names that the compiler needs to compile my program (an excellent memoize script is built on this trick)

I want to port memoize to mac, so I need some kind of strace . I really need a list of gcc files to read and write, so I need more truss . Of course, I can say dtruss -f gcc hello.c and get somewhat the same functionality, but then the compiler starts with root privileges, which is clearly undesirable (besides the huge security risk, one problem is that the a.out file now belongs root :-)

Then I tried dtruss -f sudo -u myusername gcc hello.c , but this seems a bit wrong and does not work anyway (I do not get the a.out file all the time, I don’t know why)

This whole long story tries to motivate my initial question: how do I get dtrace to run my command with normal user privileges, just like strace does on linux?

Edit: it seems that I'm not the only one wondering how to do this: question # 1204256 is pretty much like mine (and has the same suboptimal answer sudo :-)

+48
root dtrace strace macos
Jun 09 2018-10-06T00:
source share
7 answers

Not the answer to your question, but to know something. OpenSolaris solved this problem (in part) with "privileges" - see this page . Even in OpenSolaris, it would be impossible to allow the user to process his own process without any additional privileges. The reason is how dtrace works - it allows probes in the kernel. Thus, allowing a non-privileged user to explore the kernel, the user can do many unwanted things, for example. sniffing another passwd user by enabling probes in the keyboard driver!

+5
Jan 15 '11 at 12:16
source share

The easiest way is to use sudo:

 sudo dtruss -f sudo -u $USER whoami 



Another solution would be to start the debugger first and control the new concrete processes. For example.

 sudo dtruss -fn whoami 

Then in another terminal just run:

 whoami 

Just like that.

You will find more complex arguments in the manual: man dtruss




Alternatively, you can connect dtruss to a running user process, for example. on Mac:

 sudo dtruss -fp PID 

or similar on Linux / Unix using strace:

 sudo strace -fp PID 



Another hacker trick may consist in executing a command and immediately after that attach to the process. Here are some examples:

 sudo true; (./Pages &); sudo dtruss -fp `pgrep -n -x Pages` sudo true; (sleep 1 &); sudo dtruss -fp `pgrep -n -x sleep` sudo true; (tail -f /var/log/system.log &); sudo dtruss -fp `pgrep -n -x tail` 

Note:

  • the first sudo is only for password caching on first run,

  • this trick does not work for fast command lines such as ls, date , as it takes some time until the debugger joins the process,

  • you need to enter the command in two places,

  • you can ignore & to start the process in the background if it already does this,

  • after debugging is complete, you will have to manually kill the background process (e.g. killall -v tail )

+34
Jul 29 2018-12-12T00:
source share

The -n argument to dtruss will cause dtruss to wait and check processes matching the -n argument. The -f option will still work to keep track of processes caused by processes consistent with -n .

All of this means that if you want to process a process (for the sake of an argument, say, whoami ) running as your unprivileged user, follow these steps:

  • Open the root shell
  • Run dtruss -fn whoami
    • it will sit and wait for a process called "whoami" for existence
  • Open an unprivileged shell
  • Run whoami
    • it will run and work fine
  • Observe the system call trace in the dtruss window.
    • dtruss will not exit on its own - it will continue to wait for the processes to coincide - so it will exit when you finish



This answer duplicates the last part of @kenorb's answer, but it deserves to be a first-class answer.

+7
Jan 02 '14 at 21:28
source share

I don't know if you can force dtruss to be non-invasive like strace.

The variant "sudo [to root] dtruss sudo [back to nonroot] cmd", which seems to work better in some quick tests for me:

 sudo dtruss -f su -l `whoami` cd `pwd` && cmd.... 

External sudo, of course, dtruss works as root.

The inner su comes back to me, and with -l it recreates the environment properly, after which we need to get back to where we started.

I think su -l user is better than sudo -u user if you want the environment to be what the user usually gets. However, this will be their entry medium; I don't know if there is a good way to let the environment inherit through two user changes.

In your question, another complaint that you described about the sudo dtruss sudo workaround, other than ugliness, was that "I have not received any a.out file all this time, I don’t know why." I don’t know why either, but in my small test script, the sudo dtruss sudo variant also could not be written to the test output file, and the “sudo dtruss su” variant created the output file above.

+5
Jan 14 2018-11-11T00:
source share

OS X doesn't seem to support using dtrace to replicate all strace functions you need. However, I suggest trying to create a wrapper around suitable system calls. It looks like DYLD_INSERT_LIBRARIES is the environment variable you want to hack. This is basically the same as LD_PRELOAD for Linux.

An easier way to do library function overrides is to use the DYLD_INSERT_LIBRARIES environment variable (similar to LD_PRELOAD on Linux). The concept is simple: at boot time, the dynamic linker (dyld) will load any dynamic libraries specified in DYLD_INSERT_LIBRARIES before any libraries that the executable wants to load. The function naming is the same as in the library function; it cancels any calls to the original.

The original function is also loaded and can be restored using dlsym (RTLD_NEXT, "function_name"); function. This allows the wrapping method of existing library functions.

According to the example of Tom Robinson, you may also need to set DYLD_FORCE_FLAT_NAMESPACE=1 .

A copy of the original example ( lib_overrides.c ) that overrides only fopen :

 #include <stdio.h> #include <unistd.h> #include <dlfcn.h> // for caching the original fopen implementation FILE * (*original_fopen) (const char *, const char *) = NULL; // our fopen override implmentation FILE * fopen(const char * filename, const char * mode) { // if we haven't already, retrieve the original fopen implementation if (!original_fopen) original_fopen = dlsym(RTLD_NEXT, "fopen"); // do our own processing; in this case just print the parameters printf("== fopen: {%s,%s} ==\n", filename, mode); // call the original fopen with the same arugments FILE* f = original_fopen(filename, mode); // return the result return f; } 

Using:

 $ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c $ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib command-to-test 
+3
Aug 28 '14 at 2:00
source share

Disclaimer: This comes from @kenorb's answer. This has some advantages: PID is more specific than execname. And we can do the short-term process of waiting for DTrace before it starts.

It's a bit of a race condition, but ...

Let's say we want to track cat /etc/hosts :

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

We use sudo true to make sure that we clear the sudo password password before we start running anything time sensitive.

We start the background process ("wait 1 sec, then do something interesting"). Meanwhile, we are starting DTrace. We grabbed the PID of the background process at $! , so we can pass this DTrace as arg.

kill $! starts after closing DTrace. This is not necessary for our cat example (the process closes by itself), but it helps us complete long-running background processes such as ping . Transfer -p $! in DTrace is the preferred way to do this, but on macOS, apparently, executable code with code is required.




Another thing you can do is run the command in a separate shell and track that shell. See my answer.

+2
Jun 25 '17 at 18:51
source share

I don't know how to run what you want as a regular user, as it seems that dtruss that uses dtrace requires su privileges.

However, I believe that the team you were looking for instead

dtruss -f sudo -u myusername gcc hello.c

is an

sudo dtruss -f gcc hello.c

After entering the password, dtruss will start dtrace there will be sudo privileges, and you will get a trace, as well as a.out file.

Sorry, I can’t help.

+1
Jan 12 '11 at 8:14
source share



All Articles