You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.6 KiB
81 lines
2.6 KiB
// ============================================================================ |
|
// kons_clone.hpp |
|
// ko::ns::clone namespace |
|
// (c) 2019 Taeyeon Mori <taeyeon at oro.sodimm.me> |
|
// ============================================================================ |
|
// Small Linux namespace utility header |
|
// Clone-related functions |
|
|
|
#pragma once |
|
|
|
#include "kons.hpp" |
|
#include "koproc.hpp" |
|
|
|
/** |
|
* clone namespace |
|
* Useful wrappers around the clone(2) syscall |
|
*/ |
|
namespace ko::ns::clone { |
|
namespace detail { |
|
template <typename ArgP> |
|
int uvclone_entry(void *arg) { |
|
auto [f, args, sync] = *reinterpret_cast<ArgP>(arg); |
|
sync.yield(); |
|
return std::apply(f, args); |
|
} |
|
} |
|
|
|
/** |
|
* Spawn a process in a new user namespace |
|
* @param uidmap The uid map for the user namespace |
|
* @param gidmap The gid map for the user namespace |
|
* @param fn The function to call in the child process |
|
* @param stacksize The size of the process stack |
|
* @param flags The clone(2) flags (SIGCHLD|CLONE_VM|CLONE_NEWUSER implied) |
|
* @param args The function arguments |
|
*/ |
|
template <typename U, typename G, typename F, typename... Args> |
|
std::pair<proc::child_ref, int> uvclone(U uidmap, G gidmap, F fn, size_t stacksize, long flags, Args... args) { |
|
auto [sync, sync_c] = proc::sync::make_semapair(false); |
|
auto data = new std::tuple{fn, std::tuple{std::forward<Args>(args)...}, sync_c}; |
|
|
|
auto proc = proc::detail::do_clone(detail::uvclone_entry<decltype(data)>, stacksize, CLONE_NEWUSER | CLONE_VM | flags, data); |
|
auto res = EINVAL; |
|
|
|
if (proc) { |
|
// Wait for child |
|
sync.wait(); |
|
|
|
// Set maps |
|
auto pid = proc.pid(); |
|
if (idmap::set(idmap::path(pid, "uid"), uidmap)) { |
|
if (idmap::disable_setgroups(pid)) { |
|
if (idmap::set(idmap::path(pid, "gid"), gidmap)) { |
|
res = 0; |
|
} |
|
} |
|
} |
|
|
|
if (res) |
|
res = errno; |
|
|
|
sync.post(); |
|
} |
|
|
|
return {std::move(proc), res}; |
|
} |
|
|
|
/** |
|
* Spawn a process in a new single-user user namespace |
|
* @param uid The uid inside the user namespace |
|
* @param gid The gid inside the user namespace |
|
* @param fn The function to call in the child process |
|
* @param stacksize The size of the process stack |
|
* @param flags The clone(2) flags (SIGCHLD|CLONE_VM|CLONE_NEWUSER implied) |
|
* @param args The function arguments |
|
*/ |
|
template <typename F, typename... Args> |
|
inline std::pair<proc::child_ref, int> uvclone_single(uid_t uid, gid_t gid, F fn, size_t stacksize, long flags, Args... args) { |
|
return uvclone(idmap::single(uid, getuid()), idmap::single(gid, getgid()), fn, stacksize, flags, args...); |
|
} |
|
} // namespace ko::ns::clone
|
|
|