bunpen: barebones pasta integration

totally untested, except that it builds
This commit is contained in:
2024-09-20 12:41:39 +00:00
parent d22bbcf44a
commit 0546bf6ea5
2 changed files with 59 additions and 10 deletions

View File

@@ -107,7 +107,7 @@ export fn namespace_restrict(what: *restrict::resources) void = {
case restrict::net_none => case restrict::net_none =>
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET)); errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET));
case let subset: restrict::net_subset => case let subset: restrict::net_subset =>
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET)); setup_pasta(subset);
case restrict::net_all => case restrict::net_all =>
log::println("[namespace] keeping net namespace"); log::println("[namespace] keeping net namespace");
}; };
@@ -164,19 +164,22 @@ type ns_ctx = struct {
// - in the parent: wait for the child, then propagate its exit status // - in the parent: wait for the child, then propagate its exit status
fn fork_and_propagate() (void | os::exec::error) = { fn fork_and_propagate() (void | os::exec::error) = {
match (os::exec::fork()?) { match (os::exec::fork()?) {
case let child_pid: os::exec::process => case let child_pid: os::exec::process => return wait_and_propagate(child_pid);
forward_signals(child_pid);
log::println("[namespace/fork] signals configured");
let status = wait_child(child_pid)?;
let rc = rt::wexitstatus(status.status);
// TODO: if the child exited due to a signal (e.g. SIGTERM), we (confusingly?) exit 0.
// seems correct behavior may be to send the same termination signal to ourselves.
log::printfln("[namespace/fork] child exited with {}; forwarding as {}", status.status, rc);
os::exit(rc); // propagate exit code
case => log::println("[namespace/fork] continuing as child"); case => log::println("[namespace/fork] continuing as child");
}; };
}; };
fn wait_and_propagate(child_pid: os::exec::process) (void | os::exec::error) = {
forward_signals(child_pid);
log::println("[namespace/fork] signals configured");
let status = wait_child(child_pid)?;
let rc = rt::wexitstatus(status.status);
// TODO: if the child exited due to a signal (e.g. SIGTERM), we (confusingly?) exit 0.
// seems correct behavior may be to send the same termination signal to ourselves.
log::printfln("[namespace/fork] child exited with {}; forwarding as {}", status.status, rc);
os::exit(rc); // propagate exit code
};
fn wait_child(child_pid: os::exec::process) (os::exec::status | os::exec::error) = { fn wait_child(child_pid: os::exec::process) (os::exec::status | os::exec::error) = {
for (true) { for (true) {
match (os::exec::wait(&child_pid)) { match (os::exec::wait(&child_pid)) {

View File

@@ -0,0 +1,46 @@
// vim: set shiftwidth=2 :
use errors;
use errors::ext;
use fmt;
use os;
use os::exec;
use restrict;
use rt;
use rt::ext;
fn setup_pasta(net: restrict::net_subset) void = {
// `pasta PID [options]`: creates a device in the netns of PID.
// ordering:
// 1. fork
// 2. child: enter netns, signal parent.
// 3. parent: fork and spawn `pasta --pid /proc/fd/$N`
// then dumbly wait on child until completion
// 4. child: wait for `pasta` to signal readiness on fd `$N`
//
// after that, we can continue on & exec into the user code
//
// TODO: this currently lacks the synchronization described above
match (os::exec::fork()) {
case let child_pid: os::exec::process =>
errors::ext::check("setup_pasta: attach", attach_pasta(child_pid));
errors::ext::check("setup_pasta: wait", wait_and_propagate(child_pid));
case void =>
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET));
case let e: os::exec::error =>
errors::ext::check("setup_pasta: fork", e);
};
};
// spawn pasta as a separate process, and have it attach to the netns of the given pid.
fn attach_pasta(child: os::exec::process) (void | os::exec::error | rt::errno) = {
return match (os::exec::fork()?) {
case let pasta_pid: os::exec::process => yield void;
case void =>
let pidstr = fmt::asprint(child: int);
defer free(pidstr);
let pasta_args = [ "pasta", pidstr ];
// TODO: append dns, gateway arguments to `pasta`.
yield rt::ext::execvpe("pasta", pasta_args, os::getenvs());
};
};