File Coverage

blib/lib/App/Hako.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 13 13 100.0


line stmt bran cond sub pod time code
1             package App::Hako;
2 1     1   440 use 5.008001;
  1         3  
3 1     1   3 use strict;
  1         1  
  1         36  
4 1     1   9 use warnings;
  1         1  
  1         52  
5              
6             our $VERSION = "0.02";
7              
8             BEGIN {
9 1     1   182 require 'syscall.ph';
10             # really we want to also:
11             # require "linux/sched.ph";
12             # require "sys/mount.ph";
13             # but those headers are not in core,
14             # and I haven't ran h2ph correctly yet!
15             # Instead, use magic number constants for now.
16             }
17              
18             use constant {
19             MS_BIND => 4096,
20             CLONE_NEWNS => 0x20000,
21             CLONE_NEWUTS => 0x4000000,
22             CLONE_NEWIPC => 0x8000000,
23             CLONE_NEWUSER => 0x10000000,
24             CLONE_NEWPID => 0x20000000,
25             CLONE_NEWNET => 0x40000000,
26             };
27              
28             sub run {
29             my ($box, @cmd) = @_;
30             chdir $box or die "cannot enter $box: $!\n";
31             my $uid = $>;
32             my ($gid) = split " ", $);
33             syscall(SYS_unshare, CLONE_NEWUSER|CLONE_NEWNS);
34             map_my_id($uid, $gid);
35             bind_mount($box, $ENV{HOME});
36             chdir or die "cannot go home: $!\n";
37             exec @cmd;
38             die "exec failed: $!\n";
39             }
40              
41             sub bind_mount {
42             my ($src, $tgt) = @_;
43             my $dummy = "ignore me";
44             syscall(SYS_mount, $src, $tgt, $dummy, MS_BIND, $dummy);
45             }
46              
47             sub map_my_id {
48             my ($uid, $gid) = @_;
49             proc_write(setgroups => "deny");
50             proc_write(uid_map => "$uid $uid 1");
51             proc_write(gid_map => "$gid $gid 1");
52             }
53              
54             sub proc_write ($$) {
55             my ($file, $data) = @_;
56             open my $pf, ">", "/proc/self/$file" or die "cannot open $file: $!\n";
57             print {$pf} $data or die "cannot write to $file: $!\n";
58             close $pf or die "failed to close $file: $!\n";
59             }
60              
61             1;
62             __END__