-
Notifications
You must be signed in to change notification settings - Fork 19
/
init.go
124 lines (109 loc) · 3.56 KB
/
init.go
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
package lxcri
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/lxc/lxcri/pkg/specki"
"github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/sys/unix"
)
func createFifo(dst string, mode uint32) error {
if err := unix.Mkfifo(dst, mode); err != nil {
return errorf("mkfifo dst:%s failed: %w", dst, err)
}
// lxcri-init must be able to write to the fifo.
// Init process UID/GID can be different from runtime process UID/GID
// liblxc changes the owner of the runtime directory to the effective container UID.
// access to the files is protected by the runtimeDir
// because umask (0022) affects unix.Mkfifo, a separate chmod is required
// FIXME if container UID equals os.GetUID() and spec.
if err := unix.Chmod(dst, mode); err != nil {
return errorf("chmod mkfifo failed: %w", err)
}
return nil
}
// runAsRuntimeUser returns true if container process is started as runtime user.
func runAsRuntimeUser(spec *specs.Spec) bool {
puid := specki.UnmapContainerID(spec.Process.User.UID, spec.Linux.UIDMappings)
return puid == uint32(os.Getuid())
}
func configureInit(rt *Runtime, c *Container) error {
initDir := "/.lxcri"
c.Spec.Mounts = append(c.Spec.Mounts, specs.Mount{
Source: c.RuntimePath(),
Destination: strings.TrimLeft(initDir, "/"),
Type: "bind",
Options: []string{"bind", "ro", "nodev", "nosuid", "create=dir"},
})
if err := c.setConfigItem("lxc.init.cwd", initDir); err != nil {
return err
}
if runAsRuntimeUser(c.Spec) {
if err := createFifo(c.syncFifoPath(), 0600); err != nil {
return fmt.Errorf("failed to create sync fifo: %w", err)
}
} else {
if err := createFifo(c.syncFifoPath(), 0666); err != nil {
return fmt.Errorf("failed to create sync fifo: %w", err)
}
}
if err := configureInitUser(c); err != nil {
return err
}
// bind mount lxcri-init into the container
initCmdPath := c.RuntimePath("lxcri-init")
err := touchFile(initCmdPath, 0)
if err != nil {
return fmt.Errorf("failed to create %s: %w", initCmdPath, err)
}
initCmd := filepath.Join(initDir, "lxcri-init")
c.Spec.Mounts = append(c.Spec.Mounts, specs.Mount{
Source: rt.libexec(ExecInit),
Destination: strings.TrimLeft(initCmd, "/"),
Type: "bind",
Options: []string{"bind", "ro", "nosuid"},
})
return c.setConfigItem("lxc.init.cmd", initCmd)
}
func touchFile(filePath string, perm os.FileMode) error {
// #nosec
f, err := os.OpenFile(filePath, os.O_CREATE|os.O_RDONLY, perm)
if err == nil {
return f.Close()
}
return err
}
func configureInitUser(c *Container) error {
// TODO ensure that the user namespace is enabled
// See `man lxc.container.conf` lxc.idmap.
for _, m := range c.Spec.Linux.UIDMappings {
if err := c.setConfigItem("lxc.idmap", fmt.Sprintf("u %d %d %d", m.ContainerID, m.HostID, m.Size)); err != nil {
return err
}
}
for _, m := range c.Spec.Linux.GIDMappings {
if err := c.setConfigItem("lxc.idmap", fmt.Sprintf("g %d %d %d", m.ContainerID, m.HostID, m.Size)); err != nil {
return err
}
}
if err := c.setConfigItem("lxc.init.uid", fmt.Sprintf("%d", c.Spec.Process.User.UID)); err != nil {
return err
}
if err := c.setConfigItem("lxc.init.gid", fmt.Sprintf("%d", c.Spec.Process.User.GID)); err != nil {
return err
}
if len(c.Spec.Process.User.AdditionalGids) > 0 && c.supportsConfigItem("lxc.init.groups") {
var b strings.Builder
for i, gid := range c.Spec.Process.User.AdditionalGids {
if i > 0 {
b.WriteByte(',')
}
fmt.Fprintf(&b, "%d", gid)
}
if err := c.setConfigItem("lxc.init.groups", b.String()); err != nil {
return err
}
}
return nil
}