Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/common-go/nsenter/utils.go
2498 views
1
// Copyright (c) 2021 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
//go:build linux
6
// +build linux
7
8
package nsenter
9
10
import (
11
"fmt"
12
"os"
13
"os/exec"
14
"strconv"
15
16
"golang.org/x/sys/unix"
17
"golang.org/x/xerrors"
18
)
19
20
type Namespace int
21
22
const (
23
// NamespaceMount refers to the mount namespace
24
NamespaceMount = iota
25
// NamespaceNet refers to the network namespace
26
NamespaceNet
27
// NamespaceNet refers to the network namespace
28
NamespacePID
29
)
30
31
// Run executes a workspacekit handler in a namespace.
32
// Use preflight to check libseccomp.NotifIDValid().
33
func Run(pid int, args []string, addFD []*os.File, enterNamespace ...Namespace) error {
34
nss := []struct {
35
Env string
36
Source string
37
Flags int
38
NS Namespace
39
}{
40
{"_LIBNSENTER_ROOTFD", fmt.Sprintf("/proc/%d/root", pid), unix.O_PATH, -1},
41
{"_LIBNSENTER_CWDFD", fmt.Sprintf("/proc/%d/cwd", pid), unix.O_PATH, -1},
42
{"_LIBNSENTER_MNTNSFD", fmt.Sprintf("/proc/%d/ns/mnt", pid), os.O_RDONLY, NamespaceMount},
43
{"_LIBNSENTER_NETNSFD", fmt.Sprintf("/proc/%d/ns/net", pid), os.O_RDONLY, NamespaceNet},
44
{"_LIBNSENTER_PIDNSFD", fmt.Sprintf("/proc/%d/ns/pid", pid), os.O_RDONLY, NamespacePID},
45
}
46
47
stdioFdCount := 3
48
cmd := exec.Command("/proc/self/exe", append([]string{"handler"}, args...)...)
49
cmd.ExtraFiles = append(cmd.ExtraFiles, addFD...)
50
cmd.Env = os.Environ()
51
cmd.Env = append(cmd.Env, "_LIBNSENTER_INIT=1")
52
for _, ns := range nss {
53
var enter bool
54
if ns.NS == -1 {
55
enter = true
56
} else {
57
for _, s := range enterNamespace {
58
if ns.NS == s {
59
enter = true
60
break
61
}
62
}
63
}
64
if !enter {
65
continue
66
}
67
68
f, err := os.OpenFile(ns.Source, ns.Flags, 0)
69
if err != nil {
70
return xerrors.Errorf("cannot open %s: %w", ns.Source, err)
71
}
72
defer f.Close()
73
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", ns.Env, stdioFdCount+len(cmd.ExtraFiles)))
74
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
75
}
76
77
cmd.Stdout = os.Stdout
78
cmd.Stderr = os.Stderr
79
cmd.Stdin = os.Stdin
80
err := cmd.Run()
81
if err != nil {
82
return xerrors.Errorf("cannot run handler: %w", err)
83
}
84
return nil
85
}
86
87
// Mount executes mount in the mount namespace of PID
88
func Mount(pid int, source, target string, fstype string, flags int, data string) error {
89
args := []string{"mount",
90
"--source", source,
91
"--target", target,
92
"--flags", strconv.Itoa(flags),
93
}
94
if fstype != "" {
95
args = append(args, "--fstype", fstype)
96
}
97
if data != "" {
98
args = append(args, "--data", data)
99
}
100
return Run(pid, args, nil, NamespaceMount)
101
}
102
103
func MoveMount(pid int, fromFD *os.File, target string) error {
104
args := []string{"move-mount",
105
"--fd", "3",
106
"--dest", target,
107
}
108
return Run(pid, args, []*os.File{fromFD}, NamespaceMount)
109
}
110
111