File Coverage

lib/Mojo/IOLoop/ReadWriteProcess/Namespace.pm
Criterion Covered Total %
statement 55 65 84.6
branch 17 40 42.5
condition 5 13 38.4
subroutine 11 11 100.0
pod 3 3 100.0
total 91 132 68.9


line stmt bran cond sub pod time code
1             package Mojo::IOLoop::ReadWriteProcess::Namespace;
2 13     13   91 use Mojo::Base -base;
  13         25  
  13         90  
3 13     13   1938 use Mojo::File 'path';
  13         25  
  13         696  
4 13     13   187 use Carp 'confess';
  13         33  
  13         599  
5 13     13   89 use Config;
  13         28  
  13         985  
6              
7             use constant {
8 13         3140 CLONE_ALL => 0,
9             CLONE_NEWNS => 0x00020000,
10             CLONE_NEWIPC => 0x08000000,
11             CLONE_NEWNET => 0x40000000,
12             CLONE_NEWUTS => 0x04000000,
13             CLONE_NEWPID => 0x20000000,
14             CLONE_NEWUSER => 0x10000000,
15             CLONE_NEWCGROUP => 0x02000000,
16             MS_REC => 0x4000,
17             MS_PRIVATE => 1 << 18,
18             MS_NOSUID => 2,
19             MS_NOEXEC => 8,
20             MS_NODEV => 4,
21 13     13   80 };
  13         25  
22              
23             our @EXPORT_OK = (
24             qw(CLONE_ALL CLONE_NEWNS CLONE_NEWIPC CLONE_NEWUTS),
25             qw(CLONE_NEWNET CLONE_NEWPID CLONE_NEWUSER CLONE_NEWCGROUP),
26             qw(MS_REC MS_PRIVATE MS_NOSUID MS_NOEXEC MS_NODEV)
27             );
28 13     13   90 use Exporter 'import';
  13         26  
  13         12201  
29              
30             sub _get_unshare_syscall {
31              
32 3 50   3   90 confess "Only Linux is supported" unless $^O eq 'linux';
33              
34 3         55 my $machine = (POSIX::uname())[4];
35 3 50       14 die "Could not get machine type" unless $machine;
36              
37             # if we're running on an x86_64 kernel, but a 32-bit process,
38             # we need to use the i386 syscall numbers.
39 3 50 33     223 $machine = "i386" if ($machine eq "x86_64" && $Config{ptrsize} == 4);
40              
41 3 0       63 my $prctl_call
    0          
    50          
    50          
    50          
42             = $machine
43             =~ /^i[3456]86|^blackfin|cris|frv|h8300|m32r|m68k|microblaze|mn10300|sh|parisc$/
44             ? 310
45             : $machine eq "s390" ? 303
46              
47             : $machine eq "x86_64" ? 272
48             : $machine eq "ppc" ? 282
49             : $machine eq "ia64" ? 1296
50             : undef;
51              
52 3 50       14 unless (defined $prctl_call) {
53             delete @INC{
54 0         0 qw
55             sys/syscall.ph>
56             };
57 0         0 my $rv = eval { require 'syscall.ph'; 1 } ## no critic
  0         0  
58 0 0       0 or eval { require 'sys/syscall.ph'; 1 }; ## no critic
  0         0  
  0         0  
59              
60 0         0 $prctl_call = eval { &SYS_unshare; };
  0         0  
61             }
62 3         33 return $prctl_call;
63             }
64              
65             sub _get_mount_syscall {
66              
67 2 50   2   42 confess "Only Linux is supported" unless $^O eq 'linux';
68              
69 2         51 my $machine = (POSIX::uname())[4];
70 2 50       38 die "Could not get machine type" unless $machine;
71              
72             # if we're running on an x86_64 kernel, but a 32-bit process,
73             # we need to use the i386 syscall numbers.
74 2 50 33     133 $machine = "i386" if ($machine eq "x86_64" && $Config{ptrsize} == 4);
75              
76 2         16 my $prctl_call;
77              
78             # $machine
79             # =~ /^i[3456]86|^blackfin|cris|frv|h8300|m32r|m68k|microblaze|mn10300|sh|parisc$/
80             # ? 310
81             # : $machine eq "s390" ? 303
82             #
83             # : $machine eq "x86_64" ? 272
84             # : $machine eq "ppc" ? 282
85             # : $machine eq "ia64" ? 1296
86             # :
87              
88              
89 2 50       27 unless (defined $prctl_call) {
90             delete @INC{
91 2         29 qw
92             sys/syscall.ph>
93             };
94 2         568 my $rv = eval { require 'syscall.ph'; 1 } ## no critic
  0         0  
95 2 50       15 or eval { require 'sys/syscall.ph'; 1 }; ## no critic
  2         321  
  0         0  
96              
97 2         44 $prctl_call = eval { &SYS_mount; };
  2         125  
98             }
99 2         76 return $prctl_call;
100             }
101              
102             sub mount {
103 2     2 1 16 my ($self, $arg1, $arg2, $arg3, $opts) = (@_);
104 2   50     35 $arg3 //= 0;
105 2         43 local $!;
106 2         23 my $ret
107             = syscall(_get_mount_syscall(), my $s = $arg1, my $t = $arg2, $arg3, $opts,
108             0);
109              
110 2 50       96 warn "mount is unavailable on this platform." if $!{EINVAL};
111 2 50       156 warn "Mount failed! $!" if $!;
112 2         57 return $ret;
113             }
114              
115             sub unshare {
116 3     3 1 147 my ($self, $opts) = @_;
117 3         515 local $!;
118 3         51 my $ret = syscall(_get_unshare_syscall(), $opts, 0, 0);
119              
120 3 50       94 warn "unshare is unavailable on this platform." if $!{EINVAL};
121 3 50       167 warn "Unshare failed! $!" if $!;
122 3         29 return $ret;
123             }
124              
125             sub isolate {
126 1     1 1 110 my ($self, $procdir) = shift;
127 1   50     70 $procdir //= "/proc";
128 1         24 $self->mount("none", "/", 0, MS_REC | MS_PRIVATE);
129 1 50 33     5 warn "Failed isolating proc"
130             if $self->mount("none", $procdir, 0, MS_REC | MS_PRIVATE) != 0
131             || $self->mount("proc", $procdir, "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV)
132             != 0;
133             }
134              
135             =encoding utf-8
136              
137             =head1 NAME
138              
139             Mojo::IOLoop::ReadWriteProcess::Namespace - Namespace object for Mojo::IOLoop::ReadWriteProcess.
140              
141             =head1 SYNOPSIS
142              
143             use Mojo::IOLoop::ReadWriteProcess::Namespace qw(CLONE_ALL);
144              
145             my $ns = Mojo::IOLoop::ReadWriteProcess::Namespace->new();
146              
147             $ns->unshare(CLONE_ALL);
148             $ns->mount("proc", "/proc", "proc");
149             $ns->isolate();
150              
151             =head1 METHODS
152              
153             L inherits all methods from L and implements
154             the following new ones.
155              
156             =head2 unshare
157              
158             use Mojo::IOLoop::ReadWriteProcess::Namespace qw(CLONE_ALL);
159             my $ns = Mojo::IOLoop::ReadWriteProcess::Namespace->new();
160             $ns->unshare(CLONE_ALL);
161              
162             Wrapper around the unshare syscall, accepts the same arguments,
163             constants can be exported from L.
164              
165             =head2 mount
166              
167             my $ns = Mojo::IOLoop::ReadWriteProcess::Namespace->new();
168             $ns->mount("proc", "/proc", "proc");
169              
170             Wrapper around the mount syscall, accepts the same arguments.
171              
172             =head2 isolate
173              
174             my $ns = Mojo::IOLoop::ReadWriteProcess::Namespace->new();
175             $ns->isolate();
176              
177             Mount appropriately /proc to achieve process isolation during process containment, see L.
178              
179             =head1 LICENSE
180              
181             Copyright (C) Ettore Di Giacinto.
182              
183             This library is free software; you can redistribute it and/or modify
184             it under the same terms as Perl itself.
185              
186             =head1 AUTHOR
187              
188             Ettore Di Giacinto Eedigiacinto@suse.comE
189              
190             =cut
191              
192              
193             1;