blob: 6f172b0216b81672058a52fc40c7dfc167eaf655 [file] [log] [blame]
Dylan Reid6b590e62016-10-27 19:10:53 -07001// Copyright 2016 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stephen Barber5f6dc9b2017-04-04 12:36:32 -07005#include "run_oci/container_config_parser.h"
Dylan Reid6b590e62016-10-27 19:10:53 -07006
Luis Hector Chavez8e4dcc12017-06-27 12:54:47 -07007#include <linux/capability.h>
Dylan Reid6b590e62016-10-27 19:10:53 -07008#include <unistd.h>
9
Luis Hector Chavez8e4dcc12017-06-27 12:54:47 -070010#include <map>
Ben Chanf43980b2017-03-10 11:31:46 -080011#include <regex> // NOLINT(build/c++11)
Dylan Reid6b590e62016-10-27 19:10:53 -070012#include <string>
13#include <vector>
14
15#include <base/json/json_reader.h>
16#include <base/values.h>
17
Stephen Barber5f6dc9b2017-04-04 12:36:32 -070018namespace run_oci {
Dylan Reid6b590e62016-10-27 19:10:53 -070019
20namespace {
21
Dylan Reidc0c28502016-11-04 10:51:30 -070022// Gets a uint32 from the given dictionary.
23bool ParseUint32FromDict(const base::DictionaryValue& dict, const char *name,
24 uint32_t* val_out) {
25 double double_val;
26 if (!dict.GetDouble(name, &double_val)) {
Dylan Reidc0c28502016-11-04 10:51:30 -070027 return false;
28 }
29 *val_out = double_val;
30 return true;
31}
32
Dylan Reidb0a72772016-11-03 16:27:50 +000033// Gets a uint64 from the given dictionary.
34bool ParseUint64FromDict(const base::DictionaryValue& dict, const char *name,
35 uint64_t* val_out) {
36 double double_val;
37 if (!dict.GetDouble(name, &double_val)) {
Dylan Reidb0a72772016-11-03 16:27:50 +000038 return false;
39 }
40 *val_out = double_val;
41 return true;
42}
43
Dylan Reid6b590e62016-10-27 19:10:53 -070044// Parses basic platform configuration.
45bool ParsePlatformConfig(const base::DictionaryValue& config_root_dict,
46 OciConfigPtr const& config_out) {
47 // |platform_dict| stays owned by |config_root_dict|
48 const base::DictionaryValue* platform_dict = nullptr;
49 if (!config_root_dict.GetDictionary("platform", &platform_dict)) {
50 LOG(ERROR) << "Fail to parse platform dictionary from config";
51 return false;
52 }
53
54 if (!platform_dict->GetString("os", &config_out->platform.os)) {
55 return false;
56 }
57
58 if (!platform_dict->GetString("arch", &config_out->platform.arch)) {
59 return false;
60 }
61
62 return true;
63}
64
65// Parses root fs info.
66bool ParseRootFileSystemConfig(const base::DictionaryValue& config_root_dict,
67 OciConfigPtr const& config_out) {
68 // |rootfs_dict| stays owned by |config_root_dict|
69 const base::DictionaryValue* rootfs_dict = nullptr;
70 if (!config_root_dict.GetDictionary("root", &rootfs_dict)) {
71 LOG(ERROR) << "Fail to parse rootfs dictionary from config";
72 return false;
73 }
74 if (!rootfs_dict->GetString("path", &config_out->root.path)) {
75 LOG(ERROR) << "Fail to get rootfs path from config";
76 return false;
77 }
Dylan Reid6d650742016-11-02 23:10:38 -070078 rootfs_dict->GetBoolean("readonly", &config_out->root.readonly);
Dylan Reid6b590e62016-10-27 19:10:53 -070079 return true;
80}
81
Luis Hector Chavez8e4dcc12017-06-27 12:54:47 -070082#define CAP_MAP_ENTRY(cap) { "CAP_" #cap, CAP_##cap }
83
84static const std::map<std::string, int> kCapMap = {
85 CAP_MAP_ENTRY(CHOWN),
86 CAP_MAP_ENTRY(DAC_OVERRIDE),
87 CAP_MAP_ENTRY(DAC_READ_SEARCH),
88 CAP_MAP_ENTRY(FOWNER),
89 CAP_MAP_ENTRY(FSETID),
90 CAP_MAP_ENTRY(KILL),
91 CAP_MAP_ENTRY(SETGID),
92 CAP_MAP_ENTRY(SETUID),
93 CAP_MAP_ENTRY(SETPCAP),
94 CAP_MAP_ENTRY(LINUX_IMMUTABLE),
95 CAP_MAP_ENTRY(NET_BIND_SERVICE),
96 CAP_MAP_ENTRY(NET_BROADCAST),
97 CAP_MAP_ENTRY(NET_ADMIN),
98 CAP_MAP_ENTRY(NET_RAW),
99 CAP_MAP_ENTRY(IPC_LOCK),
100 CAP_MAP_ENTRY(IPC_OWNER),
101 CAP_MAP_ENTRY(SYS_MODULE),
102 CAP_MAP_ENTRY(SYS_RAWIO),
103 CAP_MAP_ENTRY(SYS_CHROOT),
104 CAP_MAP_ENTRY(SYS_PTRACE),
105 CAP_MAP_ENTRY(SYS_PACCT),
106 CAP_MAP_ENTRY(SYS_ADMIN),
107 CAP_MAP_ENTRY(SYS_BOOT),
108 CAP_MAP_ENTRY(SYS_NICE),
109 CAP_MAP_ENTRY(SYS_RESOURCE),
110 CAP_MAP_ENTRY(SYS_TIME),
111 CAP_MAP_ENTRY(SYS_TTY_CONFIG),
112 CAP_MAP_ENTRY(MKNOD),
113 CAP_MAP_ENTRY(LEASE),
114 CAP_MAP_ENTRY(AUDIT_WRITE),
115 CAP_MAP_ENTRY(AUDIT_CONTROL),
116 CAP_MAP_ENTRY(SETFCAP),
117 CAP_MAP_ENTRY(MAC_OVERRIDE),
118 CAP_MAP_ENTRY(MAC_ADMIN),
119 CAP_MAP_ENTRY(SYSLOG),
120 CAP_MAP_ENTRY(WAKE_ALARM),
121 CAP_MAP_ENTRY(BLOCK_SUSPEND),
122 CAP_MAP_ENTRY(AUDIT_READ),
123};
124
125// Fills |config_out| with information about the capability sets in the
126// container.
127bool ParseCapabilitiesConfig(const base::DictionaryValue& capabilities_dict,
128 std::map<std::string, CapSet>* config_out) {
129 constexpr const char* kCapabilitySetNames[] = {
130 "effective", "bounding", "inheritable", "permitted", "ambient"};
131 const std::string kAmbientCapabilitySetName = "ambient";
132
133 CapSet caps_superset;
134 for (const char* set_name : kCapabilitySetNames) {
135 // |capset_list| stays owned by |capabilities_dict|.
136 const base::ListValue* capset_list = nullptr;
137 if (!capabilities_dict.GetList(set_name, &capset_list))
138 continue;
139 CapSet caps;
140 for (const auto* cap_name_value : *capset_list) {
141 std::string cap_name;
142 if (!cap_name_value->GetAsString(&cap_name)) {
143 LOG(ERROR) << "Capability list " << set_name
144 << " contains a non-string";
145 return false;
146 }
147 const auto it = kCapMap.find(cap_name);
148 if (it == kCapMap.end()) {
149 LOG(ERROR) << "Unrecognized capability name: " << cap_name;
150 return false;
151 }
152 caps[it->second] = true;
153 }
154 (*config_out)[set_name] = caps;
155 caps_superset = caps;
156 }
157
158 // We currently only support sets that are identical, except that ambient is
159 // optional.
160 for (const char* set_name : kCapabilitySetNames) {
161 auto it = config_out->find(set_name);
162 if (it == config_out->end() && set_name == kAmbientCapabilitySetName) {
163 // Ambient capabilities are optional.
164 continue;
165 }
166 if (it == config_out->end()) {
167 LOG(ERROR)
168 << "If capabilities are set, all capability sets should be present";
169 return false;
170 }
171 if (it->second != caps_superset) {
172 LOG(ERROR)
173 << "If capabilities are set, all capability sets should be identical";
174 return false;
175 }
176 }
177
178 return true;
179}
180
Dylan Reid6b590e62016-10-27 19:10:53 -0700181// Fills |config_out| with information about the main process to run in the
182// container and the user it should be run as.
183bool ParseProcessConfig(const base::DictionaryValue& config_root_dict,
184 OciConfigPtr const& config_out) {
185 // |process_dict| stays owned by |config_root_dict|
186 const base::DictionaryValue* process_dict = nullptr;
187 if (!config_root_dict.GetDictionary("process", &process_dict)) {
188 LOG(ERROR) << "Fail to get main process from config";
189 return false;
190 }
191 process_dict->GetBoolean("terminal", &config_out->process.terminal);
192 // |user_dict| stays owned by |process_dict|
193 const base::DictionaryValue* user_dict = nullptr;
194 if (!process_dict->GetDictionary("user", &user_dict)) {
195 LOG(ERROR) << "Failed to get user info from config";
196 return false;
197 }
Dylan Reidc0c28502016-11-04 10:51:30 -0700198 if (!ParseUint32FromDict(*user_dict, "uid", &config_out->process.user.uid))
Dylan Reid6b590e62016-10-27 19:10:53 -0700199 return false;
Dylan Reidc0c28502016-11-04 10:51:30 -0700200 if (!ParseUint32FromDict(*user_dict, "gid", &config_out->process.user.gid))
Dylan Reid6b590e62016-10-27 19:10:53 -0700201 return false;
Dylan Reid6b590e62016-10-27 19:10:53 -0700202 // |args_list| stays owned by |process_dict|
203 const base::ListValue* args_list = nullptr;
204 if (!process_dict->GetList("args", &args_list)) {
205 LOG(ERROR) << "Fail to get main process args from config";
206 return false;
207 }
208 size_t num_args = args_list->GetSize();
209 for (size_t i = 0; i < num_args; ++i) {
210 std::string arg;
211 if (!args_list->GetString(i, &arg)) {
212 LOG(ERROR) << "Fail to get process args from config";
213 return false;
214 }
215 config_out->process.args.push_back(arg);
216 }
217 // |env_list| stays owned by |process_dict|
218 const base::ListValue* env_list = nullptr;
219 if (process_dict->GetList("env", &env_list)) {
220 size_t num_env = env_list->GetSize();
221 for (size_t i = 0; i < num_env; ++i) {
222 std::string env;
223 if (!env_list->GetString(i, &env)) {
224 LOG(ERROR) << "Fail to get process env from config";
225 return false;
226 }
227 config_out->process.env.push_back(env);
228 }
229 }
230 if (!process_dict->GetString("cwd", &config_out->process.cwd)) {
231 LOG(ERROR) << "failed to get cwd of process";
232 return false;
233 }
Luis Hector Chavez8e4dcc12017-06-27 12:54:47 -0700234 // |capabilities_dict| stays owned by |process_dict|
235 const base::DictionaryValue* capabilities_dict = nullptr;
236 if (process_dict->GetDictionary("capabilities", &capabilities_dict)) {
237 if (!ParseCapabilitiesConfig(*capabilities_dict,
238 &config_out->process.capabilities)) {
239 return false;
240 }
241 }
Dylan Reid6b590e62016-10-27 19:10:53 -0700242
243 return true;
244}
245
246// Parses the 'mounts' field. The necessary mounts for running the container
247// are specified here.
248bool ParseMounts(const base::DictionaryValue& config_root_dict,
249 OciConfigPtr const& config_out) {
250 // |config_mounts_list| stays owned by |config_root_dict|
251 const base::ListValue* config_mounts_list = nullptr;
252 if (!config_root_dict.GetList("mounts", &config_mounts_list)) {
253 LOG(ERROR) << "Fail to get mounts from config dictionary";
254 return false;
255 }
256
257 for (size_t i = 0; i < config_mounts_list->GetSize(); ++i) {
258 const base::DictionaryValue* mount_dict;
259 if (!config_mounts_list->GetDictionary(i, &mount_dict)) {
260 LOG(ERROR) << "Fail to get mount item " << i;
261 return false;
262 }
263 OciMount mount;
264 if (!mount_dict->GetString("destination", &mount.destination)) {
265 LOG(ERROR) << "Fail to get mount path for mount " << i;
266 return false;
267 }
Dylan Reid6d650742016-11-02 23:10:38 -0700268 if (!mount_dict->GetString("type", &mount.type)) {
Dylan Reid6b590e62016-10-27 19:10:53 -0700269 LOG(ERROR) << "Fail to get mount type for mount " << i;
270 return false;
271 }
272 if (!mount_dict->GetString("source", &mount.source)) {
273 LOG(ERROR) << "Fail to get mount source for mount " << i;
274 return false;
275 }
276
277 // |options| are owned by |mount_dict|
278 const base::ListValue* options = nullptr;
279 if (mount_dict->GetList("options", &options)) {
280 for (size_t j = 0; j < options->GetSize(); ++j) {
281 std::string this_opt;
282 if (!options->GetString(j, &this_opt)) {
283 LOG(ERROR) << "Fail to get option " << j << " from mount options";
284 return false;
285 }
286 mount.options.push_back(this_opt);
287 }
288 }
289
290 config_out->mounts.push_back(mount);
291 }
292 return true;
293}
294
Dylan Reid6985e3b2017-03-31 19:39:16 -0700295// Parses the linux resource list
296bool ParseResources(const base::DictionaryValue& resources_dict,
297 OciLinuxResources* resources_out) {
298 // |device_list| is owned by |resources_dict|
299 const base::ListValue* device_list = nullptr;
300 if (!resources_dict.GetList("devices", &device_list)) {
301 // The device list is optional.
302 return true;
303 }
304 size_t num_devices = device_list->GetSize();
305 for (size_t i = 0; i < num_devices; ++i) {
306 OciLinuxCgroupDevice device;
307
308 const base::DictionaryValue* dev;
309 if (!device_list->GetDictionary(i, &dev)) {
310 LOG(ERROR) << "Fail to get device " << i;
311 return false;
312 }
313
314 if (!dev->GetBoolean("allow", &device.allow)) {
315 LOG(ERROR) << "Fail to get allow value for device " << i;
316 return false;
317 }
318 if (!dev->GetString("access", &device.access))
319 device.access = "rwm"; // Optional, default to all perms.
320 if (!dev->GetString("type", &device.type))
321 device.type = "a"; // Optional, default to both a means all.
322 if (!ParseUint32FromDict(*dev, "major", &device.major))
323 device.major = -1; // Optional, -1 will map to all devices.
324 if (!ParseUint32FromDict(*dev, "minor", &device.minor))
325 device.minor = -1; // Optional, -1 will map to all devices.
326
327 resources_out->devices.push_back(device);
328 }
329
330 return true;
331}
332
Dylan Reid6b590e62016-10-27 19:10:53 -0700333// Parse the list of device nodes that the container needs to run.
334bool ParseDeviceList(const base::DictionaryValue& linux_dict,
335 OciConfigPtr const& config_out) {
336 // |device_list| is owned by |linux_dict|
337 const base::ListValue* device_list = nullptr;
338 if (!linux_dict.GetList("devices", &device_list)) {
Dylan Reida5ed1272016-11-11 16:43:39 -0800339 // The device list is optional.
340 return true;
Dylan Reid6b590e62016-10-27 19:10:53 -0700341 }
342 size_t num_devices = device_list->GetSize();
343 for (size_t i = 0; i < num_devices; ++i) {
344 OciLinuxDevice device;
345
346 const base::DictionaryValue* dev;
347 if (!device_list->GetDictionary(i, &dev)) {
348 LOG(ERROR) << "Fail to get device " << i;
349 return false;
350 }
351 std::string path;
352 if (!dev->GetString("path", &device.path)) {
353 LOG(ERROR) << "Fail to get path for dev";
354 return false;
355 }
Dylan Reid6d650742016-11-02 23:10:38 -0700356 if (!dev->GetString("type", &device.type)) {
Dylan Reid6b590e62016-10-27 19:10:53 -0700357 LOG(ERROR) << "Fail to get type for " << device.path;
358 return false;
359 }
Dylan Reidc0c28502016-11-04 10:51:30 -0700360 if (!ParseUint32FromDict(*dev, "major", &device.major))
361 return false;
362 if (!ParseUint32FromDict(*dev, "minor", &device.minor))
363 return false;
364 if (!ParseUint32FromDict(*dev, "fileMode", &device.fileMode))
365 return false;
366 if (!ParseUint32FromDict(*dev, "uid", &device.uid))
367 return false;
368 if (!ParseUint32FromDict(*dev, "gid", &device.gid))
369 return false;
Dylan Reid6b590e62016-10-27 19:10:53 -0700370
371 config_out->linux_config.devices.push_back(device);
372 }
373
374 return true;
375}
376
377// Parses the list of ID mappings and fills |mappings_out| with them.
378bool ParseLinuxIdMappings(const base::ListValue* id_map_list,
Ben Chanf43980b2017-03-10 11:31:46 -0800379 std::vector<OciLinuxNamespaceMapping>* mappings_out) {
Dylan Reid6b590e62016-10-27 19:10:53 -0700380 for (size_t i = 0; i < id_map_list->GetSize(); ++i) {
381 OciLinuxNamespaceMapping new_map;
382 const base::DictionaryValue* map;
383 if (!id_map_list->GetDictionary(i, &map)) {
384 LOG(ERROR) << "Fail to get id map " << i;
385 return false;
386 }
Dylan Reidc0c28502016-11-04 10:51:30 -0700387 if (!ParseUint32FromDict(*map, "hostID", &new_map.hostID))
Dylan Reid6b590e62016-10-27 19:10:53 -0700388 return false;
Dylan Reidc0c28502016-11-04 10:51:30 -0700389 if (!ParseUint32FromDict(*map, "containerID", &new_map.containerID))
Dylan Reid6b590e62016-10-27 19:10:53 -0700390 return false;
Dylan Reidc0c28502016-11-04 10:51:30 -0700391 if (!ParseUint32FromDict(*map, "size", &new_map.size))
Dylan Reid6b590e62016-10-27 19:10:53 -0700392 return false;
Ben Chanf43980b2017-03-10 11:31:46 -0800393 mappings_out->push_back(new_map);
Dylan Reid6b590e62016-10-27 19:10:53 -0700394 }
395 return true;
396}
397
Dylan Reidb0a72772016-11-03 16:27:50 +0000398// Parses seccomp syscall args.
399bool ParseSeccompArgs(const base::DictionaryValue& syscall_dict,
400 OciSeccompSyscall* syscall_out) {
401 const base::ListValue* args = nullptr;
402 if (syscall_dict.GetList("args", &args)) {
403 for (size_t i = 0; i < args->GetSize(); ++i) {
404 const base::DictionaryValue* args_dict = nullptr;
405 if (!args->GetDictionary(i, &args_dict)) {
406 LOG(ERROR) << "Failed to pars args dict for " << syscall_out->name;
407 return false;
408 }
409 OciSeccompArg this_arg;
410 if (!ParseUint32FromDict(*args_dict, "index", &this_arg.index))
411 return false;
412 if (!ParseUint64FromDict(*args_dict, "value", &this_arg.value))
413 return false;
414 if (!ParseUint64FromDict(*args_dict, "value2", &this_arg.value2))
415 return false;
416 if (!args_dict->GetString("op", &this_arg.op)) {
417 LOG(ERROR) << "Failed to parse op for arg " << this_arg.index
418 << " of " << syscall_out->name;
419 return false;
420 }
421 syscall_out->args.push_back(this_arg);
422 }
423 }
424 return true;
425}
426
427// Parses the seccomp node if it is present.
428bool ParseSeccompInfo(const base::DictionaryValue& seccomp_dict,
429 OciSeccomp* seccomp_out) {
430 if (!seccomp_dict.GetString("defaultAction",
431 &seccomp_out->defaultAction))
432 return false;
433
434 // Gets the list of architectures.
435 const base::ListValue* architectures = nullptr;
436 if (!seccomp_dict.GetList("architectures", &architectures)) {
437 LOG(ERROR) << "Fail to read seccomp architectures";
438 return false;
439 }
440 for (size_t i = 0; i < architectures->GetSize(); ++i) {
441 std::string this_arch;
442 if (!architectures->GetString(i, &this_arch)) {
443 LOG(ERROR) << "Fail to parse seccomp architecture list";
444 return false;
445 }
446 seccomp_out->architectures.push_back(this_arch);
447 }
448
449 // Gets the list of syscalls.
450 const base::ListValue* syscalls = nullptr;
451 if (!seccomp_dict.GetList("syscalls", &syscalls)) {
452 LOG(ERROR) << "Fail to read seccomp syscalls";
453 return false;
454 }
455 for (size_t i = 0; i < syscalls->GetSize(); ++i) {
456 const base::DictionaryValue* syscall_dict = nullptr;
457 if (!syscalls->GetDictionary(i, &syscall_dict)) {
458 LOG(ERROR) << "Fail to parse seccomp syscalls list";
459 return false;
460 }
461 OciSeccompSyscall this_syscall;
462 if (!syscall_dict->GetString("name", &this_syscall.name)) {
463 LOG(ERROR) << "Fail to parse syscall name " << i;
464 return false;
465 }
466 if (!syscall_dict->GetString("action", &this_syscall.action)) {
467 LOG(ERROR) << "Fail to parse syscall action for " << this_syscall.name;
468 return false;
469 }
470 if (!ParseSeccompArgs(*syscall_dict, &this_syscall))
471 return false;
472 seccomp_out->syscalls.push_back(this_syscall);
473 }
474
475 return true;
476}
477
Dylan Reid6b590e62016-10-27 19:10:53 -0700478// Parses the linux node which has information about setting up a user
479// namespace, and the list of devices for the container.
480bool ParseLinuxConfigDict(const base::DictionaryValue& runtime_root_dict,
481 OciConfigPtr const& config_out) {
482 // |linux_dict| is owned by |runtime_root_dict|
483 const base::DictionaryValue* linux_dict = nullptr;
484 if (!runtime_root_dict.GetDictionary("linux", &linux_dict)) {
485 LOG(ERROR) << "Fail to get linux dictionary from the runtime dictionary";
486 return false;
487 }
488
489 // |uid_map_list| is owned by |linux_dict|
490 const base::ListValue* uid_map_list = nullptr;
491 if (!linux_dict->GetList("uidMappings", &uid_map_list)) {
492 LOG(ERROR) << "Fail to get uid mappings list";
493 return false;
494 }
Ben Chanf43980b2017-03-10 11:31:46 -0800495 ParseLinuxIdMappings(uid_map_list, &config_out->linux_config.uidMappings);
Dylan Reid6b590e62016-10-27 19:10:53 -0700496
497 // |gid_map_list| is owned by |linux_dict|
498 const base::ListValue* gid_map_list = nullptr;
499 if (!linux_dict->GetList("gidMappings", &gid_map_list)) {
500 LOG(ERROR) << "Fail to get gid mappings list";
501 return false;
502 }
Ben Chanf43980b2017-03-10 11:31:46 -0800503 ParseLinuxIdMappings(gid_map_list, &config_out->linux_config.gidMappings);
Dylan Reid6b590e62016-10-27 19:10:53 -0700504
505 if (!ParseDeviceList(*linux_dict, config_out))
506 return false;
507
Dylan Reid6985e3b2017-03-31 19:39:16 -0700508 const base::DictionaryValue* resources_dict = nullptr;
509 if (linux_dict->GetDictionary("resources", &resources_dict)) {
510 if (!ParseResources(*resources_dict, &config_out->linux_config.resources))
511 return false;
512 }
513
Dylan Reidb0a72772016-11-03 16:27:50 +0000514 const base::DictionaryValue* seccomp_dict = nullptr;
515 if (linux_dict->GetDictionary("seccomp", &seccomp_dict)) {
516 if (!ParseSeccompInfo(*seccomp_dict, &config_out->linux_config.seccomp))
517 return false;
518 }
519
Dylan Reid6b590e62016-10-27 19:10:53 -0700520 return true;
521}
522
Dylan Reid45e34fe2016-12-02 15:11:53 -0800523bool HostnameValid(const std::string& hostname) {
524 if (hostname.length() > 255)
525 return false;
526
527 const std::regex name("^[0-9a-zA-Z]([0-9a-zA-Z-]*[0-9a-zA-Z])?$");
528 if (!std::regex_match(hostname, name))
529 return false;
530
531 const std::regex double_dash("--");
532 if (std::regex_match(hostname, double_dash))
533 return false;
534
535 return true;
536}
537
Dylan Reid6b590e62016-10-27 19:10:53 -0700538// Parses the configuration file for the container. The config file specifies
539// basic filesystem info and details about the process to be run. namespace,
540// cgroup, and syscall configurations are also specified
541bool ParseConfigDict(const base::DictionaryValue& config_root_dict,
542 OciConfigPtr const& config_out) {
Dylan Reid6d650742016-11-02 23:10:38 -0700543 if (!config_root_dict.GetString("ociVersion", &config_out->ociVersion)) {
Dylan Reid6b590e62016-10-27 19:10:53 -0700544 LOG(ERROR) << "Failed to parse ociVersion";
545 return false;
546 }
547 if (!config_root_dict.GetString("hostname", &config_out->hostname)) {
548 LOG(ERROR) << "Failed to parse hostname";
549 return false;
550 }
Dylan Reid45e34fe2016-12-02 15:11:53 -0800551 if (!HostnameValid(config_out->hostname)) {
552 LOG(ERROR) << "Invalid hostname " << config_out->hostname;
553 return false;
554 }
Dylan Reid6b590e62016-10-27 19:10:53 -0700555
556 // Platform info
557 if (!ParsePlatformConfig(config_root_dict, config_out)) {
558 return false;
559 }
560
561 // Root fs info
562 if (!ParseRootFileSystemConfig(config_root_dict, config_out)) {
563 return false;
564 }
565
566 // Process info
567 if (!ParseProcessConfig(config_root_dict, config_out)) {
568 return false;
569 }
570
571 // Get a list of mount points and mounts.
572 if (!ParseMounts(config_root_dict, config_out)) {
573 LOG(ERROR) << "Failed to parse mounts";
574 return false;
575 }
576
577 // Parse linux node.
578 if (!ParseLinuxConfigDict(config_root_dict, config_out)) {
579 LOG(ERROR) << "Failed to parse the linux node";
580 return false;
581 }
582
583 return true;
584}
585
Ben Chanf43980b2017-03-10 11:31:46 -0800586} // anonymous namespace
Dylan Reid6b590e62016-10-27 19:10:53 -0700587
588bool ParseContainerConfig(const std::string& config_json_data,
589 OciConfigPtr const& config_out) {
Luis Hector Chavezd63f1ba2017-06-28 15:58:12 -0700590 std::string error_msg;
Dylan Reid6b590e62016-10-27 19:10:53 -0700591 std::unique_ptr<const base::Value> config_root_val =
Luis Hector Chavezd63f1ba2017-06-28 15:58:12 -0700592 base::JSONReader::ReadAndReturnError(config_json_data,
593 base::JSON_PARSE_RFC,
594 nullptr /* error_code_out */,
595 &error_msg,
596 nullptr /* error_line_out */,
597 nullptr /* error_column_out */);
Dylan Reid6b590e62016-10-27 19:10:53 -0700598 if (!config_root_val) {
Luis Hector Chavezd63f1ba2017-06-28 15:58:12 -0700599 LOG(ERROR) << "Fail to parse config.json: " << error_msg;
Dylan Reid6b590e62016-10-27 19:10:53 -0700600 return false;
601 }
602 const base::DictionaryValue* config_dict = nullptr;
603 if (!config_root_val->GetAsDictionary(&config_dict)) {
604 LOG(ERROR) << "Fail to parse root dictionary from config.json";
605 return false;
606 }
607 if (!ParseConfigDict(*config_dict, config_out)) {
608 return false;
609 }
610
611 return true;
612}
613
Stephen Barber5f6dc9b2017-04-04 12:36:32 -0700614} // namespace run_oci