blob: 26c4c4eece6378532eae2f81900a3290c051d495 [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "run_oci/container_config_parser.h"
#include <stddef.h>
#include <sys/mount.h>
#include <base/at_exit.h>
#include <base/values.h>
#include <gtest/gtest.h>
#include "run_oci/oci_config.h"
namespace {
const char kBasicJsonData[] = R"json(
{
"ociVersion": "1.0.0-rc1",
"platform": {
"os": "linux",
"arch": "amd64"
},
"root": {
"path": "rootfs",
"readonly": true
},
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sh"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
],
"noNewPrivileges": true
},
"hostname": "tester",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
},
{
"destination": "/dev/shm",
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev",
"mode=1777",
"size=65536k"
]
},
{
"destination": "/dev/mqueue",
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
],
"hooks" : {
"prestart": [
{
"path": "/usr/bin/fix-mounts",
"args": ["fix-mounts", "arg1", "arg2"],
"env": [ "key1=value1"]
},
{
"path": "/usr/bin/setup-network"
}
],
"poststart": [
{
"path": "/usr/bin/notify-start",
"timeout": 5
}
],
"poststop": [
{
"path": "/usr/sbin/cleanup.sh",
"args": ["cleanup.sh", "-f"]
}
]
},
"linux": {
"devices": [
{
"path": "/dev/fuse",
"type": "c",
"major": 10,
"minor": 229,
"fileMode": 438,
"uid": 0,
"gid": 3221225472
},
{
"path": "/dev/sda",
"type": "b",
"major": 8,
"minor": 0,
"fileMode": 432,
"uid": 0,
"gid": 0
}
],
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
],
"network": {
"classID": 1048577,
"priorities": [
{
"name": "eth0",
"priority": 500
},
{
"name": "eth1",
"priority": 1000
}
]
}
},
"namespaces": [
{
"type": "pid"
},
{
"type": "network"
},
{
"type": "ipc"
},
{
"type": "uts"
},
{
"type": "mount"
}
],
"uidMappings": [
{
"hostID": 1000,
"containerID": 0,
"size": 10
}
],
"gidMappings": [
{
"hostID": 1000,
"containerID": 0,
"size": 10
}
],
"maskedPaths": [
"/proc/kcore",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug"
],
"readonlyPaths": [
"/proc/asound",
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
],
"seccomp": {
"defaultAction": "SCP_ACT_KILL",
"architectures": [
"SCP_ARCH_X86"
],
"syscalls": [
{
"name": "read",
"action": "SCP_ACT_ALLOW"
},
{
"name": "write",
"action": "SCP_ACT_ALLOW",
"args": [
{
"index": 1,
"value": 255,
"value2": 4,
"op": "SCMP_CMP_EQ"
}
]
}
]
}
}
}
)json";
const char kStrippedJsonData[] = R"json(
{
"ociVersion": "1.0.0-rc1",
"platform": {
"os": "linux",
"arch": "amd64"
},
"root": {
"path": "rootfs",
"readonly": true
},
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sh"
],
"cwd": "/",
"noNewPrivileges": true
},
"hostname": "tester",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
}
],
"linux": {
"uidMappings": [
{
"hostID": 1000,
"containerID": 0,
"size": 10
}
],
"gidMappings": [
{
"hostID": 1000,
"containerID": 0,
"size": 10
}
]
}
}
)json";
const char kInvalidHostnameJsonData[] = R"json(
{
"ociVersion": "1.0.0-rc1",
"platform": {
"os": "linux",
"arch": "amd64"
},
"root": {
"path": "rootfs",
"readonly": true
},
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sh"
],
"cwd": "/",
"noNewPrivileges": true
},
"hostname": "../secrets",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
}
],
"linux": {
"uidMappings": [
{
"hostID": 1000,
"containerID": 0,
"size": 10
}
],
"gidMappings": [
{
"hostID": 1000,
"containerID": 0,
"size": 10
}
]
}
}
)json";
} // anonymous namespace
namespace run_oci {
TEST(OciConfigParserTest, TestBasicConfig) {
OciConfigPtr basic_config(new OciConfig());
ASSERT_TRUE(ParseContainerConfig(kBasicJsonData,
basic_config));
EXPECT_EQ(basic_config->ociVersion, "1.0.0-rc1");
EXPECT_EQ(basic_config->platform.os, "linux");
EXPECT_EQ(basic_config->root.path, "rootfs");
EXPECT_EQ(basic_config->root.readonly, true);
EXPECT_EQ(basic_config->process.terminal, true);
EXPECT_EQ(basic_config->process.user.uid, 0);
EXPECT_EQ(basic_config->process.user.gid, 0);
EXPECT_EQ(basic_config->process.user.additionalGids.size(), 0);
EXPECT_EQ(basic_config->process.args.size(), 1);
EXPECT_EQ(basic_config->process.args[0], "sh");
EXPECT_EQ(basic_config->process.env.size(), 2);
EXPECT_EQ(basic_config->process.env[1], "TERM=xterm");
EXPECT_EQ(basic_config->process.cwd, "/");
EXPECT_EQ(basic_config->hostname, "tester");
ASSERT_EQ(basic_config->mounts.size(), 7);
EXPECT_EQ(basic_config->mounts[0].options.size(), 0);
EXPECT_EQ(basic_config->mounts[1].destination, "/dev");
EXPECT_EQ(basic_config->mounts[2].options.size(), 6);
// Devices
ASSERT_EQ(2, basic_config->linux_config.devices.size());
OciLinuxDevice *dev = &basic_config->linux_config.devices[0];
EXPECT_EQ(dev->type, "c");
EXPECT_EQ(dev->path, "/dev/fuse");
EXPECT_EQ(dev->fileMode, 438);
EXPECT_EQ(dev->uid, 0);
EXPECT_EQ(dev->gid, 3221225472); // INT32_MAX < id < UINT32_MAX
// Namespace Maps
ASSERT_EQ(1, basic_config->linux_config.uidMappings.size());
OciLinuxNamespaceMapping *id_map =
&basic_config->linux_config.uidMappings[0];
EXPECT_EQ(id_map->hostID, 1000);
EXPECT_EQ(id_map->containerID, 0);
EXPECT_EQ(id_map->size, 10);
// seccomp
OciSeccomp *seccomp = &basic_config->linux_config.seccomp;
EXPECT_EQ(seccomp->defaultAction, "SCP_ACT_KILL");
EXPECT_EQ(seccomp->architectures[0], "SCP_ARCH_X86");
EXPECT_EQ(seccomp->syscalls[0].name, "read");
EXPECT_EQ(seccomp->syscalls[0].action, "SCP_ACT_ALLOW");
EXPECT_EQ(seccomp->syscalls[1].name, "write");
EXPECT_EQ(seccomp->syscalls[1].action, "SCP_ACT_ALLOW");
EXPECT_EQ(seccomp->syscalls[1].args[0].index, 1);
EXPECT_EQ(seccomp->syscalls[1].args[0].value, 255);
EXPECT_EQ(seccomp->syscalls[1].args[0].value2, 4);
EXPECT_EQ(seccomp->syscalls[1].args[0].op, "SCMP_CMP_EQ");
}
TEST(OciConfigParserTest, TestStrippedConfig) {
OciConfigPtr stripped_config(new OciConfig());
ASSERT_TRUE(ParseContainerConfig(kStrippedJsonData,
stripped_config));
}
TEST(OciConfigParserTest, TestInvalidHostnameConfig) {
OciConfigPtr invalid_config(new OciConfig());
ASSERT_FALSE(ParseContainerConfig(kInvalidHostnameJsonData,
invalid_config));
}
} // namespace run_oci
int main(int argc, char **argv) {
base::AtExitManager exit_manager;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}