aristanetworks / bst

A one-stop shop for process isolation
MIT License
99 stars 9 forks source link

Deal with inheriting traced processes. #16

Closed peadar closed 4 years ago

peadar commented 4 years ago

If a debugger exits and leaves its child traced, then init inherits the tracing of the process as well as becoming its parent.

Change our wait behaviour to detach from such children, and forward them the signal that caused them to be stopped.

This stops us accumulating zombies if a debugger doesn't clean up on exit

peadar commented 4 years ago

BTW: I checked this because dumb-init's behaviour is to abort when this happens, killing the container. It appears systemd's init also leaves the process attached to the init, and renders it unkillable except with kill -9. So if you want to discard this, it'll be no worse than systemd. Here's what I used to repro:


#include <assert.h>
#include <stdarg.h>
#include <errno.h>
#include <iostream>
#include <unistd.h>
#include <err.h>
#include <string.h>

#include <sys/ptrace.h>
#include <sys/wait.h>

void
okOrExit(int value, int expected, const char *reason, ...) {
   if (value != expected) {
      va_list args; va_start(args, reason);
      verr(1, reason, args);
   }
}

void sighandle(int) {}
static int child() {
   okOrExit(ptrace(PTRACE_TRACEME, 0, 0), 0, "ptrace(PTRACE_TRACEME) failed");      
   signal(SIGALRM, sighandle);
   okOrExit(alarm(4), 0, "alarm failed");
   std::clog << "pausing...\n";
   int rc = pause();
   std::clog << "pause returned " << rc << "/" << strerror(errno) << std::endl;     
   return 0;
}

static int parent(pid_t childpid) {
   int status;
   okOrExit(ptrace(PTRACE_ATTACH, childpid, 0, 0), 0, "ptrace attach failed");      
   int rc = waitpid(childpid, &status, 0);
   okOrExit(rc, childpid, "waitpid for %d got %d", childpid, rc);
   std::clog << "child continued\n";
   return 0;
}

int main() {
   pid_t childpid;
   switch (childpid = fork()) {
      case  0: return child();
      default: return parent(childpid);
      case -1: return err(1, "fork failed"), 1;
   } 
}