Preliminary idea for PID namespaces

This commit is contained in:
Ryan Voots 2017-05-03 01:38:16 -07:00
parent 1dcfccb512
commit b78dcaaaab

View file

@ -5,6 +5,7 @@ use warnings;
use Sys::Linux::Mount qw/:all/; use Sys::Linux::Mount qw/:all/;
use Sys::Linux::Unshare qw/:all/; use Sys::Linux::Unshare qw/:all/;
use POSIX qw/_exit/;
sub namespace { sub namespace {
my ($options) = @_; my ($options) = @_;
@ -12,20 +13,7 @@ sub namespace {
my $uflags = 0; my $uflags = 0;
my $mflags = 0; my $mflags = 0;
if ($options->{pid}) { my $post_setup = sub {
die "TODO, need to setup a proper 'init' PID 1";
}
if ($options->{mount} || $options->{private_mount} || $options->{private_tmp}) {
$uflags |= CLONE_NEWNS;
}
if ($options->{net}) {
die "TODO, need to setup network interfaces";
}
unshare($uflags);
# If we want a private /tmp, or private mount we need to recursively make every mount private. it CAN be done without that but this is more reliable. # If we want a private /tmp, or private mount we need to recursively make every mount private. it CAN be done without that but this is more reliable.
if ($options->{private_mount} || $options->{private_tmp}) { if ($options->{private_mount} || $options->{private_tmp}) {
mount("/", "/", undef, MS_REC|MS_PRIVATE, undef); mount("/", "/", undef, MS_REC|MS_PRIVATE, undef);
@ -40,4 +28,55 @@ sub namespace {
mount("/tmp", "/tmp", "tmpfs", MS_PRIVATE, undef); mount("/tmp", "/tmp", "tmpfs", MS_PRIVATE, undef);
} }
} }
};
if (ref $options->{pid} eq 'CODE') {
$uflags |= CLONE_NEWPID;
} elsif (ref $options->{pid}) {
die "New PID namespace requires a coderef";
}
if ($options->{mount} || $options->{private_mount} || $options->{private_tmp}) {
$uflags |= CLONE_NEWNS;
}
if ($options->{net}) {
die "TODO, need to setup network interfaces";
}
if (ref $options->{pid} eq 'CODE') {
my $mid_pid = fork();
unless($mid_pid == -1) {
if($mid_pid) {
# Original Process
waitpid($mid_pid); # WE MUST BLOCK
return; # don't run anything else in here
} else {
# Middle child process
unshare($uflags); # Setup the namespaces
$post_setup->();
my $child_pid = fork();
unless($child_pid == -1) {
if ($child_pid) {
waitpid($child_pid);
} else {
$options->{pid}->();
}
# exit and do no cleanup, don't continue running the program, or any END{} blocks
# This is so that we don't cause anything to go wrong in the parent because something was left around
_exit(0);
} else {
die "Couldn't make PID 1: $!";
}
}
} else {
die "Couldn't fork $!";
}
} else {
unshare($uflags);
$post_setup->();
}
} }