Skip to content

Commit a698552

Browse files
authored
Merge pull request #3980 from cyphar/timens-cleanups
timens: minor cleanups
2 parents 0866112 + aa5f4c1 commit a698552

File tree

7 files changed

+105
-14
lines changed

7 files changed

+105
-14
lines changed

libcontainer/configs/validate/validator.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ func namespaces(config *configs.Config) error {
120120
if _, err := os.Stat("/proc/self/timens_offsets"); os.IsNotExist(err) {
121121
return errors.New("time namespaces aren't enabled in the kernel")
122122
}
123+
} else {
124+
if config.TimeOffsets != nil {
125+
return errors.New("time namespace offsets specified, but time namespace isn't enabled in the config")
126+
}
123127
}
124128

125129
return nil

libcontainer/configs/validate/validator_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77

88
"github.com/opencontainers/runc/libcontainer/configs"
9+
"github.com/opencontainers/runtime-spec/specs-go"
910
"golang.org/x/sys/unix"
1011
)
1112

@@ -201,6 +202,40 @@ func TestValidateUsernamespaceWithoutUserNS(t *testing.T) {
201202
}
202203
}
203204

205+
func TestValidateTimeNamespace(t *testing.T) {
206+
if _, err := os.Stat("/proc/self/ns/time"); os.IsNotExist(err) {
207+
t.Skip("Test requires timens.")
208+
}
209+
config := &configs.Config{
210+
Rootfs: "/var",
211+
Namespaces: configs.Namespaces(
212+
[]configs.Namespace{
213+
{Type: configs.NEWTIME},
214+
},
215+
),
216+
}
217+
218+
err := Validate(config)
219+
if err != nil {
220+
t.Errorf("expected error to not occur %+v", err)
221+
}
222+
}
223+
224+
func TestValidateTimeOffsetsWithoutTimeNamespace(t *testing.T) {
225+
config := &configs.Config{
226+
Rootfs: "/var",
227+
TimeOffsets: map[string]specs.LinuxTimeOffset{
228+
"boottime": {Secs: 150, Nanosecs: 314159},
229+
"monotonic": {Secs: 512, Nanosecs: 271818},
230+
},
231+
}
232+
233+
err := Validate(config)
234+
if err == nil {
235+
t.Error("Expected error to occur but it was nil")
236+
}
237+
}
238+
204239
// TestConvertSysctlVariableToDotsSeparator tests whether the sysctl variable
205240
// can be correctly converted to a dot as a separator.
206241
func TestConvertSysctlVariableToDotsSeparator(t *testing.T) {

libcontainer/container_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
11921192
}
11931193

11941194
// write boottime and monotonic time ns offsets.
1195-
if c.config.Namespaces.Contains(configs.NEWTIME) && c.config.TimeOffsets != nil {
1195+
if c.config.TimeOffsets != nil {
11961196
var offsetSpec bytes.Buffer
11971197
for clock, offset := range c.config.TimeOffsets {
11981198
fmt.Fprintf(&offsetSpec, "%s %d %d\n", clock, offset.Secs, offset.Nanosecs)

libcontainer/nsenter/nsexec.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -758,15 +758,13 @@ void receive_idmapsources(int sockfd)
758758
receive_fd_sources(sockfd, "_LIBCONTAINER_IDMAP_FDS");
759759
}
760760

761-
static void update_timens(char *map, size_t map_len)
761+
static void update_timens_offsets(char *map, size_t map_len)
762762
{
763763
if (map == NULL || map_len == 0)
764764
return;
765765
write_log(DEBUG, "update /proc/self/timens_offsets to '%s'", map);
766-
if (write_file(map, map_len, "/proc/self/timens_offsets") < 0) {
767-
if (errno != EPERM)
768-
bail("failed to update /proc/self/timens_offsets");
769-
}
766+
if (write_file(map, map_len, "/proc/self/timens_offsets") < 0)
767+
bail("failed to update /proc/self/timens_offsets");
770768
}
771769

772770
void nsexec(void)
@@ -1174,6 +1172,7 @@ void nsexec(void)
11741172
* was broken, so we'll just do it the long way anyway.
11751173
*/
11761174
try_unshare(config.cloneflags & ~CLONE_NEWCGROUP, "remaining namespaces (except cgroupns)");
1175+
update_timens_offsets(config.timensoffset, config.timensoffset_len);
11771176

11781177
/* Ask our parent to send the mount sources fds. */
11791178
if (config.mountsources) {
@@ -1207,11 +1206,6 @@ void nsexec(void)
12071206
bail("failed to sync with parent: SYNC_MOUNT_IDMAP_ACK: got %u", s);
12081207
}
12091208

1210-
/*
1211-
* set boottime and monotonic timens offsets.
1212-
*/
1213-
update_timens(config.timensoffset, config.timensoffset_len);
1214-
12151209
/*
12161210
* TODO: What about non-namespace clone flags that we're dropping here?
12171211
*

libcontainer/specconv/spec_linux.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
422422
config.ReadonlyPaths = spec.Linux.ReadonlyPaths
423423
config.MountLabel = spec.Linux.MountLabel
424424
config.Sysctl = spec.Linux.Sysctl
425+
config.TimeOffsets = spec.Linux.TimeOffsets
425426
if spec.Linux.Seccomp != nil {
426427
seccomp, err := SetupSeccomp(spec.Linux.Seccomp)
427428
if err != nil {
@@ -436,9 +437,6 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
436437
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
437438
}
438439
}
439-
440-
// update timens offsets
441-
config.TimeOffsets = spec.Linux.TimeOffsets
442440
}
443441

444442
// Set the host UID that should own the container's cgroup.

tests/integration/helpers.bash

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,11 @@ function requires() {
429429
skip_me=1
430430
fi
431431
;;
432+
timens)
433+
if [ ! -e "/proc/self/ns/time" ]; then
434+
skip_me=1
435+
fi
436+
;;
432437
cgroups_v1)
433438
init_cgroup_paths
434439
if [ ! -v CGROUP_V1 ]; then

tests/integration/timens.bats

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bats
2+
3+
load helpers
4+
5+
function setup() {
6+
setup_busybox
7+
}
8+
9+
function teardown() {
10+
teardown_bundle
11+
}
12+
13+
@test "runc run [timens offsets with no timens]" {
14+
requires timens
15+
16+
update_config '.process.args = ["cat", "/proc/self/timens_offsets"]'
17+
update_config '.linux.namespaces = .linux.namespace | map(select(.type != "time"))'
18+
update_config '.linux.timeOffsets = {
19+
"monotonic": { "secs": 7881, "nanosecs": 2718281 },
20+
"boottime": { "secs": 1337, "nanosecs": 3141519 }
21+
}'
22+
23+
runc run test_busybox
24+
[ "$status" -ne 0 ]
25+
}
26+
27+
@test "runc run [timens with no offsets]" {
28+
requires timens
29+
30+
update_config '.process.args = ["cat", "/proc/self/timens_offsets"]'
31+
update_config '.linux.namespaces += [{"type": "time"}]
32+
| .linux.timeOffsets = null'
33+
34+
runc run test_busybox
35+
[ "$status" -eq 0 ]
36+
# Default offsets are 0.
37+
grep -E '^monotonic\s+0\s+0$' <<<"$output"
38+
grep -E '^boottime\s+0\s+0$' <<<"$output"
39+
}
40+
41+
@test "runc run [simple timens]" {
42+
requires timens
43+
44+
update_config '.process.args = ["cat", "/proc/self/timens_offsets"]'
45+
update_config '.linux.namespaces += [{"type": "time"}]
46+
| .linux.timeOffsets = {
47+
"monotonic": { "secs": 7881, "nanosecs": 2718281 },
48+
"boottime": { "secs": 1337, "nanosecs": 3141519 }
49+
}'
50+
51+
runc run test_busybox
52+
[ "$status" -eq 0 ]
53+
grep -E '^monotonic\s+7881\s+2718281$' <<<"$output"
54+
grep -E '^boottime\s+1337\s+3141519$' <<<"$output"
55+
}

0 commit comments

Comments
 (0)