-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathseminar.go
More file actions
178 lines (136 loc) · 4.18 KB
/
seminar.go
File metadata and controls
178 lines (136 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"syscall"
"time"
"net"
"strconv"
"io/ioutil"
)
func main() {
switch os.Args[1] {
case "run":
run()
case "child":
child()
default:
panic("help")
}
}
func pivotRoot(newroot string) error {
putold := filepath.Join(newroot, "/putold")
// https://unix.stackexchange.com/a/513417
// due to requirment that new root must not be on same filesystem as current root
// to do this we have to do a slight workaround - which to be completely honest I dont understand the reasoning behind
// but we are allowed to bind-mount new root to itself and then pivot the root to that directory
must(syscall.Mount(newroot, newroot, "", syscall.MS_BIND|syscall.MS_REC, ""))
// this is where we will put old root filesystem - has to be underneath new root
must(os.MkdirAll(putold, 0700))
must(syscall.PivotRoot(newroot, putold))
// ensure current working directory is set to new root
must(os.Chdir("/"))
// umount putold, granted now path is relative to our new root folder
must(syscall.Unmount("/putold", syscall.MNT_DETACH))
// remove putold
must(os.RemoveAll("/putold"))
return nil
}
// found at https://github.com/teddyking/ns-process/blob/master/net.go
func waitForNetwork() error {
maxWait := time.Second * 3
checkInterval := time.Second
timeStarted := time.Now()
for {
interfaces, err := net.Interfaces()
if err != nil {
return err
}
// pretty basic check ...
// > 1 as a lo device will already exist
if len(interfaces) > 1 {
return nil
}
if time.Since(timeStarted) > maxWait {
return fmt.Errorf("Timeout after %s waiting for network", maxWait)
}
time.Sleep(checkInterval)
}
}
// We call run function before child function because we need to create namespaces before we pupulate them
func run() {
// telling the programm to call itself but now in child case, we dont yet run the command - we only do that with cmd. lines
cmd := exec.Command("/proc/self/exe",append([]string{"child"}, os.Args[2:]...)...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWNS |
syscall.CLONE_NEWUTS |
syscall.CLONE_NEWIPC |
syscall.CLONE_NEWPID |
syscall.CLONE_NEWNET |
syscall.CLONE_NEWUSER,
Unshareflags: syscall.CLONE_NEWNS,
// mapping user and groups to be root insite the container
UidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getuid(),
Size: 1,
},
},
GidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getgid(),
Size: 1,
},
},
}
must(cmd.Start())
pid := fmt.Sprintf("%d", cmd.Process.Pid)
netsetgoCmd := exec.Command("/usr/local/bin/netsetgo", "-pid", pid)
must(netsetgoCmd.Run())
must(cmd.Wait())
}
func child () {
// using cgroup created in previous example to limit memory usage of our process
parent_cgroup := "/sys/fs/cgroup/test"
leaf := filepath.Join(parent_cgroup, "child_test")
// Limiting cgroup to 10 processes
must(ioutil.WriteFile(filepath.Join(leaf, "pids.max"), []byte("10"), 0700))
// Limiting this cgroup to 10 Mb of memory
must(ioutil.WriteFile(filepath.Join(leaf, "memory.max"), []byte("10M"), 0700))
// adding this process to cgroup
must(ioutil.WriteFile(filepath.Join(leaf, "cgroup.procs"),[]byte(strconv.Itoa(os.Getpid())), 0700))
// Execute all arguments after the first one
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// Mount our directory to place where we stored out alpine linux file system
must(syscall.Mount(
"proc",
"/root/alpine/rootfs/proc",
"proc",
0,
"",
))
// pivoting root to our new root directory
must(pivotRoot("/root/alpine/rootfs"))
python1 := exec.Command("apk add python3")
python1.Run()
// Using our newly created UTS namespace to set a new hostname
must(syscall.Sethostname([]byte("DaniloAlpineContainer")))
must(waitForNetwork())
must(cmd.Run())
}
func must(err error) {
if err != nil {
fmt.Printf("Error - %s\n", err)
os.Exit(1)
}
}