Search code examples
bpftrace

bpftrace - How do I print a tree of parents for the calling process?


For the 'tracepoint:syscalls:sys_enter_fchownat' I'm trying to print the program name and pid of the calling but also of all the parent programs.

I know pid and comm but how do I go up the tree?

I tried a number of things..

$current_pid = $pid_ns[$current_pid]->parent; parent_pid = task_struct_ptr->parent->pid;

I checked the LLMs as well but they hallucinated up a storm.


Solution

  • bpftrace questions never get any answers here :( Anyway I've been struggling towards an answer..

    Tried just doing a pid/parent tree in a system() call to awk, but the calling process is long dead before awk is booted up.

    Then I found that curtask->parent->pid works..

    So I put that in a while loop until pid == 1 (which is basically the process top level). But then bpftrace invalidly accuses my script of having an infinite loop. So I unroll loops as a ghetto solution. Also the fact that bpftrace does not support functions... oof.

    So if you read this script, it works, and it looks like jank for reasons.

    #!/usr/bin/bpftrace
    
    // touch example
    // while true; do chown $RANDOM.$RANDOM example; sleep 5; done
    
    // sys_enter_fchownat fmt: "dfd: 0x%08lx, filename: 0x%08lx, user: 0x%08lx, group: 0x%08lx, flag: 0x%08lx", ((unsigned long)(REC->dfd)), ((unsigned long)(REC->filename)), ((unsigned long)(REC->user)), ((unsigned long)(REC->group)), ((unsigned long)(REC->flag))
    tracepoint:syscalls:sys_enter_fchownat
    {
    printf(">%llu\t%d\t%s(%s,%d,%d)", nsecs, uid, probe, str(args->filename), args->user, args->group);
    
    $c = curtask;
    $t = 0;
    while($t == 0)
      {
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 1
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 2
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 3
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 4
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 5
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 6
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 7
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 8
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 9
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 10
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 11
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 12
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 13
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 14
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 15
      printf("\t...");
      $t=1;
      }
    
    printf("\n");
    }
    
    //sys_enter_chown    fmt: "filename: 0x%08lx, user: 0x%08lx, group: 0x%08lx", ((unsigned long)(REC->filename)), ((unsigned long)(REC->user)), ((unsigned long)(REC->group))
    tracepoint:syscalls:sys_enter_chown
    {
    printf(">%llu\t%d\t%s(%s,%d,%d)", nsecs, uid, probe, str(args->filename), args->user, args->group);
    
    $c = curtask;
    $t = 0;
    while($t == 0)
      {
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 1
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 2
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 3
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 4
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 5
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 6
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 7
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 8
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 9
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 10
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 11
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 12
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 13
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 14
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 15
      printf("\t...");
      $t=1;
      }
    
    printf("\n");
    }
    
    // sys_enter_fchown   fmt: "fd: 0x%08lx, user: 0x%08lx, group: 0x%08lx", ((unsigned long)(REC->fd)), ((unsigned long)(REC->user)), ((unsigned long)(REC->group))
    tracepoint:syscalls:sys_enter_fchown
    {
    printf(">%llu\t%d\t%s(%d,%d)", nsecs, uid, probe, args->user, args->group);
    
    $c = curtask;
    $t = 0;
    while($t == 0)
      {
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 1
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 2
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 3
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 4
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 5
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 6
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 7
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 8
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 9
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 10
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 11
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 12
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 13
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 14
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 15
      printf("\t...");
      $t=1;
      }
    
    printf("\n");
    }
    
    // sys_enter_lchown   fmt: "filename: 0x%08lx, user: 0x%08lx, group: 0x%08lx", ((unsigned long)(REC->filename)), ((unsigned long)(REC->user)), ((unsigned long)(REC->group))
    tracepoint:syscalls:sys_enter_lchown
    {
    printf(">%llu\t%d\t%s(%s,%d,%d))", nsecs, uid, probe, str(args->filename), args->user, args->group);
    
    $c = curtask;
    $t = 0;
    while($t == 0)
      {
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 1
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 2
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 3
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 4
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 5
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 6
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 7
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 8
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 9
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 10
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 11
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 12
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 13
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 14
      if($c->pid == 1) {break;} printf("\t%s(%d)", $c->comm, $c->pid); $c = $c->parent;  // 15
      printf("\t...");
      $t=1;
      }
    
    printf("\n");
    }
    
    // EOF