I want to monitor systemcalls with bpftrace (https://github.com/iovisor/bpftrace/). For most systemcalls, this works without problems, but I have problems to monitor applications, where the suid bit is set.

Folowing syscalls are monitored (https://github.com/iovisor/bpftrace/blob/master/tools/setuids.bt):

  • setuid
  • setfsuid
  • setreuid
  • setresuid

For testing purposes, a copy of the sleep command is used.

$ cp /bin/sleep ~
$ sudo chown root ~/sleep
$ sudo chmod +s ~/sleep

btftrace is started with following command:

$ sudo ./bpftrace setuids.bt

After the start of btftrace the custom sleep command is started.

$ ./sleep 1337

I expected, that btftrace should print an information about the started process, but nothing was captured.

ps is used to verify, if the process is running with root-privileges:

$ ps aux | grep sleep
root  5552  0.0  0.0  16872  1012 pts/2  S+   10:18   0:00 ./sleep 1337

To check if bpftrace captures the mentioned syscalls, su was started to switch to a different user:

$ su testuser

This was captured by bpftrace and to process id and additional information is shown:

$ sudo ./bpftrace setuids.bt 
Attaching 7 probes...
Tracing setuid(2) family syscalls. Hit Ctrl-C to end.
TIME     PID    COMM             UID    SYSCALL   ARGS (RET)
10:23:15 5661   su               1000   setuid    uid=1001 (0)

Why is this not detected by monitoring the mentioned syscalls?

1 Answer 1


The tracepoints from bpftrace only captures syscalls but does not capture other functions, which are executed inside the Linux kernel.

This is an important difference, because the suid bit is interpreted when executing the execve systemcall. execve does not use the setuid(2) family syscalls to set the userids for the process. The function, where the suid bit is interpreted can be found in exec.c in the kernel sources: https://github.com/torvalds/linux/blob/38f8ccde04a3fa317b51b05e63c3cb57e1641931/fs/exec.c#L1596

bpftrace only supports the uid in handlers, but not euid, ruid, and fuid. When executing applications, where the suid bit is set, the uid is the same as the user, who started the application. euid, ruid and fuid are changed to the owner of the file.

This can be verified by going to the process information in /proc/{pid}/status .

There is a line, which starts with Uid:

Uid:    1000    0   0   0

The columns are defined as uid´, euid, ruidandfuid`. This information can be found in: http://lxr.linux.no/#linux+v2.6.37/fs/proc/array.c#L186

With bpftrace it's not possible to monitor applications where the suid bit is set, but in combination with python (or another scripting language) the information can be combined with the information from the `/proc/ filesystem.

Example python script to monitor seuid bit applications:

Following bpftrace-script, which prints the command name and the pid is used. This is stored as monitor.bt.

    printf("%s;%d\n", comm, pid);

Following python script executes bpftrace and reads the captured information from stdout:

import os
import subprocess
import signal

def get_resuid(pid):
    '''Return username of UID of process pid'''
    pid_path = '/proc/{}/status'.format(pid)
    if os.path.isfile(pid_path):
        for ln in open(pid_path):
            if ln.startswith('Uid:'):
                return [int(x) for x in ln.split()[1:5]]
    return None

proc = subprocess.Popen(
while True:
  line = proc.stdout.readline()
  if not line:
  comm, pid = line.decode().strip("\n").rsplit(";", maxsplit=1)
  pid = int(pid)
  uids = get_resuid(pid)
  if uids:
    print("{} -> {}".format(comm, uids))

The bpfscript monitors the execution of new application which are started with execve and prints the pid. This pid is used to get the uid, euid, ... from the proc filesystem and prints this information to stdout.

This will look like:

sleep -> [1000, 0, 0, 0]

The columns are specified as uid, euid, ruid and fuid.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .