Signed-off-by: Filip Schauer <[email protected]>
---
 src/PVE/LXC/Namespaces.pm | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/PVE/LXC/Namespaces.pm b/src/PVE/LXC/Namespaces.pm
index 477d0ac..7836d06 100644
--- a/src/PVE/LXC/Namespaces.pm
+++ b/src/PVE/LXC/Namespaces.pm
@@ -3,10 +3,10 @@ package PVE::LXC::Namespaces;
 use strict;
 use warnings;
 
-use Fcntl qw(O_WRONLY);
+use Fcntl qw(O_WRONLY O_RDONLY);
 use Socket;
 
-use PVE::Tools qw(CLONE_NEWNS CLONE_NEWUSER);
+use PVE::Tools qw(CLONE_NEWNS CLONE_NEWUSER O_CLOEXEC);
 
 my sub set_id_map($$) {
     my ($pid, $id_map) = @_;
@@ -67,4 +67,34 @@ sub run_in_userns($;$) {
     PVE::Tools::run_fork($child, { afterfork => $parent });
 }
 
+# Create a new user namespace with the provided idmap applied.
+# Returns a file handle to the namespace.
+sub new_userns($) {
+    my ($id_map) = @_;
+    socketpair(my $sp, my $sc, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
+        or die "socketpair: $!\n";
+    my $userns_fh;
+    my $child = sub {
+        close($sp);
+        PVE::Tools::unshare(CLONE_NEWUSER) or die "unshare(NEWUSER): $!\n";
+        sync_send($sc, "1\n");
+        shutdown($sc, 1);
+        sync_recv($sc, "2\n");
+        close($sc);
+    };
+    my $parent = sub {
+        my ($pid) = @_;
+        close($sc);
+        sync_recv($sp, "1\n");
+        set_id_map($pid, $id_map);
+        sysopen($userns_fh, "/proc/$pid/ns/user", O_RDONLY | O_CLOEXEC)
+            or die "Failed to open user namespace of child: $!\n";
+        sync_send($sp, "2\n");
+        close($sp);
+    };
+    PVE::Tools::run_fork($child, { afterfork => $parent });
+
+    return $userns_fh;
+}
+
 1;
-- 
2.47.3




Reply via email to