Skip to content

Commit 8ce0b3e

Browse files
committed
[ws-daemon] Internalize libcontainer/specconv because it got dropped between runc 1.1.10 and 1.1.14
1 parent 5c3f05d commit 8ce0b3e

File tree

7 files changed

+409
-4
lines changed

7 files changed

+409
-4
lines changed

components/ws-daemon/go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ require (
153153
github.com/prometheus/common v0.48.0 // indirect
154154
github.com/prometheus/procfs v0.12.0 // indirect
155155
github.com/rs/xid v1.5.0 // indirect
156-
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646 // indirect
157156
github.com/slok/go-http-metrics v0.10.0 // indirect
158157
github.com/spf13/pflag v1.0.5 // indirect
159158
github.com/stretchr/testify v1.9.0 // indirect

components/ws-daemon/pkg/cgroup/plugin_fuse_v2.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import (
1111
"github.com/opencontainers/runc/libcontainer/cgroups/ebpf"
1212
"github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter"
1313
"github.com/opencontainers/runc/libcontainer/devices"
14-
"github.com/opencontainers/runc/libcontainer/specconv"
1514
"golang.org/x/sys/unix"
1615
"golang.org/x/xerrors"
1716

1817
"github.com/gitpod-io/gitpod/common-go/log"
18+
"github.com/gitpod-io/gitpod/ws-daemon/pkg/libcontainer/specconv"
1919
)
2020

2121
var (

components/ws-daemon/pkg/content/initializer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"time"
1919

2020
"github.com/google/uuid"
21-
"github.com/opencontainers/runc/libcontainer/specconv"
2221
"github.com/opencontainers/runtime-spec/specs-go"
2322
"github.com/opentracing/opentracing-go"
2423
"github.com/sirupsen/logrus"
@@ -31,6 +30,7 @@ import (
3130
"github.com/gitpod-io/gitpod/content-service/pkg/archive"
3231
wsinit "github.com/gitpod-io/gitpod/content-service/pkg/initializer"
3332
"github.com/gitpod-io/gitpod/content-service/pkg/storage"
33+
"github.com/gitpod-io/gitpod/ws-daemon/pkg/libcontainer/specconv"
3434
)
3535

3636
// RunInitializerOpts configure RunInitializer
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Why this package exists
2+
3+
The only reason this package exists is because libcontainer decided to privatize some functions we depend on in the specconv package.
4+
It was easier to copy the files over than re-thinking everything we're doing here.
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// Copyright The libcontainer authors
2+
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Copied from: https://github.com/opencontainers/runc/blob/364ec0f1b4fa188ad96049c590ecb42fa70ea165/libcontainer/specconv/example.go#L1
16+
package specconv
17+
18+
import (
19+
"os"
20+
"path/filepath"
21+
"strings"
22+
23+
"github.com/opencontainers/runc/libcontainer/cgroups"
24+
"github.com/opencontainers/runtime-spec/specs-go"
25+
)
26+
27+
// Example returns an example spec file, with many options set so a user can
28+
// see what a standard spec file looks like.
29+
func Example() *specs.Spec {
30+
spec := &specs.Spec{
31+
Version: specs.Version,
32+
Root: &specs.Root{
33+
Path: "rootfs",
34+
Readonly: true,
35+
},
36+
Process: &specs.Process{
37+
Terminal: true,
38+
User: specs.User{},
39+
Args: []string{
40+
"sh",
41+
},
42+
Env: []string{
43+
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
44+
"TERM=xterm",
45+
},
46+
Cwd: "/",
47+
NoNewPrivileges: true,
48+
Capabilities: &specs.LinuxCapabilities{
49+
Bounding: []string{
50+
"CAP_AUDIT_WRITE",
51+
"CAP_KILL",
52+
"CAP_NET_BIND_SERVICE",
53+
},
54+
Permitted: []string{
55+
"CAP_AUDIT_WRITE",
56+
"CAP_KILL",
57+
"CAP_NET_BIND_SERVICE",
58+
},
59+
Ambient: []string{
60+
"CAP_AUDIT_WRITE",
61+
"CAP_KILL",
62+
"CAP_NET_BIND_SERVICE",
63+
},
64+
Effective: []string{
65+
"CAP_AUDIT_WRITE",
66+
"CAP_KILL",
67+
"CAP_NET_BIND_SERVICE",
68+
},
69+
},
70+
Rlimits: []specs.POSIXRlimit{
71+
{
72+
Type: "RLIMIT_NOFILE",
73+
Hard: uint64(1024),
74+
Soft: uint64(1024),
75+
},
76+
},
77+
},
78+
Hostname: "runc",
79+
Mounts: []specs.Mount{
80+
{
81+
Destination: "/proc",
82+
Type: "proc",
83+
Source: "proc",
84+
Options: nil,
85+
},
86+
{
87+
Destination: "/dev",
88+
Type: "tmpfs",
89+
Source: "tmpfs",
90+
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
91+
},
92+
{
93+
Destination: "/dev/pts",
94+
Type: "devpts",
95+
Source: "devpts",
96+
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
97+
},
98+
{
99+
Destination: "/dev/shm",
100+
Type: "tmpfs",
101+
Source: "shm",
102+
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
103+
},
104+
{
105+
Destination: "/dev/mqueue",
106+
Type: "mqueue",
107+
Source: "mqueue",
108+
Options: []string{"nosuid", "noexec", "nodev"},
109+
},
110+
{
111+
Destination: "/sys",
112+
Type: "sysfs",
113+
Source: "sysfs",
114+
Options: []string{"nosuid", "noexec", "nodev", "ro"},
115+
},
116+
{
117+
Destination: "/sys/fs/cgroup",
118+
Type: "cgroup",
119+
Source: "cgroup",
120+
Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
121+
},
122+
},
123+
Linux: &specs.Linux{
124+
MaskedPaths: []string{
125+
"/proc/acpi",
126+
"/proc/asound",
127+
"/proc/kcore",
128+
"/proc/keys",
129+
"/proc/latency_stats",
130+
"/proc/timer_list",
131+
"/proc/timer_stats",
132+
"/proc/sched_debug",
133+
"/sys/firmware",
134+
"/proc/scsi",
135+
},
136+
ReadonlyPaths: []string{
137+
"/proc/bus",
138+
"/proc/fs",
139+
"/proc/irq",
140+
"/proc/sys",
141+
"/proc/sysrq-trigger",
142+
},
143+
Resources: &specs.LinuxResources{
144+
Devices: []specs.LinuxDeviceCgroup{
145+
{
146+
Allow: false,
147+
Access: "rwm",
148+
},
149+
},
150+
},
151+
Namespaces: []specs.LinuxNamespace{
152+
{
153+
Type: specs.PIDNamespace,
154+
},
155+
{
156+
Type: specs.NetworkNamespace,
157+
},
158+
{
159+
Type: specs.IPCNamespace,
160+
},
161+
{
162+
Type: specs.UTSNamespace,
163+
},
164+
{
165+
Type: specs.MountNamespace,
166+
},
167+
},
168+
},
169+
}
170+
if cgroups.IsCgroup2UnifiedMode() {
171+
spec.Linux.Namespaces = append(spec.Linux.Namespaces, specs.LinuxNamespace{
172+
Type: specs.CgroupNamespace,
173+
})
174+
}
175+
return spec
176+
}
177+
178+
// ToRootless converts the given spec file into one that should work with
179+
// rootless containers (euid != 0), by removing incompatible options and adding others that
180+
// are needed.
181+
func ToRootless(spec *specs.Spec) {
182+
var namespaces []specs.LinuxNamespace
183+
184+
// Remove networkns from the spec.
185+
for _, ns := range spec.Linux.Namespaces {
186+
switch ns.Type {
187+
case specs.NetworkNamespace, specs.UserNamespace:
188+
// Do nothing.
189+
default:
190+
namespaces = append(namespaces, ns)
191+
}
192+
}
193+
// Add userns to the spec.
194+
namespaces = append(namespaces, specs.LinuxNamespace{
195+
Type: specs.UserNamespace,
196+
})
197+
spec.Linux.Namespaces = namespaces
198+
199+
// Add mappings for the current user.
200+
spec.Linux.UIDMappings = []specs.LinuxIDMapping{{
201+
HostID: uint32(os.Geteuid()),
202+
ContainerID: 0,
203+
Size: 1,
204+
}}
205+
spec.Linux.GIDMappings = []specs.LinuxIDMapping{{
206+
HostID: uint32(os.Getegid()),
207+
ContainerID: 0,
208+
Size: 1,
209+
}}
210+
211+
// Fix up mounts.
212+
var mounts []specs.Mount
213+
for _, mount := range spec.Mounts {
214+
// Replace the /sys mount with an rbind.
215+
if filepath.Clean(mount.Destination) == "/sys" {
216+
mounts = append(mounts, specs.Mount{
217+
Source: "/sys",
218+
Destination: "/sys",
219+
Type: "none",
220+
Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"},
221+
})
222+
continue
223+
}
224+
225+
// Remove all gid= and uid= mappings.
226+
var options []string
227+
for _, option := range mount.Options {
228+
if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") {
229+
options = append(options, option)
230+
}
231+
}
232+
233+
mount.Options = options
234+
mounts = append(mounts, mount)
235+
}
236+
spec.Mounts = mounts
237+
238+
// Remove cgroup settings.
239+
spec.Linux.Resources = nil
240+
}

0 commit comments

Comments
 (0)