diff --git a/libcontainer/configs/validate/validator_test.go b/libcontainer/configs/validate/validator_test.go index b6b2d3723..d2b3c70ad 100644 --- a/libcontainer/configs/validate/validator_test.go +++ b/libcontainer/configs/validate/validator_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" ) @@ -201,6 +202,40 @@ func TestValidateUsernamespaceWithoutUserNS(t *testing.T) { } } +func TestValidateTimeNamespace(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/time"); os.IsNotExist(err) { + t.Skip("Test requires timens.") + } + config := &configs.Config{ + Rootfs: "/var", + Namespaces: configs.Namespaces( + []configs.Namespace{ + {Type: configs.NEWTIME}, + }, + ), + } + + err := Validate(config) + if err != nil { + t.Errorf("expected error to not occur %+v", err) + } +} + +func TestValidateTimeOffsetsWithoutTimeNamespace(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + TimeOffsets: map[string]specs.LinuxTimeOffset{ + "boottime": {Secs: 150, Nanosecs: 314159}, + "monotonic": {Secs: 512, Nanosecs: 271818}, + }, + } + + err := Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + // TestConvertSysctlVariableToDotsSeparator tests whether the sysctl variable // can be correctly converted to a dot as a separator. func TestConvertSysctlVariableToDotsSeparator(t *testing.T) { diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash index e1ce42144..65912951d 100755 --- a/tests/integration/helpers.bash +++ b/tests/integration/helpers.bash @@ -429,6 +429,11 @@ function requires() { skip_me=1 fi ;; + timens) + if [ ! -e "/proc/self/ns/time" ]; then + skip_me=1 + fi + ;; cgroups_v1) init_cgroup_paths if [ ! -v CGROUP_V1 ]; then diff --git a/tests/integration/timens.bats b/tests/integration/timens.bats new file mode 100644 index 000000000..e0d21d551 --- /dev/null +++ b/tests/integration/timens.bats @@ -0,0 +1,55 @@ +#!/usr/bin/env bats + +load helpers + +function setup() { + setup_busybox +} + +function teardown() { + teardown_bundle +} + +@test "runc run [timens offsets with no timens]" { + requires timens + + update_config '.process.args = ["cat", "/proc/self/timens_offsets"]' + update_config '.linux.namespaces = .linux.namespace | map(select(.type != "time"))' + update_config '.linux.timeOffsets = { + "monotonic": { "secs": 7881, "nanosecs": 2718281 }, + "boottime": { "secs": 1337, "nanosecs": 3141519 } + }' + + runc run test_busybox + [ "$status" -ne 0 ] +} + +@test "runc run [timens with no offsets]" { + requires timens + + update_config '.process.args = ["cat", "/proc/self/timens_offsets"]' + update_config '.linux.namespaces += [{"type": "time"}] + | .linux.timeOffsets = null' + + runc run test_busybox + [ "$status" -eq 0 ] + # Default offsets are 0. + grep -E '^monotonic\s+0\s+0$' <<<"$output" + grep -E '^boottime\s+0\s+0$' <<<"$output" +} + +@test "runc run [simple timens]" { + requires timens + + update_config '.process.args = ["cat", "/proc/self/timens_offsets"]' + update_config '.linux.namespaces += [{"type": "time"}] + | .linux.timeOffsets = { + "monotonic": { "secs": 7881, "nanosecs": 2718281 }, + "boottime": { "secs": 1337, "nanosecs": 3141519 } + }' + + runc run test_busybox + [ "$status" -eq 0 ] + grep -E '^monotonic\s+7881\s+2718281$' <<<"$output" + grep -E '^boottime\s+1337\s+3141519$' <<<"$output" +}