class FrrCliFuzzer::LinuxNamespace

Public Class Methods

new() click to toggle source
# File lib/frr-cli-fuzzer/linux_namespace.rb, line 3
def initialize
  fork_and_unshare do
    # This is the init process of the new PID namespace. We need to reap
    # the zombies.
    trap(:CHLD) { Process.wait }
    trap(:INT, :IGNORE)
    sleep
  end
end

Public Instance Methods

fork_and_unshare() { || ... } click to toggle source

Create a child process running on a separate network and mount namespace.

# File lib/frr-cli-fuzzer/linux_namespace.rb, line 14
def fork_and_unshare
  io_in, io_out = IO.pipe

  LibC.prctl(FrrCliFuzzer::LibC::PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)

  pid = Kernel.fork do
    LibC.unshare(LibC::CLONE_NEWNS | LibC::CLONE_NEWPID | LibC::CLONE_NEWNET)

    # Fork again to use the new PID namespace.
    # Need to supress a warning that is irrelevant for us.
    warn_level = $VERBOSE
    $VERBOSE = nil
    pid = Kernel.fork do
      # HACK: kill when parent dies.
      trap(:SIGUSR1) do
        LibC.prctl(LibC::PR_SET_PDEATHSIG, 15, 0, 0, 0)
        trap(:SIGUSR1, :IGNORE)
      end
      LibC.prctl(LibC::PR_SET_PDEATHSIG, 10, 0, 0, 0)

      mount_propagation(LibC::MS_REC | LibC::MS_PRIVATE)
      mount_proc
      yield
    end
    $VERBOSE = warn_level
    io_out.puts(pid)
    exit(0)
  end

  @pid = io_in.gets.to_i
  Process.waitpid(pid)
rescue SystemCallError => e
  warn "System call error:: #{e.message}"
  warn e.backtrace
  exit(1)
end
mount_proc() click to toggle source

Mount the proc filesystem (useful after creating a new PID namespace).

# File lib/frr-cli-fuzzer/linux_namespace.rb, line 57
def mount_proc
  LibC.mount("none", "/proc", nil, LibC::MS_REC | LibC::MS_PRIVATE, nil)
  LibC.mount("proc", "/proc", "proc",
             LibC::MS_NOSUID | LibC::MS_NOEXEC | LibC::MS_NODEV, nil)
end
mount_propagation(flags) click to toggle source

Set the mount propagation of the process.

# File lib/frr-cli-fuzzer/linux_namespace.rb, line 52
def mount_propagation(flags)
  LibC.mount("none", "/", nil, flags, nil)
end
nsenter() click to toggle source

nsenter(1) is a standard tool from the util-linux package. It can be used to run a program with namespaces of other processes.

# File lib/frr-cli-fuzzer/linux_namespace.rb, line 65
def nsenter
  "nsenter -t #{@pid} --mount --pid --net"
end