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__ |