Skip to content

Commit 5839cc6

Browse files
committed
Add os.md
1 parent 76a34ac commit 5839cc6

3 files changed

Lines changed: 116 additions & 0 deletions

File tree

content/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ Some starting points to navigate in this labyrinth:
1111
- [[hardware-security]] perfect crossover of security and systems
1212
- [[web-dev]]
1313
- [[compilers]] a rather deep dive in compilation, execution, binaries
14+
- [[os]] for system madlads
1415
- [[cpp]] still learning this humongoes language to get better at computer systems
1516
- [[reading]]

content/os/container.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
## Containerization
2+
3+
But how is Docker is even implemented? What means to spawn a container?
4+
The answer to both these questions is closely related to linux process management and user space.
5+
6+
## Go: minimal container
7+
Create the following program in a new folder
8+
9+
```go
10+
// container/main.go
11+
package main
12+
13+
import (
14+
"fmt"
15+
"os"
16+
"os/exec"
17+
"syscall"
18+
)
19+
20+
const ROOT_DIR = "./fs"
21+
22+
func run() {
23+
fmt.Printf("running %v as %d\n", os.Args[2:], os.Getpid())
24+
cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
25+
cmd.Stdin = os.Stdin
26+
cmd.Stdout = os.Stdout
27+
cmd.Stderr = os.Stderr
28+
29+
cmd.SysProcAttr = &syscall.SysProcAttr{
30+
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID,
31+
}
32+
33+
cmd.Run()
34+
}
35+
36+
func child() {
37+
fmt.Printf("running %v as %d\n", os.Args[2:], os.Getpid())
38+
syscall.Sethostname([]byte("container"))
39+
must(syscall.Chroot(ROOT_DIR))
40+
must(syscall.Chdir("/"))
41+
42+
cmd := exec.Command(os.Args[2], os.Args[3:]...)
43+
cmd.Stdin = os.Stdin
44+
cmd.Stdout = os.Stdout
45+
cmd.Stderr = os.Stderr
46+
cmd.Env = append(os.Environ(), "PATH=/bin")
47+
48+
must(cmd.Run())
49+
}
50+
51+
func must(err error) {
52+
if err != nil { panic(err) }
53+
}
54+
55+
func main() {
56+
switch os.Args[1] {
57+
case "run":
58+
run()
59+
case "child":
60+
child()
61+
default:
62+
panic("bad command")
63+
}
64+
}
65+
```
66+
67+
## Minimal filesystem
68+
We will spawn a container rooted inside the `./fs` directory, for this we need to setup `fs`. Create the following script outside `fs`
69+
```bash
70+
#!/bin/bash
71+
# container/make-rootfs.sh
72+
73+
# 1. Make sure the fs tree exists
74+
mkdir -p fs/{bin,proc}
75+
76+
# 2. Download a real binary
77+
if [ ! -f ./fs/bin/busybox ]; then
78+
curl -L https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox -o fs/bin/busybox
79+
fi
80+
81+
# (Check BusyBox site for the latest x86_64 build if the above link 404s)
82+
# 3. Make it executable and symlink sh
83+
chmod +x fs/bin/busybox
84+
for app in sh ls cat echo ps; do
85+
if [ ! -f ./fs/bin/$app ]; then
86+
ln -s busybox fs/bin/$app
87+
fi
88+
done
89+
```
90+
91+
This will spawn a child process which exec's the program given by the user (we will try to invoke `./fs/bin/sh`.
92+
- run the script defined above: `sudo ./make-rootfs.sh`
93+
- build the container binary: `go build -o container main.go`
94+
- run the container: `sudo ./container run /bin/sh`
95+
96+
```shell
97+
$ sudo ./container run /bin/sh
98+
running [/bin/sh] as 81281
99+
running [/bin/sh] as 1
100+
/ # ls -a
101+
. .. bin proc
102+
/ #
103+
```
104+
105+
## Todo: symbolically linking `/proc`

content/os/os.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Operating Systems
2+
3+
At the time of writing this note, I am running a machine with the following specifications:
4+
- Operating System: Arch Linux
5+
- Kernel: Linux 6.12.45-1-lts
6+
- Architecture: x86-64
7+
8+
And that is why much of the notes found here will be related to linux environment.
9+
10+
- Recently I tried writing a minimal [[container]] program in golang

0 commit comments

Comments
 (0)