]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile.c
start: check event loop type before closing fd
[mirror_lxc.git] / src / lxc / confile.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "config.h"
4
5 #include <arpa/inet.h>
6 #include <ctype.h>
7 #include <dirent.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <inttypes.h>
11 #include <net/if.h>
12 #include <netinet/in.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/param.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
21 #include <syslog.h>
22 #include <sys/time.h>
23 #include <unistd.h>
24
25 #include "af_unix.h"
26 #include "conf.h"
27 #include "confile.h"
28 #include "confile_utils.h"
29 #include "netns_ifaddrs.h"
30 #include "log.h"
31 #include "lxcseccomp.h"
32 #include "macro.h"
33 #include "memory_utils.h"
34 #include "network.h"
35 #include "parse.h"
36 #include "utils.h"
37
38 #if !HAVE_STRLCPY
39 #include "strlcpy.h"
40 #endif
41
42 #if !HAVE_STRLCAT
43 #include "strlcat.h"
44 #endif
45
46 #if HAVE_SYS_RESOURCE_H
47 #include <sys/resource.h>
48 #endif
49
50 lxc_log_define(confile, lxc);
51
52 #define lxc_config_define(name) \
53 __hot static int set_config_##name(const char *, const char *, \
54 struct lxc_conf *, void *); \
55 __hot static int get_config_##name(const char *, char *, int, \
56 struct lxc_conf *, void *); \
57 __hot static int clr_config_##name(const char *, struct lxc_conf *, \
58 void *);
59
60 lxc_config_define(autodev);
61 lxc_config_define(autodev_tmpfs_size);
62 lxc_config_define(apparmor_allow_incomplete);
63 lxc_config_define(apparmor_allow_nesting);
64 lxc_config_define(apparmor_profile);
65 lxc_config_define(apparmor_raw);
66 lxc_config_define(cap_drop);
67 lxc_config_define(cap_keep);
68 lxc_config_define(cgroup_controller);
69 lxc_config_define(cgroup2_controller);
70 lxc_config_define(cgroup_dir);
71 lxc_config_define(cgroup_monitor_dir);
72 lxc_config_define(cgroup_monitor_pivot_dir);
73 lxc_config_define(cgroup_container_dir);
74 lxc_config_define(cgroup_container_inner_dir);
75 lxc_config_define(cgroup_relative);
76 lxc_config_define(console_buffer_size);
77 lxc_config_define(console_logfile);
78 lxc_config_define(console_path);
79 lxc_config_define(console_rotate);
80 lxc_config_define(console_size);
81 lxc_config_define(unsupported_key);
82 lxc_config_define(environment);
83 lxc_config_define(ephemeral);
84 lxc_config_define(execute_cmd);
85 lxc_config_define(group);
86 lxc_config_define(hooks);
87 lxc_config_define(hooks_version);
88 lxc_config_define(idmaps);
89 lxc_config_define(includefiles);
90 lxc_config_define(init_cmd);
91 lxc_config_define(init_cwd);
92 lxc_config_define(init_gid);
93 lxc_config_define(init_uid);
94 lxc_config_define(init_groups);
95 lxc_config_define(jump_table_net);
96 lxc_config_define(keyring_session);
97 lxc_config_define(log_file);
98 lxc_config_define(log_level);
99 lxc_config_define(log_syslog);
100 lxc_config_define(monitor);
101 lxc_config_define(monitor_signal_pdeath);
102 lxc_config_define(mount);
103 lxc_config_define(mount_auto);
104 lxc_config_define(mount_fstab);
105 lxc_config_define(namespace_clone);
106 lxc_config_define(namespace_keep);
107 lxc_config_define(time_offset_boot);
108 lxc_config_define(time_offset_monotonic);
109 lxc_config_define(namespace_share);
110 lxc_config_define(net);
111 lxc_config_define(net_flags);
112 lxc_config_define(net_hwaddr);
113 lxc_config_define(net_ipv4_address);
114 lxc_config_define(net_ipv4_gateway);
115 lxc_config_define(net_ipv6_address);
116 lxc_config_define(net_ipv6_gateway);
117 lxc_config_define(net_link);
118 lxc_config_define(net_l2proxy);
119 lxc_config_define(net_macvlan_mode);
120 lxc_config_define(net_ipvlan_mode);
121 lxc_config_define(net_ipvlan_isolation);
122 lxc_config_define(net_mtu);
123 lxc_config_define(net_name);
124 lxc_config_define(net_script_down);
125 lxc_config_define(net_script_up);
126 lxc_config_define(net_type);
127 lxc_config_define(net_veth_mode);
128 lxc_config_define(net_veth_n_rxqueues);
129 lxc_config_define(net_veth_n_txqueues);
130 lxc_config_define(net_veth_pair);
131 lxc_config_define(net_veth_ipv4_route);
132 lxc_config_define(net_veth_ipv6_route);
133 lxc_config_define(net_veth_vlan_id);
134 lxc_config_define(net_veth_vlan_tagged_id);
135 lxc_config_define(net_vlan_id);
136 lxc_config_define(no_new_privs);
137 lxc_config_define(personality);
138 lxc_config_define(prlimit);
139 lxc_config_define(pty_max);
140 lxc_config_define(rootfs_managed);
141 lxc_config_define(rootfs_mount);
142 lxc_config_define(rootfs_options);
143 lxc_config_define(rootfs_path);
144 lxc_config_define(seccomp_profile);
145 lxc_config_define(seccomp_allow_nesting);
146 lxc_config_define(seccomp_notify_cookie);
147 lxc_config_define(seccomp_notify_proxy);
148 lxc_config_define(selinux_context);
149 lxc_config_define(selinux_context_keyring);
150 lxc_config_define(signal_halt);
151 lxc_config_define(signal_reboot);
152 lxc_config_define(signal_stop);
153 lxc_config_define(start);
154 lxc_config_define(tty_max);
155 lxc_config_define(tty_dir);
156 lxc_config_define(uts_name);
157 lxc_config_define(sysctl);
158 lxc_config_define(proc);
159 lxc_config_define(sched_core);
160
161 static int set_config_unsupported_key(const char *key, const char *value,
162 struct lxc_conf *lxc_conf, void *data)
163 {
164 return syserror_set(-EINVAL, "Unsupported config key \"%s\"", key);
165 }
166
167 static int get_config_unsupported_key(const char *key, char *retv, int inlen,
168 struct lxc_conf *c, void *data)
169 {
170 return syserror_set(-EINVAL, "Unsupported config key \"%s\"", key);
171 }
172
173 static int clr_config_unsupported_key(const char *key,
174 struct lxc_conf *lxc_conf, void *data)
175 {
176 return syserror_set(-EINVAL, "Unsupported config key \"%s\"", key);
177 }
178
179 /*
180 * Important Note:
181 * If a new config option is added to this table, be aware that
182 * the order in which the options are places into the table matters.
183 * That means that more specific options of a namespace have to be
184 * placed above more generic ones.
185 *
186 * For instance: If lxc.ab is placed before lxc.ab.c, the config option
187 * lxc.ab.c will always be matched to lxc.ab. That is, the lxc.ab.c option
188 * has to be placed above lxc.ab.
189 */
190 static struct lxc_config_t config_jump_table[] = {
191 { "lxc.arch", true, set_config_personality, get_config_personality, clr_config_personality, },
192 { "lxc.apparmor.profile", true, set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
193 { "lxc.apparmor.allow_incomplete", true, set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
194 { "lxc.apparmor.allow_nesting", true, set_config_apparmor_allow_nesting, get_config_apparmor_allow_nesting, clr_config_apparmor_allow_nesting, },
195 { "lxc.apparmor.raw", true, set_config_apparmor_raw, get_config_apparmor_raw, clr_config_apparmor_raw, },
196 { "lxc.autodev.tmpfs.size", true, set_config_autodev_tmpfs_size, get_config_autodev_tmpfs_size, clr_config_autodev_tmpfs_size, },
197 { "lxc.autodev", true, set_config_autodev, get_config_autodev, clr_config_autodev, },
198 { "lxc.cap.drop", true, set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
199 { "lxc.cap.keep", true, set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
200 { "lxc.cgroup2", false, set_config_cgroup2_controller, get_config_cgroup2_controller, clr_config_cgroup2_controller, },
201 { "lxc.cgroup.dir.monitor.pivot", true, set_config_cgroup_monitor_pivot_dir, get_config_cgroup_monitor_pivot_dir, clr_config_cgroup_monitor_pivot_dir, },
202 { "lxc.cgroup.dir.monitor", true, set_config_cgroup_monitor_dir, get_config_cgroup_monitor_dir, clr_config_cgroup_monitor_dir, },
203 { "lxc.cgroup.dir.container.inner", true, set_config_cgroup_container_inner_dir, get_config_cgroup_container_inner_dir, clr_config_cgroup_container_inner_dir, },
204 { "lxc.cgroup.dir.container", true, set_config_cgroup_container_dir, get_config_cgroup_container_dir, clr_config_cgroup_container_dir, },
205 { "lxc.cgroup.dir", true, set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
206 { "lxc.cgroup.relative", true, set_config_cgroup_relative, get_config_cgroup_relative, clr_config_cgroup_relative, },
207 { "lxc.cgroup", false, set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
208 { "lxc.console.buffer.size", true, set_config_console_buffer_size, get_config_console_buffer_size, clr_config_console_buffer_size, },
209 { "lxc.console.logfile", true, set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
210 { "lxc.console.path", true, set_config_console_path, get_config_console_path, clr_config_console_path, },
211 { "lxc.console.rotate", true, set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
212 { "lxc.console.size", true, set_config_console_size, get_config_console_size, clr_config_console_size, },
213 { "lxc.sched.core", true, set_config_sched_core, get_config_sched_core, clr_config_sched_core, },
214 { "lxc.environment", true, set_config_environment, get_config_environment, clr_config_environment, },
215 { "lxc.ephemeral", true, set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
216 { "lxc.execute.cmd", true, set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
217 { "lxc.group", true, set_config_group, get_config_group, clr_config_group, },
218 { "lxc.hook.autodev", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
219 { "lxc.hook.clone", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
220 { "lxc.hook.destroy", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
221 { "lxc.hook.mount", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
222 { "lxc.hook.post-stop", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
223 { "lxc.hook.pre-mount", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
224 { "lxc.hook.pre-start", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
225 { "lxc.hook.start", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
226 { "lxc.hook.start-host", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
227 { "lxc.hook.stop", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
228 { "lxc.hook.version", true, set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, },
229 { "lxc.hook", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
230 { "lxc.idmap", true, set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
231 { "lxc.include", true, set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
232 { "lxc.init.cmd", true, set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
233 { "lxc.init.gid", true, set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
234 { "lxc.init.groups", true, set_config_init_groups, get_config_init_groups, clr_config_init_groups, },
235 { "lxc.init.uid", true, set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
236 { "lxc.init.cwd", true, set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, },
237 { "lxc.keyring.session", true, set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session },
238 { "lxc.log.file", true, set_config_log_file, get_config_log_file, clr_config_log_file, },
239 { "lxc.log.level", true, set_config_log_level, get_config_log_level, clr_config_log_level, },
240 { "lxc.log.syslog", true, set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
241 { "lxc.monitor.unshare", true, set_config_monitor, get_config_monitor, clr_config_monitor, },
242 { "lxc.monitor.signal.pdeath", true, set_config_monitor_signal_pdeath, get_config_monitor_signal_pdeath, clr_config_monitor_signal_pdeath, },
243 { "lxc.mount.auto", true, set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
244 { "lxc.mount.entry", true, set_config_mount, get_config_mount, clr_config_mount, },
245 { "lxc.mount.fstab", true, set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
246 { "lxc.namespace.clone", true, set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
247 { "lxc.namespace.keep", true, set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
248 { "lxc.namespace.share.", false, set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
249 { "lxc.time.offset.boot", true, set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, },
250 { "lxc.time.offset.monotonic", true, set_config_time_offset_monotonic, get_config_time_offset_monotonic, clr_config_time_offset_monotonic, },
251 { "lxc.net.", false, set_config_jump_table_net, get_config_jump_table_net, clr_config_jump_table_net, },
252 { "lxc.net", true, set_config_net, get_config_net, clr_config_net, },
253 { "lxc.no_new_privs", true, set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
254 { "lxc.prlimit", false, set_config_prlimit, get_config_prlimit, clr_config_prlimit, },
255 { "lxc.pty.max", true, set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
256 { "lxc.rootfs.managed", true, set_config_rootfs_managed, get_config_rootfs_managed, clr_config_rootfs_managed, },
257 { "lxc.rootfs.mount", true, set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
258 { "lxc.rootfs.options", true, set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
259 { "lxc.rootfs.path", true, set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
260 { "lxc.seccomp.allow_nesting", true, set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, },
261 { "lxc.seccomp.notify.cookie", true, set_config_seccomp_notify_cookie, get_config_seccomp_notify_cookie, clr_config_seccomp_notify_cookie, },
262 { "lxc.seccomp.notify.proxy", true, set_config_seccomp_notify_proxy, get_config_seccomp_notify_proxy, clr_config_seccomp_notify_proxy, },
263 { "lxc.seccomp.profile", true, set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
264 { "lxc.selinux.context.keyring", true, set_config_selinux_context_keyring, get_config_selinux_context_keyring, clr_config_selinux_context_keyring },
265 { "lxc.selinux.context", true, set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
266 { "lxc.signal.halt", true, set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
267 { "lxc.signal.reboot", true, set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
268 { "lxc.signal.stop", true, set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
269 { "lxc.start.auto", true, set_config_start, get_config_start, clr_config_start, },
270 { "lxc.start.delay", true, set_config_start, get_config_start, clr_config_start, },
271 { "lxc.start.order", true, set_config_start, get_config_start, clr_config_start, },
272 { "lxc.tty.dir", true, set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
273 { "lxc.tty.max", true, set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
274 { "lxc.uts.name", true, set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
275 { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
276 { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, },
277 };
278
279 static struct lxc_config_t unsupported_config_key = {
280 NULL,
281 false,
282 set_config_unsupported_key,
283 get_config_unsupported_key,
284 clr_config_unsupported_key,
285 };
286
287 struct lxc_config_net_t {
288 LXC_CONFIG_MEMBERS;
289 };
290
291 static struct lxc_config_net_t config_jump_table_net[] = {
292 /* If a longer key is added please update. */
293 #define NETWORK_SUBKEY_SIZE_MAX (STRLITERALLEN("veth.vlan.tagged.id") * 2)
294 { "flags", true, set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
295 { "hwaddr", true, set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
296 { "ipv4.address", true, set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
297 { "ipv4.gateway", true, set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
298 { "ipv6.address", true, set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
299 { "ipv6.gateway", true, set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
300 { "link", true, set_config_net_link, get_config_net_link, clr_config_net_link, },
301 { "l2proxy", true, set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
302 { "macvlan.mode", true, set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
303 { "ipvlan.mode", true, set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
304 { "ipvlan.isolation", true, set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
305 { "mtu", true, set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
306 { "name", true, set_config_net_name, get_config_net_name, clr_config_net_name, },
307 { "script.down", true, set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
308 { "script.up", true, set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
309 { "type", true, set_config_net_type, get_config_net_type, clr_config_net_type, },
310 { "vlan.id", true, set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
311 { "veth.mode", true, set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
312 { "veth.n_rxqueues", true, set_config_net_veth_n_rxqueues, get_config_net_veth_n_rxqueues, clr_config_net_veth_n_rxqueues, },
313 { "veth.n_txqueues", true, set_config_net_veth_n_txqueues, get_config_net_veth_n_txqueues, clr_config_net_veth_n_txqueues, },
314 { "veth.pair", true, set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
315 { "veth.ipv4.route", true, set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
316 { "veth.ipv6.route", true, set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
317 { "veth.vlan.id", true, set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
318 { "veth.vlan.tagged.id", true, set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
319 };
320
321 static struct lxc_config_net_t unsupported_config_net_key = {
322 NULL,
323 false,
324 set_config_unsupported_key,
325 get_config_unsupported_key,
326 clr_config_unsupported_key,
327 };
328
329 struct lxc_config_t *lxc_get_config_exact(const char *key)
330 {
331 size_t i;
332
333 for (i = 0; i < ARRAY_SIZE(config_jump_table); i++)
334 if (strequal(config_jump_table[i].name, key))
335 return &config_jump_table[i];
336
337 return NULL;
338 }
339
340 /* Assume a reasonable subkey size limit. */
341 #define LXC_SUBKEY_LEN_MAX 256
342
343 static inline int match_config_item(const struct lxc_config_t *entry, const char *key)
344 {
345 size_t len;
346
347 if (entry->strict)
348 return strequal(entry->name, key);
349
350 /* There should be no subkey longer than this. */
351 len = strnlen(entry->name, LXC_SUBKEY_LEN_MAX);
352 if (len == LXC_SUBKEY_LEN_MAX)
353 return error_ret(-E2BIG, "Excessive subkey length");
354
355 return strnequal(entry->name, key, len);
356 }
357
358 struct lxc_config_t *lxc_get_config(const char *key)
359 {
360 for (size_t i = 0; i < ARRAY_SIZE(config_jump_table); i++) {
361 struct lxc_config_t *cur = &config_jump_table[i];
362
363 switch (match_config_item(cur, key)) {
364 case 0:
365 continue;
366 case -E2BIG:
367 return &unsupported_config_key;
368 }
369
370 return cur;
371 }
372
373 return &unsupported_config_key;
374 }
375
376 static inline bool match_config_net_item(const struct lxc_config_net_t *entry,
377 const char *key)
378 {
379 if (entry->strict)
380 return strequal(entry->name, key);
381 return strnequal(entry->name, key, strlen(entry->name));
382 }
383
384 static struct lxc_config_net_t *lxc_get_config_net(const char *key)
385 {
386 for (size_t i = 0; i < ARRAY_SIZE(config_jump_table_net); i++) {
387 struct lxc_config_net_t *cur = &config_jump_table_net[i];
388
389 if (!match_config_net_item(cur, key))
390 continue;
391
392 return cur;
393 }
394
395 return &unsupported_config_net_key;
396 }
397
398 static int set_config_net(const char *key, const char *value,
399 struct lxc_conf *lxc_conf, void *data)
400 {
401 if (!lxc_config_value_empty(value))
402 return syserror_set(-EINVAL, "lxc.net must not have a value");
403
404 return clr_config_net(key, lxc_conf, data);
405 }
406
407 static int set_config_net_type(const char *key, const char *value,
408 struct lxc_conf *lxc_conf, void *data)
409 {
410 struct lxc_netdev *netdev = data;
411
412 if (!netdev)
413 return ret_errno(EINVAL);
414
415 clr_config_net_type(key, lxc_conf, data);
416 if (lxc_config_value_empty(value))
417 return 0;
418
419 if (strequal(value, "veth")) {
420 netdev->type = LXC_NET_VETH;
421 INIT_LIST_HEAD(&netdev->priv.veth_attr.ipv4_routes);
422 INIT_LIST_HEAD(&netdev->priv.veth_attr.ipv6_routes);
423 lxc_list_init(&netdev->priv.veth_attr.vlan_tagged_ids);
424 if (!lxc_veth_flag_to_mode(netdev->priv.veth_attr.mode))
425 lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge");
426 } else if (strequal(value, "macvlan")) {
427 netdev->type = LXC_NET_MACVLAN;
428 if (!lxc_macvlan_flag_to_mode(netdev->priv.veth_attr.mode))
429 lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
430 } else if (strequal(value, "ipvlan")) {
431 netdev->type = LXC_NET_IPVLAN;
432 if (!lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode))
433 lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, "l3");
434 if (!lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation))
435 lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, "bridge");
436 } else if (strequal(value, "vlan")) {
437 netdev->type = LXC_NET_VLAN;
438 } else if (strequal(value, "phys")) {
439 netdev->type = LXC_NET_PHYS;
440 } else if (strequal(value, "empty")) {
441 netdev->type = LXC_NET_EMPTY;
442 /* We don't support custom loopback device names. */
443 (void)strlcpy(netdev->name, "lo", IFNAMSIZ);
444 } else if (strequal(value, "none")) {
445 netdev->type = LXC_NET_NONE;
446 } else {
447 return log_error(-1, "Invalid network type %s", value);
448 }
449
450 return 0;
451 }
452
453 static int set_config_net_flags(const char *key, const char *value,
454 struct lxc_conf *lxc_conf, void *data)
455 {
456 struct lxc_netdev *netdev = data;
457
458 if (!netdev)
459 return ret_errno(EINVAL);
460
461 if (lxc_config_value_empty(value))
462 return clr_config_net_flags(key, lxc_conf, data);
463
464 netdev->flags |= IFF_UP;
465
466 return 0;
467 }
468
469 static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
470 struct lxc_netdev *netdev)
471 {
472 call_cleaner(netns_freeifaddrs) struct netns_ifaddrs *ifaddr = NULL;
473 struct netns_ifaddrs *ifa;
474 int n;
475 int ret = 0;
476 const char *type_key = "lxc.net.type";
477 const char *link_key = "lxc.net.link";
478 const char *tmpvalue = "phys";
479
480 if (netns_getifaddrs(&ifaddr, -1, &(bool){false}) < 0)
481 return log_error_errno(-1, errno, "Failed to get network interfaces");
482
483 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
484 if (!ifa->ifa_addr)
485 continue;
486
487 if (ifa->ifa_addr->sa_family != AF_PACKET)
488 continue;
489
490 if (strnequal(value, ifa->ifa_name, strlen(value) - 1)) {
491 ret = set_config_net_type(type_key, tmpvalue, lxc_conf,
492 netdev);
493 if (!ret) {
494 ret = set_config_net_link(
495 link_key, ifa->ifa_name, lxc_conf, netdev);
496 if (ret) {
497 ERROR("Failed to create matched ifnames");
498 break;
499 }
500 } else {
501 ERROR("Failed to create matched ifnames");
502 break;
503 }
504 }
505 }
506
507 return ret;
508 }
509
510 static int set_config_net_link(const char *key, const char *value,
511 struct lxc_conf *lxc_conf, void *data)
512 {
513 struct lxc_netdev *netdev = data;
514 int ret = 0;
515
516 if (!netdev)
517 return ret_errno(EINVAL);
518
519 if (lxc_config_value_empty(value))
520 return clr_config_net_link(key, lxc_conf, data);
521
522 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS)
523 ret = create_matched_ifnames(value, lxc_conf, netdev);
524 else
525 ret = network_ifname(netdev->link, value, sizeof(netdev->link));
526
527 return ret;
528 }
529
530 static int set_config_net_l2proxy(const char *key, const char *value,
531 struct lxc_conf *lxc_conf, void *data)
532 {
533 struct lxc_netdev *netdev = data;
534 unsigned int val = 0;
535 int ret;
536
537 if (!netdev)
538 return ret_errno(EINVAL);
539
540 if (lxc_config_value_empty(value))
541 return clr_config_net_l2proxy(key, lxc_conf, data);
542
543 ret = lxc_safe_uint(value, &val);
544 if (ret < 0)
545 return ret_errno(ret);
546
547 switch (val) {
548 case 0:
549 netdev->l2proxy = false;
550 return 0;
551 case 1:
552 netdev->l2proxy = true;
553 return 0;
554 }
555
556 return ret_errno(EINVAL);
557 }
558
559 static int set_config_net_name(const char *key, const char *value,
560 struct lxc_conf *lxc_conf, void *data)
561 {
562 struct lxc_netdev *netdev = data;
563
564 if (!netdev)
565 return ret_errno(EINVAL);
566
567 if (lxc_config_value_empty(value))
568 return clr_config_net_name(key, lxc_conf, data);
569
570 return network_ifname(netdev->name, value, sizeof(netdev->name));
571 }
572
573
574 static int set_config_net_veth_mode(const char *key, const char *value,
575 struct lxc_conf *lxc_conf, void *data)
576 {
577 struct lxc_netdev *netdev = data;
578
579 if (!netdev)
580 return ret_errno(EINVAL);
581
582 if (netdev->type != LXC_NET_VETH)
583 return ret_errno(EINVAL);
584
585 if (lxc_config_value_empty(value))
586 return clr_config_net_veth_mode(key, lxc_conf, data);
587
588 if (!netdev)
589 return ret_errno(EINVAL);
590
591 return lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, value);
592 }
593
594 static int set_config_net_veth_n_rxqueues(const char *key, const char *value,
595 struct lxc_conf *lxc_conf, void *data)
596 {
597 int n_rxqueues;
598 struct lxc_netdev *netdev = data;
599
600 if (!netdev)
601 return ret_errno(EINVAL);
602
603 if (netdev->type != LXC_NET_VETH)
604 return ret_errno(EINVAL);
605
606 if (lxc_config_value_empty(value))
607 return clr_config_net_veth_n_rxqueues(key, lxc_conf, data);
608
609 if (lxc_safe_int(value, &n_rxqueues))
610 return ret_errno(EINVAL);
611
612 if (n_rxqueues <= 0)
613 return ret_errno(EINVAL);
614
615 netdev->priv.veth_attr.n_rxqueues = n_rxqueues;
616 return 0;
617 }
618
619 static int set_config_net_veth_n_txqueues(const char *key, const char *value,
620 struct lxc_conf *lxc_conf, void *data)
621 {
622 int n_txqueues;
623 struct lxc_netdev *netdev = data;
624
625 if (!netdev)
626 return ret_errno(EINVAL);
627
628 if (netdev->type != LXC_NET_VETH)
629 return ret_errno(EINVAL);
630
631 if (lxc_config_value_empty(value))
632 return clr_config_net_veth_n_txqueues(key, lxc_conf, data);
633
634 if (lxc_safe_int(value, &n_txqueues))
635 return ret_errno(EINVAL);
636
637 if (n_txqueues <= 0)
638 return ret_errno(EINVAL);
639
640 netdev->priv.veth_attr.n_txqueues = n_txqueues;
641 return 0;
642 }
643
644 static int set_config_net_veth_pair(const char *key, const char *value,
645 struct lxc_conf *lxc_conf, void *data)
646 {
647 struct lxc_netdev *netdev = data;
648
649 if (!netdev)
650 return ret_errno(EINVAL);
651
652 if (netdev->type != LXC_NET_VETH)
653 return ret_errno(EINVAL);
654
655 if (lxc_config_value_empty(value))
656 return clr_config_net_veth_pair(key, lxc_conf, data);
657
658 return network_ifname(netdev->priv.veth_attr.pair, value,
659 sizeof(netdev->priv.veth_attr.pair));
660 }
661
662 static int set_config_net_veth_vlan_id(const char *key, const char *value,
663 struct lxc_conf *lxc_conf, void *data)
664 {
665 int ret;
666 struct lxc_netdev *netdev = data;
667
668 if (!netdev)
669 return ret_errno(EINVAL);
670
671 if (netdev->type != LXC_NET_VETH)
672 return ret_errno(EINVAL);
673
674 if (lxc_config_value_empty(value))
675 return clr_config_net_veth_vlan_id(key, lxc_conf, data);
676
677 if (strequal(value, "none")) {
678 netdev->priv.veth_attr.vlan_id = BRIDGE_VLAN_NONE;
679 } else {
680 unsigned short vlan_id;
681
682 ret = get_u16(&vlan_id, value, 0);
683 if (ret < 0)
684 return ret_errno(EINVAL);
685
686 if (vlan_id > BRIDGE_VLAN_ID_MAX)
687 return ret_errno(EINVAL);
688
689 netdev->priv.veth_attr.vlan_id = vlan_id;
690 }
691
692 netdev->priv.veth_attr.vlan_id_set = true;
693 return 0;
694 }
695
696 static int set_config_net_veth_vlan_tagged_id(const char *key, const char *value,
697 struct lxc_conf *lxc_conf,
698 void *data)
699 {
700 __do_free struct lxc_list *list = NULL;
701 int ret;
702 unsigned short vlan_id;
703 struct lxc_netdev *netdev = data;
704
705 if (!netdev)
706 return ret_errno(EINVAL);
707
708 if (netdev->type != LXC_NET_VETH)
709 return ret_errno(EINVAL);
710
711 if (lxc_config_value_empty(value))
712 return clr_config_net_veth_vlan_tagged_id(key, lxc_conf, data);
713
714 ret = get_u16(&vlan_id, value, 0);
715 if (ret < 0)
716 return ret_errno(EINVAL);
717
718 if (vlan_id > BRIDGE_VLAN_ID_MAX)
719 return ret_errno(EINVAL);
720
721 list = lxc_list_new();
722 if (!list)
723 return ret_errno(ENOMEM);
724
725 list->elem = UINT_TO_PTR(vlan_id);
726
727 lxc_list_add_tail(&netdev->priv.veth_attr.vlan_tagged_ids, move_ptr(list));
728
729 return 0;
730 }
731
732 static int set_config_net_macvlan_mode(const char *key, const char *value,
733 struct lxc_conf *lxc_conf, void *data)
734 {
735 struct lxc_netdev *netdev = data;
736
737 if (!netdev)
738 return ret_errno(EINVAL);
739
740 if (netdev->type != LXC_NET_MACVLAN)
741 return ret_errno(EINVAL);
742
743 if (lxc_config_value_empty(value))
744 return clr_config_net_macvlan_mode(key, lxc_conf, data);
745
746 return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
747 }
748
749 static int set_config_net_ipvlan_mode(const char *key, const char *value,
750 struct lxc_conf *lxc_conf, void *data)
751 {
752 struct lxc_netdev *netdev = data;
753
754 if (!netdev)
755 return ret_errno(EINVAL);
756
757 if (netdev->type != LXC_NET_IPVLAN)
758 return syserror_set(-EINVAL, "Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value);
759
760 if (lxc_config_value_empty(value))
761 return clr_config_net_ipvlan_mode(key, lxc_conf, data);
762
763 return lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, value);
764 }
765
766 static int set_config_net_ipvlan_isolation(const char *key, const char *value,
767 struct lxc_conf *lxc_conf, void *data)
768 {
769 struct lxc_netdev *netdev = data;
770
771 if (!netdev)
772 return ret_errno(EINVAL);
773
774 if (netdev->type != LXC_NET_IPVLAN)
775 return syserror_set(-EINVAL, "Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value);
776
777 if (lxc_config_value_empty(value))
778 return clr_config_net_ipvlan_isolation(key, lxc_conf, data);
779
780 return lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, value);
781 }
782
783 static int set_config_net_hwaddr(const char *key, const char *value,
784 struct lxc_conf *lxc_conf, void *data)
785 {
786 __do_free char *new_value = NULL;
787 struct lxc_netdev *netdev = data;
788
789 if (!netdev)
790 return ret_errno(EINVAL);
791
792 clr_config_net_hwaddr(key, lxc_conf, data);
793 if (lxc_config_value_empty(value))
794 return 0;
795
796 new_value = strdup(value);
797 if (!new_value)
798 return ret_errno(ENOMEM);
799
800 rand_complete_hwaddr(new_value);
801 if (!lxc_config_value_empty(new_value))
802 netdev->hwaddr = move_ptr(new_value);
803
804 return 0;
805 }
806
807 static int set_config_net_vlan_id(const char *key, const char *value,
808 struct lxc_conf *lxc_conf, void *data)
809 {
810 int ret;
811 struct lxc_netdev *netdev = data;
812
813 if (!netdev)
814 return ret_errno(EINVAL);
815
816 if (netdev->type != LXC_NET_VLAN)
817 return ret_errno(EINVAL);
818
819 if (lxc_config_value_empty(value))
820 return clr_config_net_vlan_id(key, lxc_conf, data);
821
822 ret = get_u16(&netdev->priv.vlan_attr.vid, value, 0);
823 if (ret < 0)
824 return ret;
825
826 return 0;
827 }
828
829 static int set_config_net_mtu(const char *key, const char *value,
830 struct lxc_conf *lxc_conf, void *data)
831 {
832 struct lxc_netdev *netdev = data;
833
834 if (!netdev)
835 return ret_errno(EINVAL);
836
837 clr_config_net_mtu(key, lxc_conf, data);
838 if (lxc_config_value_empty(value))
839 return 0;
840
841 return set_config_string_item(&netdev->mtu, value);
842 }
843
844 static int set_config_net_ipv4_address(const char *key, const char *value,
845 struct lxc_conf *lxc_conf, void *data)
846 {
847 __do_free char *addr = NULL;
848 __do_free struct lxc_inetdev *inetdev = NULL;
849 int ret;
850 struct lxc_netdev *netdev = data;
851 char *cursor, *slash;
852 char *bcast = NULL, *prefix = NULL;
853
854 if (!netdev)
855 return ret_errno(EINVAL);
856
857 if (lxc_config_value_empty(value))
858 return clr_config_net_ipv4_address(key, lxc_conf, data);
859
860 inetdev = zalloc(sizeof(*inetdev));
861 if (!inetdev)
862 return ret_errno(ENOMEM);
863
864 addr = strdup(value);
865 if (!addr)
866 return ret_errno(ENOMEM);
867
868 cursor = strstr(addr, " ");
869 if (cursor) {
870 *cursor = '\0';
871 bcast = cursor + 1;
872 }
873
874 slash = strstr(addr, "/");
875 if (slash) {
876 *slash = '\0';
877 prefix = slash + 1;
878 }
879
880 ret = inet_pton(AF_INET, addr, &inetdev->addr);
881 if (!ret || ret < 0)
882 return log_error_errno(-1, errno, "Invalid ipv4 address \"%s\"", value);
883
884 if (bcast) {
885 ret = inet_pton(AF_INET, bcast, &inetdev->bcast);
886 if (!ret || ret < 0)
887 return log_error_errno(-1, errno, "Invalid ipv4 broadcast address \"%s\"", value);
888
889 }
890
891 /* No prefix specified, determine it from the network class. */
892 ret = 0;
893 if (prefix)
894 ret = lxc_safe_uint(prefix, &inetdev->prefix);
895 else
896 inetdev->prefix = config_ip_prefix(&inetdev->addr);
897 if (ret || inetdev->prefix > 32)
898 return ret_errno(EINVAL);
899
900 /* If no broadcast address, compute one from the prefix and address. */
901 if (!bcast) {
902 unsigned int shift = LAST_BIT_PER_TYPE(inetdev->prefix);
903
904 inetdev->bcast.s_addr = inetdev->addr.s_addr;
905 if (inetdev->prefix < shift)
906 shift = inetdev->prefix;
907 inetdev->bcast.s_addr |= htonl(INADDR_BROADCAST >> shift);
908 }
909
910 list_add_tail(&inetdev->head, &netdev->ipv4_addresses);
911 move_ptr(inetdev);
912
913 return 0;
914 }
915
916 static int set_config_net_ipv4_gateway(const char *key, const char *value,
917 struct lxc_conf *lxc_conf, void *data)
918 {
919 struct lxc_netdev *netdev = data;
920
921 if (!netdev)
922 return ret_errno(EINVAL);
923
924 clr_config_net_ipv4_gateway(key, lxc_conf, data);
925 if (lxc_config_value_empty(value))
926 return 0;
927
928 if (strequal(value, "auto")) {
929 netdev->ipv4_gateway = NULL;
930 netdev->ipv4_gateway_auto = true;
931 } else if (strequal(value, "dev")) {
932 netdev->ipv4_gateway = NULL;
933 netdev->ipv4_gateway_auto = false;
934 netdev->ipv4_gateway_dev = true;
935 } else {
936 __do_free struct in_addr *gw = NULL;
937 int ret;
938
939 gw = zalloc(sizeof(*gw));
940 if (!gw)
941 return ret_errno(ENOMEM);
942
943 ret = inet_pton(AF_INET, value, gw);
944 if (!ret || ret < 0)
945 return log_error_errno(-1, errno, "Invalid ipv4 gateway address \"%s\"", value);
946
947 netdev->ipv4_gateway = move_ptr(gw);
948 netdev->ipv4_gateway_auto = false;
949 }
950
951 return 0;
952 }
953
954 static int set_config_net_veth_ipv4_route(const char *key, const char *value,
955 struct lxc_conf *lxc_conf, void *data)
956 {
957 __do_free char *valdup = NULL;
958 __do_free struct lxc_inetdev *inetdev = NULL;
959 int ret;
960 char *netmask, *slash;
961 struct lxc_netdev *netdev = data;
962
963 if (!netdev)
964 return ret_errno(EINVAL);
965
966 if (netdev->type != LXC_NET_VETH)
967 return syserror_set(-EINVAL, "Invalid ipv4 route \"%s\", can only be used with veth network", value);
968
969 if (lxc_config_value_empty(value))
970 return clr_config_net_veth_ipv4_route(key, lxc_conf, data);
971
972 inetdev = zalloc(sizeof(*inetdev));
973 if (!inetdev)
974 return ret_errno(ENOMEM);
975
976 valdup = strdup(value);
977 if (!valdup)
978 return ret_errno(ENOMEM);
979
980 slash = strchr(valdup, '/');
981 if (!slash)
982 return ret_errno(EINVAL);
983
984 *slash = '\0';
985 slash++;
986 if (*slash == '\0')
987 return ret_errno(EINVAL);
988
989 netmask = slash;
990
991 ret = lxc_safe_uint(netmask, &inetdev->prefix);
992 if (ret < 0 || inetdev->prefix > 32)
993 return ret_errno(EINVAL);
994
995 ret = inet_pton(AF_INET, valdup, &inetdev->addr);
996 if (!ret || ret < 0)
997 return ret_errno(EINVAL);
998
999 list_add_tail(&inetdev->head, &netdev->priv.veth_attr.ipv4_routes);
1000 move_ptr(inetdev);
1001
1002 return 0;
1003 }
1004
1005 static int set_config_net_ipv6_address(const char *key, const char *value,
1006 struct lxc_conf *lxc_conf, void *data)
1007 {
1008 __do_free char *valdup = NULL;
1009 __do_free struct lxc_inet6dev *inet6dev = NULL;
1010 int ret;
1011 struct lxc_netdev *netdev = data;
1012 char *slash, *netmask;
1013
1014 if (!netdev)
1015 return ret_errno(EINVAL);
1016
1017 if (lxc_config_value_empty(value))
1018 return clr_config_net_ipv6_address(key, lxc_conf, data);
1019
1020 inet6dev = zalloc(sizeof(*inet6dev));
1021 if (!inet6dev)
1022 return ret_errno(ENOMEM);
1023
1024 valdup = strdup(value);
1025 if (!valdup)
1026 return ret_errno(ENOMEM);
1027
1028 inet6dev->prefix = 64;
1029 slash = strstr(valdup, "/");
1030 if (slash) {
1031 *slash = '\0';
1032 netmask = slash + 1;
1033
1034 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
1035 if (ret < 0)
1036 return ret;
1037 }
1038
1039 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
1040 if (!ret || ret < 0)
1041 return log_error_errno(-EINVAL, EINVAL, "Invalid ipv6 address \"%s\"", valdup);
1042
1043 list_add_tail(&inet6dev->head, &netdev->ipv6_addresses);
1044 move_ptr(inet6dev);
1045
1046 return 0;
1047 }
1048
1049 static int set_config_net_ipv6_gateway(const char *key, const char *value,
1050 struct lxc_conf *lxc_conf, void *data)
1051 {
1052 struct lxc_netdev *netdev = data;
1053
1054 if (!netdev)
1055 return ret_errno(EINVAL);
1056
1057 clr_config_net_ipv6_gateway(key, lxc_conf, data);
1058 if (lxc_config_value_empty(value))
1059 return 0;
1060
1061 if (strequal(value, "auto")) {
1062 netdev->ipv6_gateway = NULL;
1063 netdev->ipv6_gateway_auto = true;
1064 } else if (strequal(value, "dev")) {
1065 netdev->ipv6_gateway = NULL;
1066 netdev->ipv6_gateway_auto = false;
1067 netdev->ipv6_gateway_dev = true;
1068 } else {
1069 int ret;
1070 __do_free struct in6_addr *gw = NULL;
1071
1072 gw = zalloc(sizeof(*gw));
1073 if (!gw)
1074 return ret_errno(ENOMEM);
1075
1076 ret = inet_pton(AF_INET6, value, gw);
1077 if (!ret || ret < 0)
1078 return log_error_errno(-EINVAL, EINVAL,
1079 "Invalid ipv6 gateway address \"%s\"", value);
1080
1081 netdev->ipv6_gateway = move_ptr(gw);
1082 netdev->ipv6_gateway_auto = false;
1083 }
1084
1085 return 0;
1086 }
1087
1088 static int set_config_net_veth_ipv6_route(const char *key, const char *value,
1089 struct lxc_conf *lxc_conf, void *data)
1090 {
1091 __do_free char *valdup = NULL;
1092 __do_free struct lxc_inet6dev *inet6dev = NULL;
1093 int ret;
1094 char *netmask, *slash;
1095 struct lxc_netdev *netdev = data;
1096
1097 if (!netdev)
1098 return ret_errno(EINVAL);
1099
1100 if (netdev->type != LXC_NET_VETH)
1101 return syserror_set(-EINVAL, "Invalid ipv6 route \"%s\", can only be used with veth network", value);
1102
1103 if (lxc_config_value_empty(value))
1104 return clr_config_net_veth_ipv6_route(key, lxc_conf, data);
1105
1106 inet6dev = zalloc(sizeof(*inet6dev));
1107 if (!inet6dev)
1108 return ret_errno(ENOMEM);
1109
1110 valdup = strdup(value);
1111 if (!valdup)
1112 return ret_errno(ENOMEM);
1113
1114 slash = strchr(valdup, '/');
1115 if (!slash)
1116 return ret_errno(EINVAL);
1117
1118 *slash = '\0';
1119 slash++;
1120 if (*slash == '\0')
1121 return ret_errno(EINVAL);
1122
1123 netmask = slash;
1124
1125 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
1126 if (ret < 0 || inet6dev->prefix > 128)
1127 return ret_errno(EINVAL);
1128
1129 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
1130 if (!ret || ret < 0)
1131 return ret_errno(EINVAL);
1132
1133 list_add_tail(&inet6dev->head, &netdev->priv.veth_attr.ipv6_routes);
1134 move_ptr(inet6dev);
1135
1136 return 0;
1137 }
1138
1139 static int set_config_net_script_up(const char *key, const char *value,
1140 struct lxc_conf *lxc_conf, void *data)
1141 {
1142 struct lxc_netdev *netdev = data;
1143
1144 if (!netdev)
1145 return ret_errno(EINVAL);
1146
1147 clr_config_net_script_up(key, lxc_conf, data);
1148 if (lxc_config_value_empty(value))
1149 return 0;
1150
1151 return set_config_string_item(&netdev->upscript, value);
1152 }
1153
1154 static int set_config_net_script_down(const char *key, const char *value,
1155 struct lxc_conf *lxc_conf, void *data)
1156 {
1157 struct lxc_netdev *netdev = data;
1158
1159 if (!netdev)
1160 return ret_errno(EINVAL);
1161
1162 clr_config_net_script_down(key, lxc_conf, data);
1163 if (lxc_config_value_empty(value))
1164 return 0;
1165
1166 return set_config_string_item(&netdev->downscript, value);
1167 }
1168
1169 static int add_hook(struct lxc_conf *lxc_conf, int which, __owns char *hook)
1170 {
1171 __do_free char *val = hook;
1172 __do_free struct string_entry *entry;
1173
1174 entry = zalloc(sizeof(struct string_entry));
1175 if (!entry)
1176 return ret_errno(ENOMEM);
1177
1178 entry->val = move_ptr(val);
1179 list_add_tail(&entry->head, &lxc_conf->hooks[which]);
1180 move_ptr(entry);
1181
1182 return 0;
1183 }
1184
1185 static int set_config_seccomp_allow_nesting(const char *key, const char *value,
1186 struct lxc_conf *lxc_conf, void *data)
1187 {
1188 #ifdef HAVE_SECCOMP
1189 if (lxc_config_value_empty(value))
1190 return clr_config_seccomp_allow_nesting(key, lxc_conf, NULL);
1191
1192 if (lxc_safe_uint(value, &lxc_conf->seccomp.allow_nesting) < 0)
1193 return -errno;
1194
1195 if (lxc_conf->seccomp.allow_nesting > 1)
1196 return ret_errno(EINVAL);
1197
1198 return 0;
1199 #else
1200 return ret_errno(ENOSYS);
1201 #endif
1202 }
1203
1204 static int set_config_seccomp_notify_cookie(const char *key, const char *value,
1205 struct lxc_conf *lxc_conf, void *data)
1206 {
1207 #ifdef HAVE_SECCOMP_NOTIFY
1208 return set_config_string_item(&lxc_conf->seccomp.notifier.cookie, value);
1209 #else
1210 return ret_errno(ENOSYS);
1211 #endif
1212 }
1213
1214 static int set_config_seccomp_notify_proxy(const char *key, const char *value,
1215 struct lxc_conf *lxc_conf, void *data)
1216 {
1217 #ifdef HAVE_SECCOMP_NOTIFY
1218 const char *offset;
1219
1220 if (lxc_config_value_empty(value))
1221 return clr_config_seccomp_notify_proxy(key, lxc_conf, NULL);
1222
1223 if (!strnequal(value, "unix:", 5))
1224 return ret_errno(EINVAL);
1225
1226 offset = value + 5;
1227 if (lxc_unix_sockaddr(&lxc_conf->seccomp.notifier.proxy_addr, offset) < 0)
1228 return -errno;
1229
1230 return 0;
1231 #else
1232 return ret_errno(ENOSYS);
1233 #endif
1234 }
1235
1236 static int set_config_seccomp_profile(const char *key, const char *value,
1237 struct lxc_conf *lxc_conf, void *data)
1238 {
1239 #ifdef HAVE_SECCOMP
1240 return set_config_path_item(&lxc_conf->seccomp.seccomp, value);
1241 #else
1242 return ret_errno(ENOSYS);
1243 #endif
1244 }
1245
1246 static int set_config_execute_cmd(const char *key, const char *value,
1247 struct lxc_conf *lxc_conf, void *data)
1248 {
1249 return set_config_path_item(&lxc_conf->execute_cmd, value);
1250 }
1251
1252 static int set_config_init_cmd(const char *key, const char *value,
1253 struct lxc_conf *lxc_conf, void *data)
1254 {
1255 return set_config_path_item(&lxc_conf->init_cmd, value);
1256 }
1257
1258 static int set_config_init_cwd(const char *key, const char *value,
1259 struct lxc_conf *lxc_conf, void *data)
1260 {
1261 return set_config_path_item(&lxc_conf->init_cwd, value);
1262 }
1263
1264 static int set_config_init_uid(const char *key, const char *value,
1265 struct lxc_conf *lxc_conf, void *data)
1266 {
1267 unsigned int init_uid;
1268
1269 if (lxc_config_value_empty(value)) {
1270 lxc_conf->init_uid = 0;
1271 return 0;
1272 }
1273
1274 if (lxc_safe_uint(value, &init_uid) < 0)
1275 return -errno;
1276
1277 lxc_conf->init_uid = init_uid;
1278
1279 return 0;
1280 }
1281
1282 static int set_config_init_gid(const char *key, const char *value,
1283 struct lxc_conf *lxc_conf, void *data)
1284 {
1285 unsigned int init_gid;
1286
1287 if (lxc_config_value_empty(value)) {
1288 lxc_conf->init_gid = 0;
1289 return 0;
1290 }
1291
1292 if (lxc_safe_uint(value, &init_gid) < 0)
1293 return -errno;
1294
1295 lxc_conf->init_gid = init_gid;
1296
1297 return 0;
1298 }
1299
1300 static int set_config_init_groups(const char *key, const char *value,
1301 struct lxc_conf *lxc_conf, void *data)
1302 {
1303 __do_free char *value_dup = NULL;
1304 gid_t *init_groups = NULL;
1305 size_t num_groups = 0;
1306 size_t idx;
1307 char *token;
1308
1309 if (lxc_config_value_empty(value))
1310 return clr_config_init_groups(key, lxc_conf, NULL);
1311
1312 value_dup = strdup(value);
1313 if (!value_dup)
1314 return -ENOMEM;
1315
1316 lxc_iterate_parts(token, value_dup, ",")
1317 num_groups++;
1318
1319 if (num_groups == INT_MAX)
1320 return log_error_errno(-ERANGE, ERANGE, "Excessive number of supplementary groups specified");
1321
1322 /* This means the string wasn't empty and all we found was garbage. */
1323 if (num_groups == 0)
1324 return log_error_errno(-EINVAL, EINVAL, "No valid groups specified %s", value);
1325
1326 idx = lxc_conf->init_groups.size;
1327 init_groups = realloc(lxc_conf->init_groups.list, sizeof(gid_t) * (idx + num_groups));
1328 if (!init_groups)
1329 return ret_errno(ENOMEM);
1330
1331 /*
1332 * Once the realloc() succeeded we need to hand control of the memory
1333 * back to the config otherwise we risk a double-free when
1334 * lxc_conf_free() is called.
1335 */
1336 lxc_conf->init_groups.list = init_groups;
1337
1338 /* Restore duplicated value so we can call lxc_iterate_parts() again. */
1339 strcpy(value_dup, value);
1340
1341 lxc_iterate_parts(token, value_dup, ",") {
1342 int ret;
1343
1344 gid_t group;
1345
1346 ret = lxc_safe_uint(token, &group);
1347 if (ret)
1348 return log_error_errno(ret, -ret, "Failed to parse group %s", token);
1349
1350 init_groups[idx++] = group;
1351 }
1352
1353 lxc_conf->init_groups.size += num_groups;
1354
1355 return 0;
1356 }
1357
1358 static int set_config_hooks(const char *key, const char *value,
1359 struct lxc_conf *lxc_conf, void *data)
1360 {
1361 __do_free char *copy = NULL;
1362
1363 if (lxc_config_value_empty(value))
1364 return lxc_clear_hooks(lxc_conf, key);
1365
1366 if (strequal(key + 4, "hook"))
1367 return log_error_errno(-EINVAL, EINVAL, "lxc.hook must not have a value");
1368
1369 copy = strdup(value);
1370 if (!copy)
1371 return ret_errno(ENOMEM);
1372
1373 if (strequal(key + 9, "pre-start"))
1374 return add_hook(lxc_conf, LXCHOOK_PRESTART, move_ptr(copy));
1375 else if (strequal(key + 9, "start-host"))
1376 return add_hook(lxc_conf, LXCHOOK_START_HOST, move_ptr(copy));
1377 else if (strequal(key + 9, "pre-mount"))
1378 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, move_ptr(copy));
1379 else if (strequal(key + 9, "autodev"))
1380 return add_hook(lxc_conf, LXCHOOK_AUTODEV, move_ptr(copy));
1381 else if (strequal(key + 9, "mount"))
1382 return add_hook(lxc_conf, LXCHOOK_MOUNT, move_ptr(copy));
1383 else if (strequal(key + 9, "start"))
1384 return add_hook(lxc_conf, LXCHOOK_START, move_ptr(copy));
1385 else if (strequal(key + 9, "stop"))
1386 return add_hook(lxc_conf, LXCHOOK_STOP, move_ptr(copy));
1387 else if (strequal(key + 9, "post-stop"))
1388 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, move_ptr(copy));
1389 else if (strequal(key + 9, "clone"))
1390 return add_hook(lxc_conf, LXCHOOK_CLONE, move_ptr(copy));
1391 else if (strequal(key + 9, "destroy"))
1392 return add_hook(lxc_conf, LXCHOOK_DESTROY, move_ptr(copy));
1393
1394 return ret_errno(EINVAL);
1395 }
1396
1397 static int set_config_hooks_version(const char *key, const char *value,
1398 struct lxc_conf *lxc_conf, void *data)
1399 {
1400 int ret;
1401 unsigned int tmp;
1402
1403 if (lxc_config_value_empty(value))
1404 return clr_config_hooks_version(key, lxc_conf, NULL);
1405
1406 ret = lxc_safe_uint(value, &tmp);
1407 if (ret < 0)
1408 return -errno;
1409
1410 if (tmp > 1)
1411 return syserror_set(-EINVAL, "Invalid hook version specified. Currently only 0 (legacy) and 1 are supported");
1412
1413 lxc_conf->hooks_version = tmp;
1414
1415 return 0;
1416 }
1417
1418 static int set_config_personality(const char *key, const char *value,
1419 struct lxc_conf *lxc_conf, void *data)
1420 {
1421 int ret;
1422 personality_t personality;
1423
1424 ret = lxc_config_parse_arch(value, &personality);
1425 if (ret < 0)
1426 return syserror("Unsupported personality \"%s\"", value);
1427
1428 lxc_conf->personality = personality;
1429 return 0;
1430 }
1431
1432 static int set_config_pty_max(const char *key, const char *value,
1433 struct lxc_conf *lxc_conf, void *data)
1434 {
1435 int ret;
1436 unsigned int max = 0;
1437
1438 if (lxc_config_value_empty(value)) {
1439 lxc_conf->pty_max = 0;
1440 return 0;
1441 }
1442
1443 ret = lxc_safe_uint(value, &max);
1444 if (ret < 0)
1445 return ret_errno(EINVAL);
1446
1447 lxc_conf->pty_max = max;
1448
1449 return 0;
1450 }
1451
1452 /* We only need to check whether the first byte of the key after the lxc.start.
1453 * prefix matches our expectations since they fortunately all start with a
1454 * different letter. If anything was wrong with the key we would have already
1455 * noticed when the callback was called.
1456 */
1457 static int set_config_start(const char *key, const char *value,
1458 struct lxc_conf *lxc_conf, void *data)
1459 {
1460 int ret;
1461 bool is_empty;
1462
1463 is_empty = lxc_config_value_empty(value);
1464
1465 if (*(key + 10) == 'a') { /* lxc.start.auto */
1466 if (is_empty) {
1467 lxc_conf->start_auto = 0;
1468 return 0;
1469 }
1470
1471 ret = lxc_safe_uint(value, &lxc_conf->start_auto);
1472 if (ret)
1473 return ret;
1474
1475 if (lxc_conf->start_auto > 1)
1476 return ret_errno(EINVAL);
1477
1478 return 0;
1479 } else if (*(key + 10) == 'd') { /* lxc.start.delay */
1480 if (is_empty) {
1481 lxc_conf->start_delay = 0;
1482 return 0;
1483 }
1484
1485 return lxc_safe_uint(value, &lxc_conf->start_delay);
1486 } else if (*(key + 10) == 'o') { /* lxc.start.order */
1487 if (is_empty) {
1488 lxc_conf->start_order = 0;
1489 return 0;
1490 }
1491
1492 return lxc_safe_int(value, &lxc_conf->start_order);
1493 }
1494
1495 return ret_errno(EINVAL);
1496 }
1497
1498 static int set_config_monitor(const char *key, const char *value,
1499 struct lxc_conf *lxc_conf, void *data)
1500 {
1501 if (lxc_config_value_empty(value)) {
1502 lxc_conf->monitor_unshare = 0;
1503 return 0;
1504 }
1505
1506 if (strequal(key + 12, "unshare"))
1507 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1508
1509 return ret_errno(EINVAL);
1510 }
1511
1512 static int set_config_monitor_signal_pdeath(const char *key, const char *value,
1513 struct lxc_conf *lxc_conf, void *data)
1514 {
1515 if (lxc_config_value_empty(value)) {
1516 lxc_conf->monitor_signal_pdeath = 0;
1517 return 0;
1518 }
1519
1520 if (strequal(key + 12, "signal.pdeath")) {
1521 int sig_n;
1522
1523 sig_n = sig_parse(value);
1524 if (sig_n < 0)
1525 return ret_errno(EINVAL);
1526
1527 lxc_conf->monitor_signal_pdeath = sig_n;
1528 return 0;
1529 }
1530
1531 return ret_errno(EINVAL);
1532 }
1533
1534 static int set_config_group(const char *key, const char *value,
1535 struct lxc_conf *lxc_conf, void *data)
1536 {
1537 __do_free char *groups = NULL;
1538 char *token;
1539
1540 if (lxc_config_value_empty(value))
1541 return lxc_clear_groups(lxc_conf);
1542
1543 groups = strdup(value);
1544 if (!groups)
1545 return ret_errno(ENOMEM);
1546
1547 /*
1548 * In case several groups are specified in a single line split these
1549 * groups in a single element for the list.
1550 */
1551 lxc_iterate_parts(token, groups, " \t") {
1552 __do_free char *val = NULL;
1553 __do_free struct string_entry *entry = NULL;
1554
1555 entry = zalloc(sizeof(struct string_entry));
1556 if (!entry)
1557 return ret_errno(ENOMEM);
1558
1559 val = strdup(token);
1560 if (!val)
1561 return ret_errno(ENOMEM);
1562
1563 entry->val = move_ptr(val);
1564 list_add_tail(&entry->head, &lxc_conf->groups);
1565 move_ptr(entry);
1566 }
1567
1568 return 0;
1569 }
1570
1571 static int set_config_environment(const char *key, const char *value,
1572 struct lxc_conf *lxc_conf, void *data)
1573 {
1574 __do_free char *dup = NULL, *val = NULL;
1575 __do_free struct environment_entry *new_env = NULL;
1576 char *env_val;
1577
1578 if (lxc_config_value_empty(value))
1579 return lxc_clear_environment(lxc_conf);
1580
1581 new_env = zalloc(sizeof(struct environment_entry));
1582 if (!new_env)
1583 return ret_errno(ENOMEM);
1584
1585 dup = strdup(value);
1586 if (!dup)
1587 return ret_errno(ENOMEM);
1588
1589 env_val = strchr(dup, '=');
1590 if (!env_val) {
1591 env_val = getenv(dup);
1592 } else {
1593 *env_val = '\0';
1594 env_val++;
1595 }
1596 if (!env_val)
1597 return ret_errno(ENOENT);
1598
1599 val = strdup(env_val);
1600 if (!val)
1601 return ret_errno(ENOMEM);
1602
1603 new_env->key = move_ptr(dup);
1604 new_env->val = move_ptr(val);
1605
1606 list_add_tail(&new_env->head, &lxc_conf->environment);
1607 move_ptr(new_env);
1608
1609 return 0;
1610 }
1611
1612 static int set_config_tty_max(const char *key, const char *value,
1613 struct lxc_conf *lxc_conf, void *data)
1614 {
1615 int ret;
1616 unsigned int nbtty = 0;
1617
1618 if (lxc_config_value_empty(value)) {
1619 lxc_conf->ttys.max = 0;
1620 return 0;
1621 }
1622
1623 ret = lxc_safe_uint(value, &nbtty);
1624 if (ret < 0)
1625 return ret;
1626
1627 lxc_conf->ttys.max = nbtty;
1628
1629 return 0;
1630 }
1631
1632 static int set_config_tty_dir(const char *key, const char *value,
1633 struct lxc_conf *lxc_conf, void *data)
1634 {
1635 return set_config_string_item_max(&lxc_conf->ttys.dir, value,
1636 NAME_MAX + 1);
1637 }
1638
1639 static int set_config_apparmor_profile(const char *key, const char *value,
1640 struct lxc_conf *lxc_conf, void *data)
1641 {
1642 #if HAVE_APPARMOR
1643 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
1644 #else
1645 return syserror_set(-EINVAL, "Built without AppArmor support");
1646 #endif
1647 }
1648
1649 static int set_config_apparmor_allow_incomplete(const char *key,
1650 const char *value,
1651 struct lxc_conf *lxc_conf,
1652 void *data)
1653 {
1654 #if HAVE_APPARMOR
1655 int ret;
1656
1657 if (lxc_config_value_empty(value)) {
1658 lxc_conf->lsm_aa_allow_incomplete = 0;
1659 return 0;
1660 }
1661
1662 ret = lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete);
1663 if (ret)
1664 return ret;
1665
1666 if (lxc_conf->lsm_aa_allow_incomplete > 1)
1667 return ret_errno(EINVAL);
1668
1669 return 0;
1670 #else
1671 return syserror_set(-EINVAL, "Built without AppArmor support");
1672 #endif
1673 }
1674
1675 static int set_config_apparmor_allow_nesting(const char *key,
1676 const char *value,
1677 struct lxc_conf *lxc_conf,
1678 void *data)
1679 {
1680 #if HAVE_APPARMOR
1681 int ret;
1682
1683 if (lxc_config_value_empty(value))
1684 return clr_config_apparmor_allow_nesting(key, lxc_conf, NULL);
1685
1686 ret = lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_nesting);
1687 if (ret)
1688 return ret;
1689
1690 if (lxc_conf->lsm_aa_allow_nesting > 1)
1691 return ret_errno(EINVAL);
1692
1693 return 0;
1694 #else
1695 return syserror_set(-EINVAL, "Built without AppArmor support");
1696 #endif
1697 }
1698
1699 static int set_config_apparmor_raw(const char *key,
1700 const char *value,
1701 struct lxc_conf *lxc_conf,
1702 void *data)
1703 {
1704 #if HAVE_APPARMOR
1705 __do_free char *elem = NULL;
1706 __do_free struct string_entry *entry = NULL;
1707
1708 if (lxc_config_value_empty(value))
1709 return lxc_clear_apparmor_raw(lxc_conf);
1710
1711 entry = zalloc(sizeof(struct string_entry));
1712 if (!entry)
1713 return ret_errno(ENOMEM);
1714
1715 elem = strdup(value);
1716 if (!elem)
1717 return ret_errno(ENOMEM);
1718
1719 entry->val = move_ptr(elem);
1720 list_add_tail(&entry->head, &lxc_conf->lsm_aa_raw);
1721 move_ptr(entry);
1722
1723 return 0;
1724 #else
1725 return syserror_set(-EINVAL, "Built without AppArmor support");
1726 #endif
1727 }
1728
1729 static int set_config_selinux_context(const char *key, const char *value,
1730 struct lxc_conf *lxc_conf, void *data)
1731 {
1732 #if HAVE_SELINUX
1733 return set_config_string_item(&lxc_conf->lsm_se_context, value);
1734 #else
1735 return syserror_set(-EINVAL, "Built without SELinux support");
1736 #endif
1737 }
1738
1739 static int set_config_selinux_context_keyring(const char *key, const char *value,
1740 struct lxc_conf *lxc_conf, void *data)
1741 {
1742 #if HAVE_SELINUX
1743 return set_config_string_item(&lxc_conf->lsm_se_keyring_context, value);
1744 #else
1745 return syserror_set(-EINVAL, "Built without SELinux support");
1746 #endif
1747 }
1748
1749 static int set_config_keyring_session(const char *key, const char *value,
1750 struct lxc_conf *lxc_conf, void *data)
1751 {
1752 return set_config_bool_item(&lxc_conf->keyring_disable_session, value, false);
1753 }
1754
1755 static int set_config_log_file(const char *key, const char *value,
1756 struct lxc_conf *c, void *data)
1757 {
1758 int ret;
1759
1760 if (lxc_config_value_empty(value)) {
1761 free_disarm(c->logfile);
1762 return 0;
1763 }
1764
1765 /*
1766 * Store these values in the lxc_conf, and then try to set for actual
1767 * current logging.
1768 */
1769 ret = set_config_path_item(&c->logfile, value);
1770 if (ret == 0)
1771 ret = lxc_log_set_file(&c->logfd, c->logfile);
1772
1773 return ret;
1774 }
1775
1776 static int set_config_log_level(const char *key, const char *value,
1777 struct lxc_conf *lxc_conf, void *data)
1778 {
1779 int newlevel;
1780
1781 if (lxc_config_value_empty(value)) {
1782 lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
1783 return 0;
1784 }
1785
1786 if (value[0] >= '0' && value[0] <= '9') {
1787 int ret;
1788
1789 ret = lxc_safe_int(value, &newlevel);
1790 if (ret)
1791 return ret_errno(EINVAL);
1792 } else {
1793 newlevel = lxc_log_priority_to_int(value);
1794 }
1795
1796 /*
1797 * Store these values in the lxc_conf, and then try to set for actual
1798 * current logging.
1799 */
1800 lxc_conf->loglevel = newlevel;
1801
1802 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
1803 }
1804
1805 static int set_config_autodev(const char *key, const char *value,
1806 struct lxc_conf *lxc_conf, void *data)
1807 {
1808 int ret;
1809
1810 if (lxc_config_value_empty(value)) {
1811 lxc_conf->autodev = 0;
1812 return 0;
1813 }
1814
1815 ret = lxc_safe_uint(value, &lxc_conf->autodev);
1816 if (ret)
1817 return ret_errno(EINVAL);
1818
1819 if (lxc_conf->autodev > 1)
1820 return ret_errno(EINVAL);
1821
1822 return 0;
1823 }
1824
1825 static int set_config_autodev_tmpfs_size(const char *key, const char *value,
1826 struct lxc_conf *lxc_conf, void *data)
1827 {
1828 if (lxc_config_value_empty(value)) {
1829 lxc_conf->autodevtmpfssize = 500000;
1830 return 0;
1831 }
1832
1833 if (lxc_safe_int(value, &lxc_conf->autodevtmpfssize) < 0)
1834 lxc_conf->autodevtmpfssize = 500000;
1835
1836 return 0;
1837 }
1838
1839 static int set_config_signal_halt(const char *key, const char *value,
1840 struct lxc_conf *lxc_conf, void *data)
1841 {
1842 int sig_n;
1843
1844 if (lxc_config_value_empty(value)) {
1845 lxc_conf->haltsignal = 0;
1846 return 0;
1847 }
1848
1849 sig_n = sig_parse(value);
1850 if (sig_n < 0)
1851 return ret_errno(EINVAL);
1852
1853 lxc_conf->haltsignal = sig_n;
1854
1855 return 0;
1856 }
1857
1858 static int set_config_signal_reboot(const char *key, const char *value,
1859 struct lxc_conf *lxc_conf, void *data)
1860 {
1861 int sig_n;
1862
1863 if (lxc_config_value_empty(value)) {
1864 lxc_conf->rebootsignal = 0;
1865 return 0;
1866 }
1867
1868 sig_n = sig_parse(value);
1869 if (sig_n < 0)
1870 return ret_errno(EINVAL);
1871
1872 lxc_conf->rebootsignal = sig_n;
1873
1874 return 0;
1875 }
1876
1877 static int set_config_signal_stop(const char *key, const char *value,
1878 struct lxc_conf *lxc_conf, void *data)
1879 {
1880 int sig_n;
1881
1882 if (lxc_config_value_empty(value)) {
1883 lxc_conf->stopsignal = 0;
1884 return 0;
1885 }
1886
1887 sig_n = sig_parse(value);
1888 if (sig_n < 0)
1889 return ret_errno(EINVAL);
1890
1891 lxc_conf->stopsignal = sig_n;
1892
1893 return 0;
1894 }
1895
1896 static int __set_config_cgroup_controller(const char *key, const char *value,
1897 struct lxc_conf *lxc_conf, int version)
1898 {
1899 call_cleaner(free_lxc_cgroup) struct lxc_cgroup *new_cgroup = NULL;
1900 const char *subkey, *token;
1901 size_t token_len;
1902
1903 if (lxc_config_value_empty(value))
1904 return lxc_clear_cgroups(lxc_conf, key, version);
1905
1906 if (version == CGROUP2_SUPER_MAGIC) {
1907 token = "lxc.cgroup2.";
1908 token_len = 12;
1909 } else if (version == CGROUP_SUPER_MAGIC) {
1910 token = "lxc.cgroup.";
1911 token_len = 11;
1912 } else {
1913 return ret_errno(EINVAL);
1914 }
1915
1916 if (!strnequal(key, token, token_len))
1917 return ret_errno(EINVAL);
1918
1919 subkey = key + token_len;
1920 if (*subkey == '\0')
1921 return ret_errno(EINVAL);
1922
1923 new_cgroup = zalloc(sizeof(*new_cgroup));
1924 if (!new_cgroup)
1925 return ret_errno(ENOMEM);
1926
1927 new_cgroup->subsystem = strdup(subkey);
1928 if (!new_cgroup->subsystem)
1929 return ret_errno(ENOMEM);
1930
1931 new_cgroup->value = strdup(value);
1932 if (!new_cgroup->value)
1933 return ret_errno(ENOMEM);
1934
1935 new_cgroup->version = version;
1936
1937 if (version == CGROUP2_SUPER_MAGIC)
1938 list_add_tail(&new_cgroup->head, &lxc_conf->cgroup2);
1939 else
1940 list_add_tail(&new_cgroup->head, &lxc_conf->cgroup);
1941 move_ptr(new_cgroup);
1942
1943 return 0;
1944 }
1945
1946 static int set_config_cgroup_controller(const char *key, const char *value,
1947 struct lxc_conf *lxc_conf, void *data)
1948 {
1949 return __set_config_cgroup_controller(key, value, lxc_conf,
1950 CGROUP_SUPER_MAGIC);
1951 }
1952
1953 static int set_config_cgroup2_controller(const char *key, const char *value,
1954 struct lxc_conf *lxc_conf, void *data)
1955 {
1956 return __set_config_cgroup_controller(key, value, lxc_conf,
1957 CGROUP2_SUPER_MAGIC);
1958 }
1959
1960 static int set_config_cgroup_dir(const char *key, const char *value,
1961 struct lxc_conf *lxc_conf, void *data)
1962 {
1963 if (!strequal(key, "lxc.cgroup.dir"))
1964 return ret_errno(EINVAL);
1965
1966 if (lxc_config_value_empty(value))
1967 return clr_config_cgroup_dir(key, lxc_conf, NULL);
1968
1969 if (abspath(value))
1970 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
1971
1972 if (dotdot(value))
1973 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
1974
1975 return set_config_path_item(&lxc_conf->cgroup_meta.dir, value);
1976 }
1977
1978 static int set_config_cgroup_monitor_dir(const char *key, const char *value,
1979 struct lxc_conf *lxc_conf, void *data)
1980 {
1981 if (lxc_config_value_empty(value))
1982 return clr_config_cgroup_monitor_dir(key, lxc_conf, NULL);
1983
1984 if (abspath(value))
1985 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
1986
1987 if (dotdot(value))
1988 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
1989
1990 return set_config_path_item(&lxc_conf->cgroup_meta.monitor_dir, value);
1991 }
1992
1993 static int set_config_cgroup_monitor_pivot_dir(const char *key, const char *value,
1994 struct lxc_conf *lxc_conf, void *data)
1995 {
1996 if (lxc_config_value_empty(value))
1997 return clr_config_cgroup_monitor_pivot_dir(key, lxc_conf, NULL);
1998
1999 if (abspath(value))
2000 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
2001
2002 if (dotdot(value))
2003 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
2004
2005 return set_config_path_item(&lxc_conf->cgroup_meta.monitor_pivot_dir, value);
2006 }
2007
2008 static int set_config_cgroup_container_dir(const char *key, const char *value,
2009 struct lxc_conf *lxc_conf,
2010 void *data)
2011 {
2012 if (lxc_config_value_empty(value))
2013 return clr_config_cgroup_container_dir(key, lxc_conf, NULL);
2014
2015 if (abspath(value))
2016 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
2017
2018 if (dotdot(value))
2019 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
2020
2021 return set_config_path_item(&lxc_conf->cgroup_meta.container_dir, value);
2022 }
2023
2024 static int set_config_cgroup_container_inner_dir(const char *key,
2025 const char *value,
2026 struct lxc_conf *lxc_conf,
2027 void *data)
2028 {
2029 if (lxc_config_value_empty(value))
2030 return clr_config_cgroup_container_inner_dir(key, lxc_conf, NULL);
2031
2032 if (abspath(value))
2033 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
2034
2035 if (strchr(value, '/') || strequal(value, ".") || strequal(value, ".."))
2036 return log_error_errno(-EINVAL, EINVAL, "lxc.cgroup.dir.container.inner must be a single directory name");
2037
2038 return set_config_string_item(&lxc_conf->cgroup_meta.namespace_dir, value);
2039 }
2040
2041 static int set_config_cgroup_relative(const char *key, const char *value,
2042 struct lxc_conf *lxc_conf, void *data)
2043 {
2044 unsigned int converted;
2045 int ret;
2046
2047 if (lxc_config_value_empty(value))
2048 return clr_config_cgroup_relative(key, lxc_conf, NULL);
2049
2050 ret = lxc_safe_uint(value, &converted);
2051 if (ret)
2052 return ret;
2053
2054 if (converted == 1) {
2055 lxc_conf->cgroup_meta.relative = true;
2056 return 0;
2057 }
2058
2059 if (converted == 0) {
2060 lxc_conf->cgroup_meta.relative = false;
2061 return 0;
2062 }
2063
2064 return ret_errno(EINVAL);
2065 }
2066
2067 static bool parse_limit_value(const char **value, rlim_t *res)
2068 {
2069 char *endptr = NULL;
2070
2071 if (strnequal(*value, "unlimited", STRLITERALLEN("unlimited"))) {
2072 *res = RLIM_INFINITY;
2073 *value += STRLITERALLEN("unlimited");
2074 return true;
2075 }
2076
2077 errno = 0;
2078 *res = strtoull(*value, &endptr, 10);
2079 if (errno || !endptr)
2080 return false;
2081
2082 *value = endptr;
2083
2084 return true;
2085 }
2086
2087 static int set_config_prlimit(const char *key, const char *value,
2088 struct lxc_conf *lxc_conf, void *data)
2089 {
2090 call_cleaner(free_lxc_limit) struct lxc_limit *new_lim = NULL;
2091 struct rlimit limit;
2092 rlim_t limit_value;
2093 struct lxc_limit *lim;
2094
2095 if (lxc_config_value_empty(value))
2096 return lxc_clear_limits(lxc_conf, key);
2097
2098 if (!strnequal(key, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")))
2099 return ret_errno(EINVAL);
2100
2101 key += STRLITERALLEN("lxc.prlimit.");
2102
2103 /* soft limit comes first in the value */
2104 if (!parse_limit_value(&value, &limit_value))
2105 return ret_errno(EINVAL);
2106
2107 limit.rlim_cur = limit_value;
2108
2109 /* skip spaces and a colon */
2110 while (isspace(*value))
2111 ++value;
2112
2113 if (*value == ':')
2114 ++value;
2115 else if (*value) /* any other character is an error here */
2116 return ret_errno(EINVAL);
2117
2118 while (isspace(*value))
2119 ++value;
2120
2121 /* optional hard limit */
2122 if (*value) {
2123 if (!parse_limit_value(&value, &limit_value))
2124 return ret_errno(EINVAL);
2125
2126 limit.rlim_max = limit_value;
2127
2128 /* check for trailing garbage */
2129 while (isspace(*value))
2130 ++value;
2131
2132 if (*value)
2133 return ret_errno(EINVAL);
2134 } else {
2135 /* a single value sets both hard and soft limit */
2136 limit.rlim_max = limit.rlim_cur;
2137 }
2138
2139 /* find existing list element */
2140 list_for_each_entry(lim, &lxc_conf->limits, head) {
2141 if (!strequal(key, lim->resource))
2142 continue;
2143
2144 lim->limit = limit;
2145 return 0;
2146 }
2147
2148 new_lim = zalloc(sizeof(*new_lim));
2149 if (!new_lim)
2150 return ret_errno(ENOMEM);
2151
2152 new_lim->resource = strdup(key);
2153 if (!new_lim->resource)
2154 return ret_errno(ENOMEM);
2155
2156 new_lim->limit = limit;
2157 list_add_tail(&new_lim->head, &lxc_conf->limits);
2158 move_ptr(new_lim);
2159
2160 return 0;
2161 }
2162
2163 static int set_config_sysctl(const char *key, const char *value,
2164 struct lxc_conf *lxc_conf, void *data)
2165 {
2166 call_cleaner(free_lxc_sysctl) struct lxc_sysctl *sysctl_elem = NULL;
2167 struct lxc_sysctl *sysctl, *nsysctl;
2168
2169 if (lxc_config_value_empty(value))
2170 return clr_config_sysctl(key, lxc_conf, NULL);
2171
2172 if (!strnequal(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
2173 return ret_errno(EINVAL);
2174
2175 key += STRLITERALLEN("lxc.sysctl.");
2176 if (is_empty_string(key))
2177 return ret_errno(EINVAL);
2178
2179 /* find existing list element */
2180 list_for_each_entry_safe(sysctl, nsysctl, &lxc_conf->sysctls, head) {
2181 __do_free char *replace_value = NULL;
2182
2183 if (!strequal(key, sysctl->key))
2184 continue;
2185
2186 replace_value = strdup(value);
2187 if (!replace_value)
2188 return ret_errno(EINVAL);
2189
2190 free(sysctl->value);
2191 sysctl->value = move_ptr(replace_value);
2192
2193 return 0;
2194 }
2195
2196 sysctl_elem = zalloc(sizeof(*sysctl_elem));
2197 if (!sysctl_elem)
2198 return ret_errno(ENOMEM);
2199
2200 sysctl_elem->key = strdup(key);
2201 if (!sysctl_elem->key)
2202 return ret_errno(ENOMEM);
2203
2204 sysctl_elem->value = strdup(value);
2205 if (!sysctl_elem->value)
2206 return ret_errno(ENOMEM);
2207
2208 list_add_tail(&sysctl_elem->head, &lxc_conf->sysctls);
2209 move_ptr(sysctl_elem);
2210
2211 return 0;
2212 }
2213
2214 static int set_config_proc(const char *key, const char *value,
2215 struct lxc_conf *lxc_conf, void *data)
2216 {
2217 call_cleaner(free_lxc_proc) struct lxc_proc *new_proc = NULL;
2218 const char *subkey;
2219
2220 if (lxc_config_value_empty(value))
2221 return clr_config_proc(key, lxc_conf, NULL);
2222
2223 if (!strnequal(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
2224 return ret_errno(EINVAL);
2225
2226 subkey = key + STRLITERALLEN("lxc.proc.");
2227 if (*subkey == '\0')
2228 return ret_errno(EINVAL);
2229
2230 new_proc = zalloc(sizeof(*new_proc));
2231 if (!new_proc)
2232 return ret_errno(ENOMEM);
2233
2234 new_proc->filename = strdup(subkey);
2235 if (!new_proc->filename)
2236 return ret_errno(ENOMEM);
2237
2238 new_proc->value = strdup(value);
2239 if (!new_proc->value)
2240 return ret_errno(ENOMEM);
2241
2242 list_add_tail(&new_proc->head, &lxc_conf->procs);
2243 move_ptr(new_proc);
2244
2245 return 0;
2246 }
2247
2248 static int set_config_idmaps(const char *key, const char *value,
2249 struct lxc_conf *lxc_conf, void *data)
2250 {
2251 __do_free struct id_map *idmap = NULL;
2252 unsigned long hostid, nsid, range;
2253 char type;
2254 int ret;
2255
2256 if (lxc_config_value_empty(value))
2257 return lxc_clear_idmaps(lxc_conf);
2258
2259 idmap = zalloc(sizeof(*idmap));
2260 if (!idmap)
2261 return ret_errno(ENOMEM);
2262
2263 ret = parse_idmaps(value, &type, &nsid, &hostid, &range);
2264 if (ret < 0)
2265 return log_error_errno(-EINVAL, EINVAL, "Failed to parse id mappings");
2266
2267 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
2268 if (type == 'u')
2269 idmap->idtype = ID_TYPE_UID;
2270 else if (type == 'g')
2271 idmap->idtype = ID_TYPE_GID;
2272 else
2273 return ret_errno(EINVAL);
2274
2275 idmap->hostid = hostid;
2276 idmap->nsid = nsid;
2277 idmap->range = range;
2278 list_add_tail(&idmap->head, &lxc_conf->id_map);
2279
2280 if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID)
2281 if (idmap->nsid == 0)
2282 lxc_conf->root_nsuid_map = idmap;
2283
2284 if (!lxc_conf->root_nsgid_map && idmap->idtype == ID_TYPE_GID)
2285 if (idmap->nsid == 0)
2286 lxc_conf->root_nsgid_map = idmap;
2287
2288 move_ptr(idmap);
2289
2290 return 0;
2291 }
2292
2293 static int set_config_mount_fstab(const char *key, const char *value,
2294 struct lxc_conf *lxc_conf, void *data)
2295 {
2296 if (lxc_config_value_empty(value)) {
2297 clr_config_mount_fstab(key, lxc_conf, NULL);
2298 return ret_errno(EINVAL);
2299 }
2300
2301 return set_config_path_item(&lxc_conf->fstab, value);
2302 }
2303
2304 static int set_config_mount_auto(const char *key, const char *value,
2305 struct lxc_conf *lxc_conf, void *data)
2306 {
2307 __do_free char *autos = NULL;
2308 char *token;
2309 int i;
2310 static struct {
2311 const char *token;
2312 int mask;
2313 int flag;
2314 } allowed_auto_mounts[] = {
2315 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2316 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2317 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
2318 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2319 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
2320 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2321 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
2322 { "cgroup2", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RW | LXC_AUTO_CGROUP_FORCE },
2323 { "cgroup2:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RO | LXC_AUTO_CGROUP_FORCE },
2324 { "cgroup2:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RW | LXC_AUTO_CGROUP_FORCE },
2325 { "cgroup2:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RO | LXC_AUTO_CGROUP_FORCE },
2326 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
2327 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
2328 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
2329 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
2330 { "cgroup:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC | LXC_AUTO_CGROUP_FORCE },
2331 { "cgroup:mixed:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED | LXC_AUTO_CGROUP_FORCE },
2332 { "cgroup:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO | LXC_AUTO_CGROUP_FORCE },
2333 { "cgroup:rw:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW | LXC_AUTO_CGROUP_FORCE },
2334 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
2335 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
2336 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
2337 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
2338 { "cgroup-full:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC | LXC_AUTO_CGROUP_FORCE },
2339 { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED | LXC_AUTO_CGROUP_FORCE },
2340 { "cgroup-full:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO | LXC_AUTO_CGROUP_FORCE },
2341 { "cgroup-full:rw:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW | LXC_AUTO_CGROUP_FORCE },
2342 { "shmounts:", LXC_AUTO_SHMOUNTS_MASK, LXC_AUTO_SHMOUNTS },
2343 /*
2344 * For adding anything that is just a single on/off, but has no
2345 * options: keep mask and flag identical and just define the
2346 * enum value as an unused bit so far
2347 */
2348 { NULL, 0, 0 }
2349 };
2350
2351 if (lxc_config_value_empty(value)) {
2352 lxc_conf->auto_mounts = 0;
2353 return 0;
2354 }
2355
2356 autos = strdup(value);
2357 if (!autos)
2358 return ret_errno(ENOMEM);
2359
2360 lxc_iterate_parts(token, autos, " \t") {
2361 bool is_shmounts = false;
2362
2363 for (i = 0; allowed_auto_mounts[i].token; i++) {
2364 if (strequal(allowed_auto_mounts[i].token, token))
2365 break;
2366
2367 if (strequal("shmounts:", allowed_auto_mounts[i].token) &&
2368 strnequal("shmounts:", token, STRLITERALLEN("shmounts:"))) {
2369 is_shmounts = true;
2370 break;
2371 }
2372 }
2373
2374 if (!allowed_auto_mounts[i].token)
2375 return log_error_errno(-EINVAL, EINVAL, "Invalid filesystem to automount \"%s\"", token);
2376
2377 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
2378 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
2379
2380 if (is_shmounts) {
2381 __do_free char *container_path = NULL, *host_path = NULL;
2382 char *val;
2383
2384 val = token + STRLITERALLEN("shmounts:");
2385 if (*val == '\0')
2386 return log_error_errno(-EINVAL, EINVAL, "Failed to copy shmounts host path");
2387
2388 host_path = strdup(val);
2389 if (!host_path)
2390 return log_error_errno(-EINVAL, EINVAL, "Failed to copy shmounts host path");
2391
2392 val = strchr(host_path, ':');
2393 if (!val || *(val + 1) == '\0')
2394 val = "/dev/.lxc-mounts";
2395 else
2396 *val++ = '\0';
2397
2398 container_path = strdup(val);
2399 if(!container_path)
2400 return log_error_errno(-EINVAL, EINVAL, "Failed to copy shmounts container path");
2401
2402 free_disarm(lxc_conf->shmount.path_host);
2403 lxc_conf->shmount.path_host = move_ptr(host_path);
2404
2405 free_disarm(lxc_conf->shmount.path_cont);
2406 lxc_conf->shmount.path_cont = move_ptr(container_path);
2407 }
2408 }
2409
2410 return 0;
2411 }
2412
2413 static int set_config_mount(const char *key, const char *value,
2414 struct lxc_conf *lxc_conf, void *data)
2415 {
2416 __do_free char *mntelem = NULL;
2417 __do_free struct string_entry *entry = NULL;
2418
2419 if (lxc_config_value_empty(value))
2420 return lxc_clear_mount_entries(lxc_conf);
2421
2422 entry = zalloc(sizeof(struct string_entry));
2423 if (!entry)
2424 return ret_errno(ENOMEM);
2425
2426 mntelem = strdup(value);
2427 if (!mntelem)
2428 return ret_errno(ENOMEM);
2429
2430 entry->val = move_ptr(mntelem);
2431 list_add_tail(&entry->head, &lxc_conf->mount_entries);
2432 move_ptr(entry);
2433
2434 return 0;
2435 }
2436
2437 int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) {
2438 return set_config_mount(NULL, value, lxc_conf, NULL);
2439 }
2440
2441 static int add_cap_entry(struct lxc_conf *conf, char *caps, bool keep)
2442 {
2443 char *token;
2444
2445 /*
2446 * In case several capability keep is specified in a single line split
2447 * these caps in a single element for the list.
2448 */
2449 lxc_iterate_parts(token, caps, " \t") {
2450 __do_free struct cap_entry *new_cap = NULL;
2451 int ret;
2452 __u32 cap;
2453
2454 if (strequal(token, "none")) {
2455 if (!keep)
2456 return syserror_set(-EINVAL, "The \"none\" keyword is only valid when keeping caps");
2457
2458 lxc_clear_config_caps(conf);
2459 continue;
2460 }
2461
2462 ret = parse_cap(token, &cap);
2463 if (ret < 0) {
2464 if (ret != -2)
2465 return syserror_set(-EINVAL, "Invalid capability specified");
2466
2467 INFO("Ignoring unknown capability \"%s\"", token);
2468 continue;
2469 }
2470
2471 new_cap = zalloc(sizeof(struct cap_entry));
2472 if (!new_cap)
2473 return ret_errno(ENOMEM);
2474
2475 new_cap->cap_name = strdup(token);
2476 if (!new_cap->cap_name)
2477 return ret_errno(ENOMEM);
2478 new_cap->cap = cap;
2479
2480 list_add_tail(&new_cap->head, &conf->caps.list);
2481 move_ptr(new_cap);
2482 }
2483
2484 return 0;
2485 }
2486
2487 static int set_config_cap_keep(const char *key, const char *value,
2488 struct lxc_conf *lxc_conf, void *data)
2489 {
2490 __do_free char *caps = NULL;
2491 int ret;
2492
2493 if (lxc_config_value_empty(value))
2494 return lxc_clear_config_caps(lxc_conf);
2495
2496 caps = strdup(value);
2497 if (!caps)
2498 return ret_errno(ENOMEM);
2499
2500 if (!lxc_conf->caps.keep && !list_empty(&lxc_conf->caps.list))
2501 return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive");
2502
2503 ret = add_cap_entry(lxc_conf, caps, true);
2504 if (ret < 0)
2505 return ret;
2506
2507 lxc_conf->caps.keep = true;
2508 return 0;
2509 }
2510
2511 static int set_config_cap_drop(const char *key, const char *value,
2512 struct lxc_conf *lxc_conf, void *data)
2513 {
2514 __do_free char *caps = NULL;
2515 int ret;
2516
2517 if (lxc_config_value_empty(value))
2518 return lxc_clear_config_caps(lxc_conf);
2519
2520 if (lxc_conf->caps.keep)
2521 return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive");
2522
2523 caps = strdup(value);
2524 if (!caps)
2525 return ret_errno(ENOMEM);
2526
2527 ret = add_cap_entry(lxc_conf, caps, false);
2528 if (ret < 0)
2529 return ret;
2530
2531 lxc_conf->caps.keep = false;
2532 return 0;
2533 }
2534
2535 static int set_config_console_path(const char *key, const char *value,
2536 struct lxc_conf *lxc_conf, void *data)
2537 {
2538 return set_config_path_item(&lxc_conf->console.path, value);
2539 }
2540
2541 static int set_config_console_rotate(const char *key, const char *value,
2542 struct lxc_conf *lxc_conf, void *data)
2543 {
2544 int ret;
2545
2546 if (lxc_config_value_empty(value)) {
2547 lxc_conf->console.log_rotate = 0;
2548 return 0;
2549 }
2550
2551 ret = lxc_safe_uint(value, &lxc_conf->console.log_rotate);
2552 if (ret)
2553 return ret_errno(EINVAL);
2554
2555 if (lxc_conf->console.log_rotate > 1)
2556 return log_error_errno(-EINVAL, EINVAL, "The \"lxc.console.rotate\" config key can only be set to 0 or 1");
2557
2558 return 0;
2559 }
2560
2561 static int set_config_console_logfile(const char *key, const char *value,
2562 struct lxc_conf *lxc_conf, void *data)
2563 {
2564 return set_config_path_item(&lxc_conf->console.log_path, value);
2565 }
2566
2567 static int set_config_console_buffer_size(const char *key, const char *value,
2568 struct lxc_conf *lxc_conf, void *data)
2569 {
2570 int ret;
2571 long long int size;
2572 uint64_t buffer_size, pgsz;
2573
2574 if (lxc_config_value_empty(value)) {
2575 lxc_conf->console.buffer_size = 0;
2576 return 0;
2577 }
2578
2579 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2580 if (strequal(value, "auto")) {
2581 lxc_conf->console.buffer_size = 1 << 17;
2582 return 0;
2583 }
2584
2585 ret = parse_byte_size_string(value, &size);
2586 if (ret)
2587 return ret;
2588
2589 if (size < 0)
2590 return ret_errno(EINVAL);
2591
2592 /* must be at least a page size */
2593 pgsz = lxc_getpagesize();
2594 if ((uint64_t)size < pgsz) {
2595 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
2596 size, pgsz, pgsz);
2597 size = pgsz;
2598 }
2599
2600 buffer_size = lxc_find_next_power2((uint64_t)size);
2601 if (buffer_size == 0)
2602 return ret_errno(EINVAL);
2603
2604 if (buffer_size != (uint64_t)size)
2605 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64 " bytes", buffer_size);
2606
2607 lxc_conf->console.buffer_size = buffer_size;
2608
2609 return 0;
2610 }
2611
2612 static int set_config_console_size(const char *key, const char *value,
2613 struct lxc_conf *lxc_conf, void *data)
2614 {
2615 int ret;
2616 long long int size;
2617 uint64_t log_size, pgsz;
2618
2619 if (lxc_config_value_empty(value)) {
2620 lxc_conf->console.log_size = 0;
2621 return 0;
2622 }
2623
2624 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2625 if (strequal(value, "auto")) {
2626 lxc_conf->console.log_size = 1 << 17;
2627 return 0;
2628 }
2629
2630 ret = parse_byte_size_string(value, &size);
2631 if (ret)
2632 return ret_errno(EINVAL);
2633
2634 if (size < 0)
2635 return ret_errno(EINVAL);
2636
2637 /* must be at least a page size */
2638 pgsz = lxc_getpagesize();
2639 if ((uint64_t)size < pgsz) {
2640 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
2641 size, pgsz, pgsz);
2642 size = pgsz;
2643 }
2644
2645 log_size = lxc_find_next_power2((uint64_t)size);
2646 if (log_size == 0)
2647 return ret_errno(EINVAL);
2648
2649 if (log_size != (uint64_t)size)
2650 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64 " bytes", log_size);
2651
2652 lxc_conf->console.log_size = log_size;
2653
2654 return 0;
2655 }
2656
2657 /*
2658 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
2659 * file, we expand it in the unexpanded_config, so that after a save_config we
2660 * store the hwaddr for re-use.
2661 * This is only called when reading the config file, not when executing a
2662 * lxc.include.
2663 * 'x' and 'X' are substituted in-place.
2664 */
2665 static void update_hwaddr(const char *line)
2666 {
2667 char *p;
2668
2669 line += lxc_char_left_gc(line, strlen(line));
2670 if (line[0] == '#')
2671 return;
2672
2673 if (!lxc_config_net_is_hwaddr(line))
2674 return;
2675
2676 /* Let config_net_hwaddr raise the error. */
2677 p = strchr(line, '=');
2678 if (!p)
2679 return;
2680 p++;
2681
2682 while (isblank(*p))
2683 p++;
2684
2685 if (!*p)
2686 return;
2687
2688 rand_complete_hwaddr(p);
2689 }
2690
2691 int append_unexp_config_line(const char *line, struct lxc_conf *conf)
2692 {
2693 size_t linelen;
2694 size_t len = conf->unexpanded_len;
2695
2696 update_hwaddr(line);
2697
2698 linelen = strlen(line);
2699 while (conf->unexpanded_alloced <= len + linelen + 2) {
2700 char *tmp;
2701
2702 tmp = realloc(conf->unexpanded_config, conf->unexpanded_alloced + 1024);
2703 if (!tmp)
2704 return ret_errno(EINVAL);
2705
2706 if (!conf->unexpanded_config)
2707 *tmp = '\0';
2708
2709 conf->unexpanded_config = tmp;
2710 conf->unexpanded_alloced += 1024;
2711 }
2712
2713 memcpy(conf->unexpanded_config + conf->unexpanded_len, line, linelen);
2714 conf->unexpanded_len += linelen;
2715 if (line[linelen - 1] != '\n')
2716 conf->unexpanded_config[conf->unexpanded_len++] = '\n';
2717 conf->unexpanded_config[conf->unexpanded_len] = '\0';
2718
2719 return 0;
2720 }
2721
2722 static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2723 {
2724 __do_closedir DIR *dir = NULL;
2725 struct dirent *direntp;
2726 int len, ret;
2727
2728 dir = opendir(dirp);
2729 if (!dir)
2730 return errno == ENOENT ? 0 : -errno;
2731
2732 while ((direntp = readdir(dir))) {
2733 const char *fnam;
2734 char path[PATH_MAX];
2735
2736 fnam = direntp->d_name;
2737 if (strequal(fnam, "."))
2738 continue;
2739
2740 if (strequal(fnam, ".."))
2741 continue;
2742
2743 len = strlen(fnam);
2744 if (len < 6 || !strnequal(fnam + len - 5, ".conf", 5))
2745 continue;
2746
2747 len = strnprintf(path, sizeof(path), "%s/%s", dirp, fnam);
2748 if (len < 0)
2749 return ret_errno(EIO);
2750
2751 ret = lxc_config_read(path, lxc_conf, true);
2752 if (ret < 0)
2753 return ret;
2754 }
2755
2756 return 0;
2757 }
2758
2759 static int set_config_includefiles(const char *key, const char *value,
2760 struct lxc_conf *lxc_conf, void *data)
2761 {
2762 if (lxc_config_value_empty(value)) {
2763 clr_config_includefiles(key, lxc_conf, NULL);
2764 return 0;
2765 }
2766
2767 if (value[strlen(value)-1] == '/' || is_dir(value))
2768 return do_includedir(value, lxc_conf);
2769
2770 return lxc_config_read(value, lxc_conf, true);
2771 }
2772
2773 static int set_config_rootfs_path(const char *key, const char *value,
2774 struct lxc_conf *lxc_conf, void *data)
2775 {
2776 __do_free char *dup = NULL;
2777 int ret;
2778 char *tmp;
2779 const char *container_path;
2780
2781 if (lxc_config_value_empty(value)) {
2782 free(lxc_conf->rootfs.path);
2783 lxc_conf->rootfs.path = NULL;
2784 return 0;
2785 }
2786
2787 dup = strdup(value);
2788 if (!dup)
2789 return ret_errno(ENOMEM);
2790
2791 /* Split <storage type>:<container path> into <storage type> and
2792 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2793 * "rootfs.path" to <container path>.
2794 */
2795 tmp = strchr(dup, ':');
2796 if (tmp) {
2797 *tmp = '\0';
2798
2799 ret = set_config_path_item(&lxc_conf->rootfs.bdev_type, dup);
2800 if (ret < 0)
2801 return ret_errno(ENOMEM);
2802
2803 tmp++;
2804 container_path = tmp;
2805 } else {
2806 container_path = value;
2807 }
2808
2809 return set_config_path_item(&lxc_conf->rootfs.path, container_path);
2810 }
2811
2812 static int set_config_rootfs_managed(const char *key, const char *value,
2813 struct lxc_conf *lxc_conf, void *data)
2814 {
2815 return set_config_bool_item(&lxc_conf->rootfs.managed, value, true);
2816 }
2817
2818 static int set_config_rootfs_mount(const char *key, const char *value,
2819 struct lxc_conf *lxc_conf, void *data)
2820 {
2821 return set_config_path_item(&lxc_conf->rootfs.mount, value);
2822 }
2823
2824 static int set_config_rootfs_options(const char *key, const char *value,
2825 struct lxc_conf *lxc_conf, void *data)
2826 {
2827 __do_free char *dup = NULL, *raw_options = NULL;
2828 struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
2829 struct lxc_mount_options *mnt_opts = &rootfs->mnt_opts;
2830 int ret;
2831
2832 clr_config_rootfs_options(key, lxc_conf, data);
2833 if (lxc_config_value_empty(value))
2834 return 0;
2835
2836 ret = set_config_string_item(&raw_options, value);
2837 if (ret < 0)
2838 return ret_errno(ENOMEM);
2839
2840 dup = strdup(value);
2841 if (!dup)
2842 return -ENOMEM;
2843
2844 ret = parse_lxc_mount_attrs(mnt_opts, dup);
2845 if (ret < 0)
2846 return ret;
2847
2848 /* Make sure we're only valid LXC specific mount options. */
2849 if (mnt_opts->create_dir || mnt_opts->create_file ||
2850 mnt_opts->optional || mnt_opts->relative)
2851 return syserror_set(-EINVAL, "Invalid LXC specific mount option for rootfs mount");
2852
2853 ret = parse_mount_attrs(mnt_opts, dup);
2854 if (ret < 0)
2855 return ret_errno(EINVAL);
2856
2857 rootfs->mnt_opts.raw_options = move_ptr(raw_options);
2858 return 0;
2859 }
2860
2861 static int set_config_uts_name(const char *key, const char *value,
2862 struct lxc_conf *lxc_conf, void *data)
2863 {
2864 __do_free struct utsname *utsname = NULL;
2865
2866 if (lxc_config_value_empty(value)) {
2867 clr_config_uts_name(key, lxc_conf, NULL);
2868 return 0;
2869 }
2870
2871 utsname = zalloc(sizeof(*utsname));
2872 if (!utsname)
2873 return ret_errno(ENOMEM);
2874
2875 if (strlen(value) >= sizeof(utsname->nodename))
2876 return ret_errno(EINVAL);
2877
2878 (void)strlcpy(utsname->nodename, value, sizeof(utsname->nodename));
2879 free(lxc_conf->utsname);
2880 lxc_conf->utsname = move_ptr(utsname);
2881
2882 return 0;
2883 }
2884
2885 static int set_config_namespace_clone(const char *key, const char *value,
2886 struct lxc_conf *lxc_conf, void *data)
2887 {
2888 __do_free char *ns = NULL;
2889 char *token;
2890 int cloneflag = 0;
2891
2892 if (lxc_config_value_empty(value))
2893 return clr_config_namespace_clone(key, lxc_conf, data);
2894
2895 if (lxc_conf->ns_keep != 0)
2896 return log_error_errno(-EINVAL, EINVAL, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2897
2898 ns = strdup(value);
2899 if (!ns)
2900 return ret_errno(ENOMEM);
2901
2902 lxc_iterate_parts(token, ns, " \t") {
2903 token += lxc_char_left_gc(token, strlen(token));
2904 token[lxc_char_right_gc(token, strlen(token))] = '\0';
2905 cloneflag = lxc_namespace_2_cloneflag(token);
2906 if (cloneflag < 0)
2907 return ret_errno(EINVAL);
2908 lxc_conf->ns_clone |= cloneflag;
2909 }
2910
2911 return 0;
2912 }
2913
2914 static int set_config_namespace_keep(const char *key, const char *value,
2915 struct lxc_conf *lxc_conf, void *data)
2916 {
2917 __do_free char *ns = NULL;
2918 char *token;
2919 int cloneflag = 0;
2920
2921 if (lxc_config_value_empty(value))
2922 return clr_config_namespace_keep(key, lxc_conf, data);
2923
2924 if (lxc_conf->ns_clone != 0)
2925 return log_error_errno(-EINVAL, EINVAL, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2926
2927 ns = strdup(value);
2928 if (!ns)
2929 return ret_errno(ENOMEM);
2930
2931 lxc_iterate_parts(token, ns, " \t") {
2932 token += lxc_char_left_gc(token, strlen(token));
2933 token[lxc_char_right_gc(token, strlen(token))] = '\0';
2934 cloneflag = lxc_namespace_2_cloneflag(token);
2935 if (cloneflag < 0)
2936 return ret_errno(EINVAL);
2937 lxc_conf->ns_keep |= cloneflag;
2938 }
2939
2940 return 0;
2941 }
2942
2943 static int set_config_time_offset_boot(const char *key, const char *value,
2944 struct lxc_conf *lxc_conf, void *data)
2945 {
2946 int ret;
2947 char *unit;
2948 int64_t offset = 0;
2949 char buf[STRLITERALLEN("ms") + 1];
2950
2951 if (lxc_config_value_empty(value))
2952 return clr_config_time_offset_boot(key, lxc_conf, data);
2953
2954 ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
2955 if (ret)
2956 return ret;
2957
2958 unit = lxc_trim_whitespace_in_place(buf);
2959 if (strequal(unit, "h")) {
2960 if (!multiply_overflow(offset, 3600, &lxc_conf->timens.s_boot))
2961 return ret_errno(EOVERFLOW);
2962 } else if (strequal(unit, "m")) {
2963 if (!multiply_overflow(offset, 60, &lxc_conf->timens.s_boot))
2964 return ret_errno(EOVERFLOW);
2965 } else if (strequal(unit, "s")) {
2966 lxc_conf->timens.s_boot = offset;
2967 } else if (strequal(unit, "ms")) {
2968 if (!multiply_overflow(offset, 1000000, &lxc_conf->timens.ns_boot))
2969 return ret_errno(EOVERFLOW);
2970 } else if (strequal(unit, "us")) {
2971 if (!multiply_overflow(offset, 1000, &lxc_conf->timens.ns_boot))
2972 return ret_errno(EOVERFLOW);
2973 } else if (strequal(unit, "ns")) {
2974 lxc_conf->timens.ns_boot = offset;
2975 } else {
2976 return ret_errno(EINVAL);
2977 }
2978
2979 return 0;
2980 }
2981
2982 static int set_config_time_offset_monotonic(const char *key, const char *value,
2983 struct lxc_conf *lxc_conf, void *data)
2984 {
2985 int ret;
2986 char *unit;
2987 int64_t offset = 0;
2988 char buf[STRLITERALLEN("ms") + 1];
2989
2990 if (lxc_config_value_empty(value))
2991 return clr_config_time_offset_monotonic(key, lxc_conf, data);
2992
2993 ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
2994 if (ret)
2995 return ret;
2996
2997 unit = lxc_trim_whitespace_in_place(buf);
2998 if (strequal(unit, "h")) {
2999 if (!multiply_overflow(offset, 3600, &lxc_conf->timens.s_monotonic))
3000 return ret_errno(EOVERFLOW);
3001 } else if (strequal(unit, "m")) {
3002 if (!multiply_overflow(offset, 60, &lxc_conf->timens.s_monotonic))
3003 return ret_errno(EOVERFLOW);
3004 } else if (strequal(unit, "s")) {
3005 lxc_conf->timens.s_monotonic = offset;
3006 } else if (strequal(unit, "ms")) {
3007 if (!multiply_overflow(offset, 1000000, &lxc_conf->timens.ns_monotonic))
3008 return ret_errno(EOVERFLOW);
3009 } else if (strequal(unit, "us")) {
3010 if (!multiply_overflow(offset, 1000, &lxc_conf->timens.ns_monotonic))
3011 return ret_errno(EOVERFLOW);
3012 } else if (strequal(unit, "ns")) {
3013 lxc_conf->timens.ns_monotonic = offset;
3014 } else {
3015 return ret_errno(EINVAL);
3016 }
3017
3018 return 0;
3019 }
3020
3021 static int set_config_namespace_share(const char *key, const char *value,
3022 struct lxc_conf *lxc_conf, void *data)
3023 {
3024 int ns_idx;
3025 const char *namespace;
3026
3027 if (lxc_config_value_empty(value))
3028 return clr_config_namespace_share(key, lxc_conf, data);
3029
3030 namespace = key + STRLITERALLEN("lxc.namespace.share.");
3031 if (is_empty_string(namespace))
3032 return ret_errno(EINVAL);
3033
3034 ns_idx = lxc_namespace_2_ns_idx(namespace);
3035 if (ns_idx < 0)
3036 return ns_idx;
3037
3038 return set_config_string_item(&lxc_conf->ns_share[ns_idx], value);
3039 }
3040
3041 struct parse_line_conf {
3042 struct lxc_conf *conf;
3043 bool from_include;
3044 };
3045
3046 static int parse_line(char *buffer, void *data)
3047 {
3048 __do_free char *linep = NULL;
3049 char *dot, *key, *line, *value;
3050 bool empty_line;
3051 struct lxc_config_t *config;
3052 int ret;
3053 char *dup = buffer;
3054 struct parse_line_conf *plc = data;
3055
3056 if (!plc->conf)
3057 return syserror_set(-EINVAL, "Missing config");
3058
3059 /* If there are newlines in the config file we should keep them. */
3060 empty_line = lxc_is_line_empty(dup);
3061 if (empty_line)
3062 dup = "\n";
3063
3064 /* We have to dup the buffer otherwise, at the re-exec for reboot we
3065 * modified the original string on the stack by replacing '=' by '\0'
3066 * below.
3067 */
3068 linep = line = strdup(dup);
3069 if (!line)
3070 return ret_errno(ENOMEM);
3071
3072 if (!plc->from_include) {
3073 ret = append_unexp_config_line(line, plc->conf);
3074 if (ret < 0)
3075 return ret;
3076 }
3077
3078 if (empty_line)
3079 return 0;
3080
3081 line += lxc_char_left_gc(line, strlen(line));
3082
3083 /* ignore comments */
3084 if (line[0] == '#')
3085 return 0;
3086
3087 /* martian option - don't add it to the config itself */
3088 if (!strnequal(line, "lxc.", 4))
3089 return 0;
3090
3091 dot = strchr(line, '=');
3092 if (!dot)
3093 return log_error_errno(-EINVAL, EINVAL, "Invalid configuration line: %s", line);
3094
3095 *dot = '\0';
3096 value = dot + 1;
3097
3098 key = line;
3099 key[lxc_char_right_gc(key, strlen(key))] = '\0';
3100
3101 value += lxc_char_left_gc(value, strlen(value));
3102 value[lxc_char_right_gc(value, strlen(value))] = '\0';
3103
3104 if (*value == '\'' || *value == '\"') {
3105 size_t len;
3106
3107 len = strlen(value);
3108 if (len > 1 && value[len - 1] == *value) {
3109 value[len - 1] = '\0';
3110 value++;
3111 }
3112 }
3113
3114 config = lxc_get_config(key);
3115 return config->set(key, value, plc->conf, NULL);
3116 }
3117
3118 static struct new_config_item *parse_new_conf_line(char *buffer)
3119 {
3120 __do_free char *k = NULL, *linep = NULL, *v = NULL;
3121 __do_free struct new_config_item *new = NULL;
3122 char *dup = buffer;
3123 char *dot, *key, *line, *value;
3124
3125 if (is_empty_string(buffer))
3126 return log_error_errno(NULL, EINVAL, "Empty configuration line");
3127
3128 linep = line = strdup(dup);
3129 if (!line)
3130 return NULL;
3131
3132 line += lxc_char_left_gc(line, strlen(line));
3133
3134 /* martian option - don't add it to the config itself */
3135 if (!strnequal(line, "lxc.", 4))
3136 return 0;
3137
3138 dot = strchr(line, '=');
3139 if (!dot)
3140 return log_error_errno(NULL, EINVAL, "Invalid configuration line: %s", line);
3141
3142 *dot = '\0';
3143 value = dot + 1;
3144
3145 key = line;
3146 key[lxc_char_right_gc(key, strlen(key))] = '\0';
3147
3148 value += lxc_char_left_gc(value, strlen(value));
3149 value[lxc_char_right_gc(value, strlen(value))] = '\0';
3150
3151 if (*value == '\'' || *value == '\"') {
3152 size_t len;
3153
3154 len = strlen(value);
3155 if (len > 1 && value[len - 1] == *value) {
3156 value[len - 1] = '\0';
3157 value++;
3158 }
3159 }
3160
3161 new = zalloc(sizeof(struct new_config_item));
3162 if (!new)
3163 return NULL;
3164
3165 k = strdup(key);
3166 if (!k)
3167 return NULL;
3168
3169 v = strdup(value);
3170 if (!v)
3171 return NULL;
3172
3173 new->key = move_ptr(k);
3174 new->val = move_ptr(v);
3175 return move_ptr(new);
3176 }
3177
3178 int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
3179 {
3180 struct parse_line_conf plc;
3181
3182 if (!conf)
3183 return syserror_set(-EINVAL, "Missing config");
3184
3185 plc.conf = conf;
3186 plc.from_include = from_include;
3187
3188 /* Catch only the top level config file name in the structure. */
3189 if (!conf->rcfile)
3190 conf->rcfile = strdup(file);
3191
3192 return lxc_file_for_each_line_mmap(file, parse_line, &plc);
3193 }
3194
3195 int lxc_config_define_add(struct lxc_list *defines, char *arg)
3196 {
3197 __do_free struct lxc_list *dent = NULL;
3198
3199 dent = lxc_list_new();
3200 if (!dent)
3201 return ret_errno(ENOMEM);
3202
3203 dent->elem = parse_new_conf_line(arg);
3204 if (!dent->elem)
3205 return ret_errno(ENOMEM);
3206
3207 lxc_list_add_tail(defines, move_ptr(dent));
3208
3209 return 0;
3210 }
3211
3212 bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c)
3213 {
3214 struct lxc_list *it;
3215 bool bret = true;
3216
3217 lxc_list_for_each(it, defines) {
3218 struct new_config_item *new_item = it->elem;
3219 bret = c->set_config_item(c, new_item->key, new_item->val);
3220 if (!bret)
3221 break;
3222 }
3223
3224 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
3225 lxc_config_define_free(defines);
3226 #endif /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
3227
3228 return bret;
3229 }
3230
3231 void lxc_config_define_free(struct lxc_list *defines)
3232 {
3233 struct lxc_list *it, *next;
3234
3235 lxc_list_for_each_safe(it, defines, next) {
3236 struct new_config_item *new_item = it->elem;
3237 free(new_item->key);
3238 free(new_item->val);
3239 lxc_list_del(it);
3240 free(it->elem);
3241 free(it);
3242 }
3243 }
3244
3245 int lxc_config_parse_arch(const char *arch, signed long *persona)
3246 {
3247 static struct per_name {
3248 char *name;
3249 unsigned long per;
3250 } pername[] = {
3251 { "arm", PER_LINUX32 },
3252 { "armel", PER_LINUX32 },
3253 { "armhf", PER_LINUX32 },
3254 { "armv7l", PER_LINUX32 },
3255 { "athlon", PER_LINUX32 },
3256 { "i386", PER_LINUX32 },
3257 { "i486", PER_LINUX32 },
3258 { "i586", PER_LINUX32 },
3259 { "i686", PER_LINUX32 },
3260 { "linux32", PER_LINUX32 },
3261 { "mips", PER_LINUX32 },
3262 { "mipsel", PER_LINUX32 },
3263 { "ppc", PER_LINUX32 },
3264 { "powerpc", PER_LINUX32 },
3265 { "x86", PER_LINUX32 },
3266 { "aarch64", PER_LINUX },
3267 { "amd64", PER_LINUX },
3268 { "arm64", PER_LINUX },
3269 { "linux64", PER_LINUX },
3270 { "mips64", PER_LINUX },
3271 { "mips64el", PER_LINUX },
3272 { "ppc64", PER_LINUX },
3273 { "ppc64el", PER_LINUX },
3274 { "ppc64le", PER_LINUX },
3275 { "powerpc64", PER_LINUX },
3276 { "riscv64", PER_LINUX },
3277 { "s390x", PER_LINUX },
3278 { "x86_64", PER_LINUX },
3279 };
3280
3281 for (size_t i = 0; i < ARRAY_SIZE(pername); i++) {
3282 if (!strequal(pername[i].name, arch))
3283 continue;
3284
3285 *persona = pername[i].per;
3286 return 0;
3287 }
3288
3289 return ret_errno(EINVAL);
3290 }
3291
3292 int lxc_fill_elevated_privileges(char *flaglist, unsigned int *flags)
3293 {
3294 unsigned int flags_tmp = 0;
3295 char *token;
3296 struct {
3297 const char *token;
3298 int flag;
3299 } all_privs[] = {
3300 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
3301 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
3302 { "LSM", LXC_ATTACH_LSM_EXEC },
3303 { NULL, 0 }
3304 };
3305
3306 if (!flaglist) {
3307 /*
3308 * For the sake of backward compatibility, keep all privileges
3309 * if no specific privileges are specified.
3310 */
3311 for (unsigned int i = 0; all_privs[i].token; i++)
3312 flags_tmp |= all_privs[i].flag;
3313
3314 *flags = flags_tmp;
3315 return 0;
3316 }
3317
3318 lxc_iterate_parts(token, flaglist, "|") {
3319 bool valid_token = false;
3320
3321 for (unsigned int i = 0; all_privs[i].token; i++) {
3322 if (!strequal(all_privs[i].token, token))
3323 continue;
3324
3325 valid_token = true;
3326 flags_tmp |= all_privs[i].flag;
3327 }
3328
3329 if (!valid_token)
3330 return syserror_set(-EINVAL, "Invalid elevated privilege \"%s\" requested", token);
3331 }
3332
3333 *flags = flags_tmp;
3334 return 0;
3335 }
3336
3337 /* Write out a configuration file. */
3338 int write_config(int fd, const struct lxc_conf *conf)
3339 {
3340 int ret;
3341 size_t len = conf->unexpanded_len;
3342
3343 if (len == 0)
3344 return 0;
3345
3346 ret = lxc_write_nointr(fd, conf->unexpanded_config, len);
3347 if (ret < 0)
3348 return log_error_errno(-errno, errno, "Failed to write configuration file");
3349
3350 return 0;
3351 }
3352
3353 bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
3354 const char *v)
3355 {
3356 __do_free char *tmp = NULL;
3357 int ret;
3358 size_t len;
3359
3360 len = strlen(key) + strlen(v) + 4;
3361 tmp = must_realloc(NULL, len);
3362
3363 if (lxc_config_value_empty(v))
3364 ret = strnprintf(tmp, len, "%s =", key);
3365 else
3366 ret = strnprintf(tmp, len, "%s = %s", key, v);
3367 if (ret < 0)
3368 return false;
3369
3370 /* Save the line verbatim into unexpanded_conf */
3371 if (append_unexp_config_line(tmp, conf))
3372 return false;
3373
3374 return true;
3375 }
3376
3377 void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
3378 bool rm_subkeys)
3379 {
3380 char *lend;
3381 char *lstart = conf->unexpanded_config;
3382
3383 if (!conf->unexpanded_config)
3384 return;
3385
3386 while (*lstart) {
3387 lend = strchr(lstart, '\n');
3388 char v;
3389
3390 if (!lend)
3391 lend = lstart + strlen(lstart);
3392 else
3393 lend++;
3394
3395 if (!strnequal(lstart, key, strlen(key))) {
3396 lstart = lend;
3397 continue;
3398 }
3399
3400 if (!rm_subkeys) {
3401 v = lstart[strlen(key)];
3402 if (!isspace(v) && v != '=') {
3403 lstart = lend;
3404 continue;
3405 }
3406 }
3407
3408 conf->unexpanded_len -= (lend - lstart);
3409
3410 if (*lend == '\0') {
3411 *lstart = '\0';
3412 return;
3413 }
3414
3415 memmove(lstart, lend, strlen(lend) + 1);
3416 }
3417 }
3418
3419 bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
3420 const char *newpath, const char *oldname,
3421 const char *newname, const char *ovldir)
3422 {
3423 __do_free char *newdir = NULL, *olddir = NULL;
3424 char *lstart = conf->unexpanded_config;
3425 const char *key = "lxc.mount.entry";
3426 int ret;
3427 char *lend, *p, *q;
3428 size_t newdirlen, olddirlen;
3429
3430 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
3431 olddir = must_realloc(NULL, olddirlen + 1);
3432 ret = strnprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath, oldname);
3433 if (ret < 0)
3434 return false;
3435
3436 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
3437 newdir = must_realloc(NULL, newdirlen + 1);
3438 ret = strnprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath, newname);
3439 if (ret < 0)
3440 return false;
3441
3442 if (!conf->unexpanded_config)
3443 return true;
3444
3445 while (*lstart) {
3446 lend = strchr(lstart, '\n');
3447 if (!lend)
3448 lend = lstart + strlen(lstart);
3449 else
3450 lend++;
3451
3452 if (!strnequal(lstart, key, strlen(key)))
3453 goto next;
3454
3455 p = strchr(lstart + strlen(key), '=');
3456 if (!p)
3457 goto next;
3458 p++;
3459
3460 while (isblank(*p))
3461 p++;
3462
3463 if (p >= lend)
3464 goto next;
3465
3466 /* Whenever a lxc.mount.entry entry is found in a line we check
3467 * if the substring "overlay" is present before doing any
3468 * further work. We check for "overlay" because substrings need
3469 * to have at least one space before them in a valid overlay
3470 * lxc.mount.entry (/A B overlay). When the space before is
3471 * missing it is very likely that these substrings are part of a
3472 * path or something else. (Checking q >= lend ensures that we
3473 * only count matches in the current line.) */
3474 q = strstr(p, " overlay");
3475 if (!q || q >= lend)
3476 goto next;
3477
3478 if (!(q = strstr(p, olddir)) || (q >= lend))
3479 goto next;
3480
3481 /* replace the olddir with newdir */
3482 if (olddirlen >= newdirlen) {
3483 size_t diff = olddirlen - newdirlen;
3484 memcpy(q, newdir, newdirlen);
3485
3486 if (olddirlen != newdirlen) {
3487 memmove(q + newdirlen, q + newdirlen + diff,
3488 strlen(q) - newdirlen - diff + 1);
3489 lend -= diff;
3490 conf->unexpanded_len -= diff;
3491 }
3492 } else {
3493 char *new;
3494 size_t diff = newdirlen - olddirlen;
3495 size_t oldlen = conf->unexpanded_len;
3496 size_t newlen = oldlen + diff;
3497 size_t poffset = q - conf->unexpanded_config;
3498
3499 new = realloc(conf->unexpanded_config, newlen + 1);
3500 if (!new)
3501 return false;
3502
3503 conf->unexpanded_len = newlen;
3504 conf->unexpanded_alloced = newlen + 1;
3505 new[newlen - 1] = '\0';
3506 lend = new + (lend - conf->unexpanded_config);
3507
3508 /* Move over the remainder to make room for the newdir.
3509 */
3510 memmove(new + poffset + newdirlen,
3511 new + poffset + olddirlen,
3512 oldlen - poffset - olddirlen + 1);
3513 conf->unexpanded_config = new;
3514
3515 memcpy(new + poffset, newdir, newdirlen);
3516 lend += diff;
3517 }
3518
3519 next:
3520 lstart = lend;
3521 }
3522
3523 return true;
3524 }
3525
3526 bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
3527 const char *newpath, const char *oldname,
3528 const char *newname)
3529 {
3530 __do_free char *newdir = NULL, *olddir = NULL;
3531 char *lstart = conf->unexpanded_config;
3532 const char *key = "lxc.hook";
3533 int ret;
3534 char *lend, *p;
3535 size_t newdirlen, olddirlen;
3536
3537 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
3538 olddir = must_realloc(NULL, olddirlen + 1);
3539 ret = strnprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
3540 if (ret < 0)
3541 return false;
3542
3543 newdirlen = strlen(newpath) + strlen(newname) + 1;
3544 newdir = must_realloc(NULL, newdirlen + 1);
3545 ret = strnprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
3546 if (ret < 0)
3547 return false;
3548
3549 if (!conf->unexpanded_config)
3550 return true;
3551
3552 while (*lstart) {
3553 lend = strchr(lstart, '\n');
3554 if (!lend)
3555 lend = lstart + strlen(lstart);
3556 else
3557 lend++;
3558
3559 if (!strnequal(lstart, key, strlen(key)))
3560 goto next;
3561
3562 p = strchr(lstart + strlen(key), '=');
3563 if (!p)
3564 goto next;
3565 p++;
3566
3567 while (isblank(*p))
3568 p++;
3569
3570 if (p >= lend)
3571 goto next;
3572
3573 if (!strnequal(p, olddir, strlen(olddir)))
3574 goto next;
3575
3576 /* replace the olddir with newdir */
3577 if (olddirlen >= newdirlen) {
3578 size_t diff = olddirlen - newdirlen;
3579 memcpy(p, newdir, newdirlen);
3580
3581 if (olddirlen != newdirlen) {
3582 memmove(p + newdirlen, p + newdirlen + diff,
3583 strlen(p) - newdirlen - diff + 1);
3584 lend -= diff;
3585 conf->unexpanded_len -= diff;
3586 }
3587 } else {
3588 char *new;
3589 size_t diff = newdirlen - olddirlen;
3590 size_t oldlen = conf->unexpanded_len;
3591 size_t newlen = oldlen + diff;
3592 size_t poffset = p - conf->unexpanded_config;
3593
3594 new = realloc(conf->unexpanded_config, newlen + 1);
3595 if (!new)
3596 return false;
3597
3598 conf->unexpanded_len = newlen;
3599 conf->unexpanded_alloced = newlen + 1;
3600 new[newlen - 1] = '\0';
3601 lend = new + (lend - conf->unexpanded_config);
3602
3603 /* Move over the remainder to make room for the newdir.
3604 */
3605 memmove(new + poffset + newdirlen,
3606 new + poffset + olddirlen,
3607 oldlen - poffset - olddirlen + 1);
3608 conf->unexpanded_config = new;
3609
3610 memcpy(new + poffset, newdir, newdirlen);
3611 lend += diff;
3612 }
3613
3614 next:
3615 lstart = lend;
3616 }
3617
3618 return true;
3619 }
3620
3621 #define DO(cmd) \
3622 { \
3623 if (!(cmd)) { \
3624 ERROR("Error writing to new config"); \
3625 return false; \
3626 } \
3627 }
3628
3629 /* This is called only from clone. We wish to update all hwaddrs in the
3630 * unexpanded config file. We can't/don't want to update any which come from
3631 * lxc.includes (there shouldn't be any).
3632 * We can't just walk the c->lxc-conf->network list because that includes netifs
3633 * from the include files. So we update the ones which we find in the unexp
3634 * config file, then find the original macaddr in the conf->network, and update
3635 * that to the same value.
3636 */
3637 bool network_new_hwaddrs(struct lxc_conf *conf)
3638 {
3639 char *lend, *p, *p2;
3640 char *lstart = conf->unexpanded_config;
3641
3642 if (!conf->unexpanded_config)
3643 return true;
3644
3645 while (*lstart) {
3646 char newhwaddr[18], oldhwaddr[17];
3647 struct lxc_netdev *netdev;
3648
3649 lend = strchr(lstart, '\n');
3650 if (!lend)
3651 lend = lstart + strlen(lstart);
3652 else
3653 lend++;
3654
3655 if (!lxc_config_net_is_hwaddr(lstart)) {
3656 lstart = lend;
3657 continue;
3658 }
3659
3660 p = strchr(lstart, '=');
3661 if (!p) {
3662 lstart = lend;
3663 continue;
3664 }
3665
3666 p++;
3667 while (isblank(*p))
3668 p++;
3669 if (!*p)
3670 return true;
3671
3672 p2 = p;
3673 while (*p2 && !isblank(*p2) && *p2 != '\n')
3674 p2++;
3675
3676 if ((p2 - p) != 17) {
3677 WARN("Bad hwaddr entry");
3678 lstart = lend;
3679 continue;
3680 }
3681
3682 memcpy(oldhwaddr, p, 17);
3683
3684 if (!new_hwaddr(newhwaddr))
3685 return false;
3686
3687 memcpy(p, newhwaddr, 17);
3688 list_for_each_entry(netdev, &conf->netdevs, head) {
3689 if (netdev->hwaddr && memcmp(oldhwaddr, netdev->hwaddr, 17) == 0)
3690 memcpy(netdev->hwaddr, newhwaddr, 17);
3691 }
3692
3693 lstart = lend;
3694 }
3695
3696 return true;
3697 }
3698
3699 static int set_config_ephemeral(const char *key, const char *value,
3700 struct lxc_conf *lxc_conf, void *data)
3701 {
3702 int ret;
3703
3704 if (lxc_config_value_empty(value)) {
3705 lxc_conf->ephemeral = 0;
3706 return 0;
3707 }
3708
3709 ret = lxc_safe_uint(value, &lxc_conf->ephemeral);
3710 if (ret < 0)
3711 return ret;
3712
3713 if (lxc_conf->ephemeral > 1)
3714 return ret_errno(EINVAL);
3715
3716 return 0;
3717 }
3718
3719 static int set_config_log_syslog(const char *key, const char *value,
3720 struct lxc_conf *lxc_conf, void *data)
3721 {
3722 int facility;
3723
3724 if (lxc_conf->syslog)
3725 free_disarm(lxc_conf->syslog);
3726
3727 if (lxc_config_value_empty(value))
3728 return 0;
3729
3730 facility = lxc_syslog_priority_to_int(value);
3731 if (facility == -EINVAL)
3732 return ret_errno(EINVAL);
3733
3734 lxc_log_syslog(facility);
3735
3736 return set_config_string_item(&lxc_conf->syslog, value);
3737 }
3738
3739 static int set_config_no_new_privs(const char *key, const char *value,
3740 struct lxc_conf *lxc_conf, void *data)
3741 {
3742 int ret;
3743 unsigned int v;
3744
3745 if (lxc_config_value_empty(value)) {
3746 lxc_conf->no_new_privs = false;
3747 return 0;
3748 }
3749
3750 ret = lxc_safe_uint(value, &v);
3751 if (ret < 0)
3752 return ret;
3753
3754 if (v > 1)
3755 return ret_errno(EINVAL);
3756
3757 lxc_conf->no_new_privs = v ? true : false;
3758
3759 return 0;
3760 }
3761
3762 /* Callbacks to get configuration items. */
3763 static int get_config_personality(const char *key, char *retv, int inlen,
3764 struct lxc_conf *c, void *data)
3765 {
3766 int fulllen = 0;
3767
3768 if (!retv)
3769 inlen = 0;
3770 else
3771 memset(retv, 0, inlen);
3772
3773 int len = 0;
3774
3775 switch (c->personality) {
3776 case PER_LINUX32:
3777 strprint(retv, inlen, "i686");
3778 break;
3779 case PER_LINUX:
3780 strprint(retv, inlen, "x86_64");
3781 break;
3782 default:
3783 break;
3784 }
3785
3786 return fulllen;
3787 }
3788
3789 static int get_config_pty_max(const char *key, char *retv, int inlen,
3790 struct lxc_conf *c, void *data)
3791 {
3792 return lxc_get_conf_size_t(c, retv, inlen, c->pty_max);
3793 }
3794
3795 static int get_config_tty_max(const char *key, char *retv, int inlen,
3796 struct lxc_conf *c, void *data)
3797 {
3798 return lxc_get_conf_size_t(c, retv, inlen, c->ttys.max);
3799 }
3800
3801 static int get_config_tty_dir(const char *key, char *retv, int inlen,
3802 struct lxc_conf *c, void *data)
3803 {
3804 return lxc_get_conf_str(retv, inlen, c->ttys.dir);
3805 }
3806
3807 static int get_config_apparmor_profile(const char *key, char *retv, int inlen,
3808 struct lxc_conf *c, void *data)
3809 {
3810 #if HAVE_APPARMOR
3811 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
3812 #else
3813 return syserror_set(-EINVAL, "Built without AppArmor support");
3814 #endif
3815 }
3816
3817 static int get_config_apparmor_allow_incomplete(const char *key, char *retv,
3818 int inlen, struct lxc_conf *c,
3819 void *data)
3820 {
3821 #if HAVE_APPARMOR
3822 return lxc_get_conf_int(c, retv, inlen, c->lsm_aa_allow_incomplete);
3823 #else
3824 return syserror_set(-EINVAL, "Built without AppArmor support");
3825 #endif
3826 }
3827
3828 static int get_config_apparmor_allow_nesting(const char *key, char *retv,
3829 int inlen, struct lxc_conf *c,
3830 void *data)
3831 {
3832 #if HAVE_APPARMOR
3833 return lxc_get_conf_int(c, retv, inlen, c->lsm_aa_allow_nesting);
3834 #else
3835 return syserror_set(-EINVAL, "Built without AppArmor support");
3836 #endif
3837 }
3838
3839 static int get_config_apparmor_raw(const char *key, char *retv,
3840 int inlen, struct lxc_conf *c,
3841 void *data)
3842 {
3843 #if HAVE_APPARMOR
3844 int len;
3845 struct string_entry *entry;
3846 int fulllen = 0;
3847
3848 if (!retv)
3849 inlen = 0;
3850 else
3851 memset(retv, 0, inlen);
3852
3853 list_for_each_entry(entry, &c->lsm_aa_raw, head) {
3854 strprint(retv, inlen, "%s\n", entry->val);
3855 }
3856
3857 return fulllen;
3858 #else
3859 return syserror_set(-EINVAL, "Built without AppArmor support");
3860 #endif
3861 }
3862
3863 static int get_config_selinux_context(const char *key, char *retv, int inlen,
3864 struct lxc_conf *c, void *data)
3865 {
3866 #if HAVE_SELINUX
3867 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
3868 #else
3869 return syserror_set(-EINVAL, "Built without SELinux support");
3870 #endif
3871 }
3872
3873 static int get_config_selinux_context_keyring(const char *key, char *retv, int inlen,
3874 struct lxc_conf *c, void *data)
3875 {
3876 #if HAVE_SELINUX
3877 return lxc_get_conf_str(retv, inlen, c->lsm_se_keyring_context);
3878 #else
3879 return syserror_set(-EINVAL, "Built without SELinux support");
3880 #endif
3881 }
3882
3883 static int get_config_keyring_session(const char *key, char *retv, int inlen,
3884 struct lxc_conf *c, void *data)
3885 {
3886 return lxc_get_conf_bool(c, retv, inlen, c->keyring_disable_session);
3887 }
3888
3889
3890 /* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
3891 * just the value(s) will be printed. Since there still could be more than one,
3892 * it is newline-separated.
3893 * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
3894 * have newlines?)
3895 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
3896 * 'lxc.cgroup.subsystem.key = value' format.
3897 */
3898 static int __get_config_cgroup_controller(const char *key, char *retv,
3899 int inlen, struct lxc_conf *c,
3900 int version)
3901 {
3902 int fulllen = 0;
3903 bool get_all = false;
3904 int len;
3905 size_t namespaced_token_len;
3906 char *global_token, *namespaced_token;
3907 struct list_head *list;
3908 struct lxc_cgroup *cgroup;
3909
3910 if (!retv)
3911 inlen = 0;
3912 else
3913 memset(retv, 0, inlen);
3914
3915 if (version == CGROUP2_SUPER_MAGIC) {
3916 global_token = "lxc.cgroup2";
3917 namespaced_token = "lxc.cgroup2.";
3918 namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
3919 list = &c->cgroup2;
3920 } else if (version == CGROUP_SUPER_MAGIC) {
3921 global_token = "lxc.cgroup";
3922 namespaced_token = "lxc.cgroup.";
3923 namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
3924 list = &c->cgroup;
3925 } else {
3926 return ret_errno(EINVAL);
3927 }
3928
3929 if (strequal(key, global_token))
3930 get_all = true;
3931 else if (strnequal(key, namespaced_token, namespaced_token_len))
3932 key += namespaced_token_len;
3933 else
3934 return ret_errno(EINVAL);
3935
3936 list_for_each_entry(cgroup, list, head) {
3937 if (get_all) {
3938 if (version != cgroup->version)
3939 continue;
3940
3941 strprint(retv, inlen, "%s.%s = %s\n", global_token,
3942 cgroup->subsystem, cgroup->value);
3943 } else if (strequal(cgroup->subsystem, key)) {
3944 strprint(retv, inlen, "%s\n", cgroup->value);
3945 }
3946 }
3947
3948 return fulllen;
3949 }
3950
3951 static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
3952 struct lxc_conf *c, void *data)
3953 {
3954 return __get_config_cgroup_controller(key, retv, inlen, c,
3955 CGROUP_SUPER_MAGIC);
3956 }
3957
3958 static int get_config_cgroup2_controller(const char *key, char *retv, int inlen,
3959 struct lxc_conf *c, void *data)
3960 {
3961 return __get_config_cgroup_controller(key, retv, inlen, c,
3962 CGROUP2_SUPER_MAGIC);
3963 }
3964
3965 static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
3966 struct lxc_conf *lxc_conf, void *data)
3967 {
3968 int len;
3969 int fulllen = 0;
3970
3971 if (!strequal(key, "lxc.cgroup.dir"))
3972 return ret_errno(EINVAL);
3973
3974 if (!retv)
3975 inlen = 0;
3976 else
3977 memset(retv, 0, inlen);
3978
3979 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.dir);
3980
3981 return fulllen;
3982 }
3983
3984 static int get_config_cgroup_monitor_dir(const char *key, char *retv, int inlen,
3985 struct lxc_conf *lxc_conf, void *data)
3986 {
3987 int len;
3988 int fulllen = 0;
3989
3990 if (!retv)
3991 inlen = 0;
3992 else
3993 memset(retv, 0, inlen);
3994
3995 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.monitor_dir);
3996
3997 return fulllen;
3998 }
3999
4000 static int get_config_cgroup_monitor_pivot_dir(const char *key, char *retv, int inlen,
4001 struct lxc_conf *lxc_conf, void *data)
4002 {
4003 int len;
4004 int fulllen = 0;
4005
4006 if (!retv)
4007 inlen = 0;
4008 else
4009 memset(retv, 0, inlen);
4010
4011 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.monitor_pivot_dir);
4012
4013 return fulllen;
4014 }
4015
4016 static int get_config_cgroup_container_dir(const char *key, char *retv,
4017 int inlen,
4018 struct lxc_conf *lxc_conf,
4019 void *data)
4020 {
4021 int len;
4022 int fulllen = 0;
4023
4024 if (!retv)
4025 inlen = 0;
4026 else
4027 memset(retv, 0, inlen);
4028
4029 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.container_dir);
4030
4031 return fulllen;
4032 }
4033
4034 static int get_config_cgroup_container_inner_dir(const char *key, char *retv,
4035 int inlen,
4036 struct lxc_conf *lxc_conf,
4037 void *data)
4038 {
4039 int len;
4040 int fulllen = 0;
4041
4042 if (!retv)
4043 inlen = 0;
4044 else
4045 memset(retv, 0, inlen);
4046
4047 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.namespace_dir);
4048
4049 return fulllen;
4050 }
4051
4052 static inline int get_config_cgroup_relative(const char *key, char *retv,
4053 int inlen, struct lxc_conf *lxc_conf,
4054 void *data)
4055 {
4056 return lxc_get_conf_int(lxc_conf, retv, inlen,
4057 lxc_conf->cgroup_meta.relative);
4058 }
4059
4060 static int get_config_idmaps(const char *key, char *retv, int inlen,
4061 struct lxc_conf *c, void *data)
4062 {
4063 struct id_map *map;
4064 int len, listlen, ret;
4065 int fulllen = 0;
4066 /* "u 1000 1000000 65536"
4067 *
4068 * let's render this as
4069 *
4070 * sizeof(char)
4071 * +
4072 * sizeof(" ")
4073 * +
4074 * sizeof(uint32_t)
4075 * +
4076 * sizeof(" ")
4077 * +
4078 * sizeof(uint32_t)
4079 * +
4080 * sizeof(" ")
4081 * +
4082 * sizeof(uint32_t)
4083 * +
4084 * \0
4085 */
4086 #define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
4087 char buf[__LXC_IDMAP_STR_BUF];
4088
4089 if (!retv)
4090 inlen = 0;
4091 else
4092 memset(retv, 0, inlen);
4093
4094 listlen = list_len(map, &c->id_map, head);
4095 list_for_each_entry(map, &c->id_map, head) {
4096 ret = strnprintf(buf, sizeof(buf), "%c %lu %lu %lu",
4097 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
4098 map->nsid, map->hostid, map->range);
4099 if (ret < 0)
4100 return ret_errno(EIO);
4101
4102 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
4103 }
4104
4105 return fulllen;
4106 }
4107
4108 static int get_config_log_level(const char *key, char *retv, int inlen,
4109 struct lxc_conf *c, void *data)
4110 {
4111 const char *v;
4112 v = lxc_log_priority_to_string(c->loglevel);
4113 return lxc_get_conf_str(retv, inlen, v);
4114 }
4115
4116 static int get_config_log_file(const char *key, char *retv, int inlen,
4117 struct lxc_conf *c, void *data)
4118 {
4119 return lxc_get_conf_str(retv, inlen, c->logfile);
4120 }
4121
4122 static int get_config_mount_fstab(const char *key, char *retv, int inlen,
4123 struct lxc_conf *c, void *data)
4124 {
4125 return lxc_get_conf_str(retv, inlen, c->fstab);
4126 }
4127
4128 static int get_config_mount_auto(const char *key, char *retv, int inlen,
4129 struct lxc_conf *c, void *data)
4130 {
4131 int len, fulllen = 0;
4132 const char *sep = "";
4133
4134 if (!retv)
4135 inlen = 0;
4136 else
4137 memset(retv, 0, inlen);
4138
4139 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
4140 return 0;
4141
4142 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
4143 case LXC_AUTO_PROC_MIXED:
4144 strprint(retv, inlen, "%sproc:mixed", sep);
4145 sep = " ";
4146 break;
4147 case LXC_AUTO_PROC_RW:
4148 strprint(retv, inlen, "%sproc:rw", sep);
4149 sep = " ";
4150 break;
4151 default:
4152 break;
4153 }
4154
4155 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
4156 case LXC_AUTO_SYS_RO:
4157 strprint(retv, inlen, "%ssys:ro", sep);
4158 sep = " ";
4159 break;
4160 case LXC_AUTO_SYS_RW:
4161 strprint(retv, inlen, "%ssys:rw", sep);
4162 sep = " ";
4163 break;
4164 case LXC_AUTO_SYS_MIXED:
4165 strprint(retv, inlen, "%ssys:mixed", sep);
4166 sep = " ";
4167 break;
4168 default:
4169 break;
4170 }
4171
4172 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
4173 case LXC_AUTO_CGROUP_NOSPEC:
4174 strprint(retv, inlen, "%scgroup", sep);
4175 break;
4176 case LXC_AUTO_CGROUP_MIXED:
4177 strprint(retv, inlen, "%scgroup:mixed", sep);
4178 break;
4179 case LXC_AUTO_CGROUP_RO:
4180 strprint(retv, inlen, "%scgroup:ro", sep);
4181 break;
4182 case LXC_AUTO_CGROUP_RW:
4183 strprint(retv, inlen, "%scgroup:rw", sep);
4184 break;
4185 case LXC_AUTO_CGROUP_FULL_NOSPEC:
4186 strprint(retv, inlen, "%scgroup-full", sep);
4187 break;
4188 case LXC_AUTO_CGROUP_FULL_MIXED:
4189 strprint(retv, inlen, "%scgroup-full:mixed", sep);
4190 break;
4191 case LXC_AUTO_CGROUP_FULL_RO:
4192 strprint(retv, inlen, "%scgroup-full:ro", sep);
4193 break;
4194 case LXC_AUTO_CGROUP_FULL_RW:
4195 strprint(retv, inlen, "%scgroup-full:rw", sep);
4196 break;
4197 default:
4198 break;
4199 }
4200
4201 return fulllen;
4202 }
4203
4204 static int get_config_mount(const char *key, char *retv, int inlen,
4205 struct lxc_conf *c, void *data)
4206 {
4207 int len, fulllen = 0;
4208 struct string_entry *entry;
4209
4210 if (!retv)
4211 inlen = 0;
4212 else
4213 memset(retv, 0, inlen);
4214
4215 list_for_each_entry(entry, &c->mount_entries, head) {
4216 strprint(retv, inlen, "%s\n", entry->val);
4217 }
4218
4219 return fulllen;
4220 }
4221
4222 static int get_config_rootfs_path(const char *key, char *retv, int inlen,
4223 struct lxc_conf *c, void *data)
4224 {
4225 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
4226 }
4227
4228 static int get_config_rootfs_managed(const char *key, char *retv, int inlen,
4229 struct lxc_conf *c, void *data)
4230 {
4231 return lxc_get_conf_bool(c, retv, inlen, c->rootfs.managed);
4232 }
4233
4234 static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
4235 struct lxc_conf *c, void *data)
4236 {
4237 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
4238 }
4239
4240 static int get_config_rootfs_options(const char *key, char *retv, int inlen,
4241 struct lxc_conf *c, void *data)
4242 {
4243 return lxc_get_conf_str(retv, inlen, c->rootfs.mnt_opts.raw_options);
4244 }
4245
4246 static int get_config_uts_name(const char *key, char *retv, int inlen,
4247 struct lxc_conf *c, void *data)
4248 {
4249 return lxc_get_conf_str(
4250 retv, inlen,
4251 c->utsname ? c->utsname->nodename : NULL);
4252 }
4253
4254 static int get_config_hooks(const char *key, char *retv, int inlen,
4255 struct lxc_conf *c, void *data)
4256 {
4257 char *subkey;
4258 int len, fulllen = 0, found = -1;
4259 struct string_entry *entry;
4260 int i;
4261
4262 subkey = strchr(key, '.');
4263 if (!subkey)
4264 return ret_errno(EINVAL);
4265
4266 subkey = strchr(subkey + 1, '.');
4267 if (!subkey)
4268 return ret_errno(EINVAL);
4269 subkey++;
4270 if (*subkey == '\0')
4271 return ret_errno(EINVAL);
4272
4273 for (i = 0; i < NUM_LXC_HOOKS; i++) {
4274 if (strequal(lxchook_names[i], subkey)) {
4275 found = i;
4276 break;
4277 }
4278 }
4279
4280 if (found == -1)
4281 return ret_errno(EINVAL);
4282
4283 if (!retv)
4284 inlen = 0;
4285 else
4286 memset(retv, 0, inlen);
4287
4288 list_for_each_entry(entry, &c->hooks[found], head) {
4289 strprint(retv, inlen, "%s\n", entry->val);
4290 }
4291
4292 return fulllen;
4293 }
4294
4295 static int get_config_hooks_version(const char *key, char *retv, int inlen,
4296 struct lxc_conf *c, void *data)
4297 {
4298 return lxc_get_conf_int(c, retv, inlen, c->hooks_version);
4299 }
4300
4301 static int get_config_net(const char *key, char *retv, int inlen,
4302 struct lxc_conf *c, void *data)
4303 {
4304 int len, fulllen = 0;
4305 struct lxc_netdev *netdev;
4306
4307 if (!retv)
4308 inlen = 0;
4309 else
4310 memset(retv, 0, inlen);
4311
4312 list_for_each_entry(netdev, &c->netdevs, head) {
4313 const char *t = lxc_net_type_to_str(netdev->type);
4314 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
4315 }
4316
4317 return fulllen;
4318 }
4319
4320 static int get_config_cap_drop(const char *key, char *retv, int inlen,
4321 struct lxc_conf *c, void *data)
4322 {
4323 int len, fulllen = 0;
4324 struct cap_entry *cap;
4325
4326 if (!retv)
4327 inlen = 0;
4328 else
4329 memset(retv, 0, inlen);
4330
4331 list_for_each_entry(cap, &c->caps.list, head) {
4332 strprint(retv, inlen, "%s\n", cap->cap_name);
4333 }
4334
4335 return fulllen;
4336 }
4337
4338 static int get_config_cap_keep(const char *key, char *retv, int inlen,
4339 struct lxc_conf *c, void *data)
4340 {
4341 int len, fulllen = 0;
4342 struct cap_entry *cap;
4343
4344 if (!retv)
4345 inlen = 0;
4346 else
4347 memset(retv, 0, inlen);
4348
4349 list_for_each_entry(cap, &c->caps.list, head) {
4350 strprint(retv, inlen, "%s\n", cap->cap_name);
4351 }
4352
4353 return fulllen;
4354 }
4355
4356 static int get_config_console_path(const char *key, char *retv, int inlen,
4357 struct lxc_conf *c, void *data)
4358 {
4359 return lxc_get_conf_str(retv, inlen, c->console.path);
4360 }
4361
4362 static int get_config_console_logfile(const char *key, char *retv, int inlen,
4363 struct lxc_conf *c, void *data)
4364 {
4365 return lxc_get_conf_str(retv, inlen, c->console.log_path);
4366 }
4367
4368 static int get_config_console_rotate(const char *key, char *retv, int inlen,
4369 struct lxc_conf *c, void *data)
4370 {
4371 return lxc_get_conf_int(c, retv, inlen, c->console.log_rotate);
4372 }
4373
4374
4375 static int get_config_console_buffer_size(const char *key, char *retv,
4376 int inlen, struct lxc_conf *c,
4377 void *data)
4378 {
4379 return lxc_get_conf_uint64(c, retv, inlen, c->console.buffer_size);
4380 }
4381
4382 static int get_config_console_size(const char *key, char *retv, int inlen,
4383 struct lxc_conf *c, void *data)
4384 {
4385 return lxc_get_conf_uint64(c, retv, inlen, c->console.log_size);
4386 }
4387
4388 static int get_config_seccomp_allow_nesting(const char *key, char *retv,
4389 int inlen, struct lxc_conf *c,
4390 void *data)
4391 {
4392 #ifdef HAVE_SECCOMP
4393 return lxc_get_conf_int(c, retv, inlen, c->seccomp.allow_nesting);
4394 #else
4395 return ret_errno(ENOSYS);
4396 #endif
4397 }
4398
4399 static int get_config_seccomp_notify_cookie(const char *key, char *retv, int inlen,
4400 struct lxc_conf *c, void *data)
4401 {
4402 #ifdef HAVE_SECCOMP_NOTIFY
4403 return lxc_get_conf_str(retv, inlen, c->seccomp.notifier.cookie);
4404 #else
4405 return ret_errno(ENOSYS);
4406 #endif
4407 }
4408
4409 static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inlen,
4410 struct lxc_conf *c, void *data)
4411 {
4412 #ifdef HAVE_SECCOMP_NOTIFY
4413 return lxc_get_conf_str(retv, inlen,
4414 (c->seccomp.notifier.proxy_addr.sun_path[0]) == '/'
4415 ? &c->seccomp.notifier.proxy_addr.sun_path[0]
4416 : &c->seccomp.notifier.proxy_addr.sun_path[1]);
4417 #else
4418 return ret_errno(ENOSYS);
4419 #endif
4420 }
4421
4422 static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
4423 struct lxc_conf *c, void *data)
4424 {
4425 #ifdef HAVE_SECCOMP
4426 return lxc_get_conf_str(retv, inlen, c->seccomp.seccomp);
4427 #else
4428 return ret_errno(ENOSYS);
4429 #endif
4430 }
4431
4432 static int get_config_autodev(const char *key, char *retv, int inlen,
4433 struct lxc_conf *c, void *data)
4434 {
4435 return lxc_get_conf_int(c, retv, inlen, c->autodev);
4436 }
4437
4438 static int get_config_autodev_tmpfs_size(const char *key, char *retv, int inlen,
4439 struct lxc_conf *c, void *data)
4440 {
4441 return lxc_get_conf_int(c, retv, inlen, c->autodevtmpfssize);
4442 }
4443
4444 static int get_config_signal_halt(const char *key, char *retv, int inlen,
4445 struct lxc_conf *c, void *data)
4446 {
4447 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
4448 }
4449
4450 static int get_config_signal_reboot(const char *key, char *retv, int inlen,
4451 struct lxc_conf *c, void *data)
4452 {
4453 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
4454 }
4455
4456 static int get_config_signal_stop(const char *key, char *retv, int inlen,
4457 struct lxc_conf *c, void *data)
4458 {
4459 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
4460 }
4461
4462 static int get_config_start(const char *key, char *retv, int inlen,
4463 struct lxc_conf *c, void *data)
4464 {
4465 if (strequal(key + 10, "auto"))
4466 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
4467 else if (strequal(key + 10, "delay"))
4468 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
4469 else if (strequal(key + 10, "order"))
4470 return lxc_get_conf_int(c, retv, inlen, c->start_order);
4471
4472 return ret_errno(EINVAL);
4473 }
4474
4475 static int get_config_log_syslog(const char *key, char *retv, int inlen,
4476 struct lxc_conf *c, void *data)
4477 {
4478 return lxc_get_conf_str(retv, inlen, c->syslog);
4479 }
4480
4481 static int get_config_monitor(const char *key, char *retv, int inlen,
4482 struct lxc_conf *c, void *data)
4483 {
4484 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
4485 }
4486
4487 static int get_config_monitor_signal_pdeath(const char *key, char *retv,
4488 int inlen, struct lxc_conf *c,
4489 void *data)
4490 {
4491 return lxc_get_conf_int(c, retv, inlen, c->monitor_signal_pdeath);
4492 }
4493
4494 static int get_config_group(const char *key, char *retv, int inlen,
4495 struct lxc_conf *c, void *data)
4496 {
4497 int len, fulllen = 0;
4498 struct string_entry *entry;
4499
4500 if (!retv)
4501 inlen = 0;
4502 else
4503 memset(retv, 0, inlen);
4504
4505 list_for_each_entry(entry, &c->groups, head) {
4506 strprint(retv, inlen, "%s\n", entry->val);
4507 }
4508
4509 return fulllen;
4510 }
4511
4512 static int get_config_environment(const char *key, char *retv, int inlen,
4513 struct lxc_conf *c, void *data)
4514 {
4515 int len, fulllen = 0;
4516 struct environment_entry *env;
4517
4518 if (!retv)
4519 inlen = 0;
4520 else
4521 memset(retv, 0, inlen);
4522
4523 list_for_each_entry(env, &c->environment, head) {
4524 strprint(retv, inlen, "%s=%s\n", env->key, env->val);
4525 }
4526
4527 return fulllen;
4528 }
4529
4530 static int get_config_execute_cmd(const char *key, char *retv, int inlen,
4531 struct lxc_conf *c, void *data)
4532 {
4533 return lxc_get_conf_str(retv, inlen, c->execute_cmd);
4534 }
4535
4536 static int get_config_init_cmd(const char *key, char *retv, int inlen,
4537 struct lxc_conf *c, void *data)
4538 {
4539 return lxc_get_conf_str(retv, inlen, c->init_cmd);
4540 }
4541
4542 static int get_config_init_cwd(const char *key, char *retv, int inlen,
4543 struct lxc_conf *c, void *data)
4544 {
4545 return lxc_get_conf_str(retv, inlen, c->init_cwd);
4546 }
4547
4548 static int get_config_init_uid(const char *key, char *retv, int inlen,
4549 struct lxc_conf *c, void *data)
4550 {
4551 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
4552 }
4553
4554 static int get_config_init_gid(const char *key, char *retv, int inlen,
4555 struct lxc_conf *c, void *data)
4556 {
4557 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
4558 }
4559
4560 static int get_config_init_groups(const char *key, char *retv, int inlen,
4561 struct lxc_conf *c, void *data)
4562 {
4563 int fulllen = 0, len;
4564
4565 if (!retv)
4566 inlen = 0;
4567 else
4568 memset(retv, 0, inlen);
4569
4570 if (c->init_groups.size == 0)
4571 return 0;
4572
4573 for (size_t i = 0; i < c->init_groups.size; i++)
4574 strprint(retv, inlen, "%s%d", (i > 0) ? "," : "",
4575 c->init_groups.list[i]);
4576
4577 return fulllen;
4578 }
4579
4580 static int get_config_ephemeral(const char *key, char *retv, int inlen,
4581 struct lxc_conf *c, void *data)
4582 {
4583 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
4584 }
4585
4586 static int get_config_no_new_privs(const char *key, char *retv, int inlen,
4587 struct lxc_conf *c, void *data)
4588 {
4589 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
4590 }
4591
4592 /* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
4593 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
4594 * printed, in 'lxc.prlimit.resource = value' format.
4595 */
4596 static int get_config_prlimit(const char *key, char *retv, int inlen,
4597 struct lxc_conf *c, void *data)
4598 {
4599 int fulllen = 0, len;
4600 bool get_all = false;
4601 struct lxc_limit *lim;
4602
4603 if (!retv)
4604 inlen = 0;
4605 else
4606 memset(retv, 0, inlen);
4607
4608 if (strequal(key, "lxc.prlimit"))
4609 get_all = true;
4610 else if (strnequal(key, "lxc.prlimit.", 12))
4611 key += 12;
4612 else
4613 return ret_errno(EINVAL);
4614
4615 list_for_each_entry(lim, &c->limits, head) {
4616 /* 2 colon separated 64 bit integers or the word 'unlimited' */
4617 char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
4618 int partlen;
4619
4620 if (lim->limit.rlim_cur == RLIM_INFINITY) {
4621 memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1);
4622 partlen = STRLITERALLEN("unlimited");
4623 } else {
4624 partlen = sprintf(buf, "%" PRIu64,
4625 (uint64_t)lim->limit.rlim_cur);
4626 }
4627
4628 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
4629 if (lim->limit.rlim_max == RLIM_INFINITY)
4630 memcpy(buf + partlen, ":unlimited",
4631 STRLITERALLEN(":unlimited") + 1);
4632 else
4633 sprintf(buf + partlen, ":%" PRIu64,
4634 (uint64_t)lim->limit.rlim_max);
4635 }
4636
4637 if (get_all) {
4638 strprint(retv, inlen, "lxc.prlimit.%s = %s\n",
4639 lim->resource, buf);
4640 } else if (strequal(lim->resource, key)) {
4641 strprint(retv, inlen, "%s", buf);
4642 }
4643 }
4644
4645 return fulllen;
4646 }
4647
4648 /* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
4649 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
4650 * entries will be printed, in 'lxc.sysctl.key = value' format.
4651 */
4652 static int get_config_sysctl(const char *key, char *retv, int inlen,
4653 struct lxc_conf *c, void *data)
4654 {
4655 int fulllen = 0;
4656 bool get_all = false;
4657 int len;
4658 struct lxc_sysctl *sysctl;
4659
4660 if (!retv)
4661 inlen = 0;
4662 else
4663 memset(retv, 0, inlen);
4664
4665 if (strequal(key, "lxc.sysctl"))
4666 get_all = true;
4667 else if (strnequal(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
4668 key += STRLITERALLEN("lxc.sysctl.");
4669 else
4670 return ret_errno(EINVAL);
4671
4672 list_for_each_entry(sysctl, &c->sysctls, head) {
4673 if (get_all) {
4674 strprint(retv, inlen, "lxc.sysctl.%s = %s\n", sysctl->key,
4675 sysctl->value);
4676 } else if (strequal(sysctl->key, key)) {
4677 strprint(retv, inlen, "%s", sysctl->value);
4678 }
4679 }
4680
4681 return fulllen;
4682 }
4683
4684 static int get_config_proc(const char *key, char *retv, int inlen,
4685 struct lxc_conf *c, void *data)
4686 {
4687 int fulllen = 0;
4688 bool get_all = false;
4689 int len;
4690 struct lxc_proc *proc;
4691
4692 if (!retv)
4693 inlen = 0;
4694 else
4695 memset(retv, 0, inlen);
4696
4697 if (strequal(key, "lxc.proc"))
4698 get_all = true;
4699 else if (strnequal(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
4700 key += STRLITERALLEN("lxc.proc.");
4701 else
4702 return ret_errno(EINVAL);
4703
4704 list_for_each_entry(proc, &c->procs, head) {
4705 if (get_all) {
4706 strprint(retv, inlen, "lxc.proc.%s = %s\n",
4707 proc->filename, proc->value);
4708 } else if (strequal(proc->filename, key)) {
4709 strprint(retv, inlen, "%s", proc->value);
4710 }
4711 }
4712
4713 return fulllen;
4714 }
4715
4716 static int get_config_namespace_clone(const char *key, char *retv, int inlen,
4717 struct lxc_conf *c, void *data)
4718 {
4719 int i, len;
4720 int fulllen = 0;
4721
4722 if (!retv)
4723 inlen = 0;
4724 else
4725 memset(retv, 0, inlen);
4726
4727 for (i = 0; i < LXC_NS_MAX; i++) {
4728 if (c->ns_clone & ns_info[i].clone_flag)
4729 strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
4730 }
4731
4732 return fulllen;
4733 }
4734
4735 static int get_config_namespace_keep(const char *key, char *retv, int inlen,
4736 struct lxc_conf *c, void *data)
4737 {
4738 int i, len;
4739 int fulllen = 0;
4740
4741 if (!retv)
4742 inlen = 0;
4743 else
4744 memset(retv, 0, inlen);
4745
4746 for (i = 0; i < LXC_NS_MAX; i++) {
4747 if (c->ns_keep & ns_info[i].clone_flag)
4748 strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
4749 }
4750
4751 return fulllen;
4752 }
4753
4754 static int get_config_time_offset_boot(const char *key, char *retv, int inlen, struct lxc_conf *c,
4755 void *data)
4756 {
4757 int len;
4758 int fulllen = 0;
4759
4760 if (!retv)
4761 inlen = 0;
4762 else
4763 memset(retv, 0, inlen);
4764
4765 if (c->timens.s_boot) {
4766 strprint(retv, inlen, "%" PRId64 " s\n", c->timens.s_boot);
4767 } else {
4768 strprint(retv, inlen, "%" PRId64 " ns\n", c->timens.ns_boot);
4769 }
4770
4771 return fulllen;
4772 }
4773
4774 static int get_config_time_offset_monotonic(const char *key, char *retv, int inlen,
4775 struct lxc_conf *c, void *data)
4776 {
4777 int len;
4778 int fulllen = 0;
4779
4780 if (!retv)
4781 inlen = 0;
4782 else
4783 memset(retv, 0, inlen);
4784
4785 if (c->timens.s_monotonic) {
4786 strprint(retv, inlen, "%" PRId64 "s\n", c->timens.s_monotonic);
4787 } else {
4788 strprint(retv, inlen, "%" PRId64 "ns\n", c->timens.ns_monotonic);
4789 }
4790
4791 return fulllen;
4792 }
4793
4794 static int get_config_namespace_share(const char *key, char *retv, int inlen,
4795 struct lxc_conf *c, void *data)
4796 {
4797 int len, ns_idx;
4798 const char *namespace;
4799 int fulllen = 0;
4800
4801 if (!retv)
4802 inlen = 0;
4803 else
4804 memset(retv, 0, inlen);
4805
4806 namespace = key + STRLITERALLEN("lxc.namespace.share.");
4807 if (is_empty_string(namespace))
4808 return ret_errno(EINVAL);
4809
4810 ns_idx = lxc_namespace_2_ns_idx(namespace);
4811 if (ns_idx < 0)
4812 return ns_idx;
4813
4814 strprint(retv, inlen, "%s", c->ns_share[ns_idx]);
4815
4816 return fulllen;
4817 }
4818
4819 /* Callbacks to clear config items. */
4820 static inline int clr_config_personality(const char *key, struct lxc_conf *c,
4821 void *data)
4822 {
4823 c->personality = -1;
4824 return 0;
4825 }
4826
4827 static inline int clr_config_pty_max(const char *key, struct lxc_conf *c,
4828 void *data)
4829 {
4830 c->pty_max = 0;
4831 return 0;
4832 }
4833
4834 static inline int clr_config_tty_max(const char *key, struct lxc_conf *c,
4835 void *data)
4836 {
4837 c->ttys.tty = 0;
4838 return 0;
4839 }
4840
4841 static inline int clr_config_tty_dir(const char *key, struct lxc_conf *c,
4842 void *data)
4843 {
4844 free_disarm(c->ttys.dir);
4845 return 0;
4846 }
4847
4848 static inline int clr_config_apparmor_profile(const char *key,
4849 struct lxc_conf *c, void *data)
4850 {
4851 #if HAVE_APPARMOR
4852 free_disarm(c->lsm_aa_profile);
4853 return 0;
4854 #else
4855 return syserror_set(-EINVAL, "Built without AppArmor support");
4856 #endif
4857 }
4858
4859 static inline int clr_config_apparmor_allow_incomplete(const char *key,
4860 struct lxc_conf *c,
4861 void *data)
4862 {
4863 #if HAVE_APPARMOR
4864 c->lsm_aa_allow_incomplete = 0;
4865 return 0;
4866 #else
4867 return syserror_set(-EINVAL, "Built without AppArmor support");
4868 #endif
4869 }
4870
4871 static inline int clr_config_apparmor_allow_nesting(const char *key,
4872 struct lxc_conf *c,
4873 void *data)
4874 {
4875 #if HAVE_APPARMOR
4876 c->lsm_aa_allow_nesting = 0;
4877 return 0;
4878 #else
4879 return syserror_set(-EINVAL, "Built without AppArmor support");
4880 #endif
4881 }
4882
4883 static inline int clr_config_apparmor_raw(const char *key,
4884 struct lxc_conf *c,
4885 void *data)
4886 {
4887 #if HAVE_APPARMOR
4888 return lxc_clear_apparmor_raw(c);
4889 #else
4890 return syserror_set(-EINVAL, "Built without AppArmor support");
4891 #endif
4892 }
4893
4894 static inline int clr_config_selinux_context(const char *key,
4895 struct lxc_conf *c, void *data)
4896 {
4897 #if HAVE_SELINUX
4898 free_disarm(c->lsm_se_context);
4899 return 0;
4900 #else
4901 return syserror_set(-EINVAL, "Built without SELinux support");
4902 #endif
4903 }
4904
4905 static inline int clr_config_selinux_context_keyring(const char *key,
4906 struct lxc_conf *c, void *data)
4907 {
4908 #if HAVE_SELINUX
4909 free_disarm(c->lsm_se_keyring_context);
4910 return 0;
4911 #else
4912 return syserror_set(-EINVAL, "Built without SELinux support");
4913 #endif
4914 }
4915
4916 static inline int clr_config_keyring_session(const char *key,
4917 struct lxc_conf *c, void *data)
4918 {
4919 c->keyring_disable_session = false;
4920 return 0;
4921 }
4922
4923 static inline int clr_config_cgroup_controller(const char *key,
4924 struct lxc_conf *c, void *data)
4925 {
4926 return lxc_clear_cgroups(c, key, CGROUP_SUPER_MAGIC);
4927 }
4928
4929 static inline int clr_config_cgroup2_controller(const char *key,
4930 struct lxc_conf *c, void *data)
4931 {
4932 return lxc_clear_cgroups(c, key, CGROUP2_SUPER_MAGIC);
4933 }
4934
4935 static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
4936 void *data)
4937 {
4938 if (!strequal(key, "lxc.cgroup.dir"))
4939 return ret_errno(EINVAL);
4940
4941 if (lxc_conf->cgroup_meta.dir)
4942 free_disarm(lxc_conf->cgroup_meta.dir);
4943
4944 return 0;
4945 }
4946
4947 static int clr_config_cgroup_monitor_dir(const char *key,
4948 struct lxc_conf *lxc_conf,
4949 void *data)
4950 {
4951 free_disarm(lxc_conf->cgroup_meta.monitor_dir);
4952 return 0;
4953 }
4954
4955 static int clr_config_cgroup_monitor_pivot_dir(const char *key,
4956 struct lxc_conf *lxc_conf,
4957 void *data)
4958 {
4959 free_disarm(lxc_conf->cgroup_meta.monitor_pivot_dir);
4960 return 0;
4961 }
4962
4963 static int clr_config_cgroup_container_dir(const char *key,
4964 struct lxc_conf *lxc_conf,
4965 void *data)
4966 {
4967 free_disarm(lxc_conf->cgroup_meta.container_dir);
4968 return 0;
4969 }
4970
4971 static int clr_config_cgroup_container_inner_dir(const char *key,
4972 struct lxc_conf *lxc_conf,
4973 void *data)
4974 {
4975 free_disarm(lxc_conf->cgroup_meta.namespace_dir);
4976 return 0;
4977 }
4978
4979 static inline int clr_config_cgroup_relative(const char *key,
4980 struct lxc_conf *lxc_conf,
4981 void *data)
4982 {
4983 lxc_conf->cgroup_meta.relative = false;
4984 return 0;
4985 }
4986
4987 static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
4988 void *data)
4989 {
4990 return lxc_clear_idmaps(c);
4991 }
4992
4993 static inline int clr_config_log_level(const char *key, struct lxc_conf *c,
4994 void *data)
4995 {
4996 c->loglevel = LXC_LOG_LEVEL_NOTSET;
4997 return 0;
4998 }
4999
5000 static inline int clr_config_log_file(const char *key, struct lxc_conf *c,
5001 void *data)
5002 {
5003 free_disarm(c->logfile);
5004 return 0;
5005 }
5006
5007 static inline int clr_config_mount(const char *key, struct lxc_conf *c,
5008 void *data)
5009 {
5010 return lxc_clear_mount_entries(c);
5011 }
5012
5013 static inline int clr_config_mount_auto(const char *key, struct lxc_conf *c,
5014 void *data)
5015 {
5016 return lxc_clear_automounts(c);
5017 }
5018
5019 static inline int clr_config_mount_fstab(const char *key, struct lxc_conf *c,
5020 void *data)
5021 {
5022 free_disarm(c->fstab);
5023 return 0;
5024 }
5025
5026 static inline int clr_config_rootfs_path(const char *key, struct lxc_conf *c,
5027 void *data)
5028 {
5029 free_disarm(c->rootfs.path);
5030 return 0;
5031 }
5032
5033 static inline int clr_config_rootfs_managed(const char *key, struct lxc_conf *c,
5034 void *data)
5035 {
5036 c->rootfs.managed = true;
5037 return 0;
5038 }
5039
5040 static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
5041 void *data)
5042 {
5043 free_disarm(c->rootfs.mount);
5044 return 0;
5045 }
5046
5047 static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
5048 void *data)
5049 {
5050 put_lxc_mount_options(&c->rootfs.mnt_opts);
5051
5052 return 0;
5053 }
5054
5055 static inline int clr_config_uts_name(const char *key, struct lxc_conf *c,
5056 void *data)
5057 {
5058 free_disarm(c->utsname);
5059 return 0;
5060 }
5061
5062 static inline int clr_config_hooks(const char *key, struct lxc_conf *c,
5063 void *data)
5064 {
5065 return lxc_clear_hooks(c, key);
5066 }
5067
5068 static inline int clr_config_hooks_version(const char *key, struct lxc_conf *c,
5069 void *data)
5070 {
5071 /* default to legacy hooks version */
5072 c->hooks_version = 0;
5073 return 0;
5074 }
5075
5076 static inline int clr_config_net(const char *key, struct lxc_conf *c,
5077 void *data)
5078 {
5079 lxc_free_networks(c);
5080
5081 return 0;
5082 }
5083
5084 static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c,
5085 void *data)
5086 {
5087 return lxc_clear_config_caps(c);
5088 }
5089
5090 static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
5091 void *data)
5092 {
5093 return lxc_clear_config_caps(c);
5094 }
5095
5096 static inline int clr_config_console_path(const char *key, struct lxc_conf *c,
5097 void *data)
5098 {
5099 free_disarm(c->console.path);
5100 return 0;
5101 }
5102
5103 static inline int clr_config_console_logfile(const char *key,
5104 struct lxc_conf *c, void *data)
5105 {
5106 free_disarm(c->console.log_path);
5107 return 0;
5108 }
5109
5110 static inline int clr_config_console_rotate(const char *key, struct lxc_conf *c,
5111 void *data)
5112 {
5113 c->console.log_rotate = 0;
5114 return 0;
5115 }
5116
5117 static inline int clr_config_console_buffer_size(const char *key,
5118 struct lxc_conf *c, void *data)
5119 {
5120 c->console.buffer_size = 0;
5121 return 0;
5122 }
5123
5124 static inline int clr_config_console_size(const char *key, struct lxc_conf *c,
5125 void *data)
5126 {
5127 c->console.log_size = 0;
5128 return 0;
5129 }
5130
5131 static inline int clr_config_seccomp_allow_nesting(const char *key,
5132 struct lxc_conf *c, void *data)
5133 {
5134 #ifdef HAVE_SECCOMP
5135 c->seccomp.allow_nesting = 0;
5136 return 0;
5137 #else
5138 return ret_errno(ENOSYS);
5139 #endif
5140 }
5141
5142 static inline int clr_config_seccomp_notify_cookie(const char *key,
5143 struct lxc_conf *c, void *data)
5144 {
5145 #ifdef HAVE_SECCOMP_NOTIFY
5146 free_disarm(c->seccomp.notifier.cookie);
5147 return 0;
5148 #else
5149 return ret_errno(ENOSYS);
5150 #endif
5151 }
5152
5153 static inline int clr_config_seccomp_notify_proxy(const char *key,
5154 struct lxc_conf *c, void *data)
5155 {
5156 #ifdef HAVE_SECCOMP_NOTIFY
5157 memset(&c->seccomp.notifier.proxy_addr, 0,
5158 sizeof(c->seccomp.notifier.proxy_addr));
5159 return 0;
5160 #else
5161 return ret_errno(ENOSYS);
5162 #endif
5163 }
5164
5165 static inline int clr_config_seccomp_profile(const char *key,
5166 struct lxc_conf *c, void *data)
5167 {
5168 free_disarm(c->seccomp.seccomp);
5169 return 0;
5170 }
5171
5172 static inline int clr_config_autodev(const char *key, struct lxc_conf *c,
5173 void *data)
5174 {
5175 c->autodev = 1;
5176 return 0;
5177 }
5178
5179 static inline int clr_config_autodev_tmpfs_size(const char *key, struct lxc_conf *c,
5180 void *data)
5181 {
5182 c->autodevtmpfssize = 500000;
5183 return 0;
5184 }
5185
5186 static inline int clr_config_signal_halt(const char *key, struct lxc_conf *c,
5187 void *data)
5188 {
5189 c->haltsignal = 0;
5190 return 0;
5191 }
5192
5193 static inline int clr_config_signal_reboot(const char *key, struct lxc_conf *c,
5194 void *data)
5195 {
5196 c->rebootsignal = 0;
5197 return 0;
5198 }
5199
5200 static inline int clr_config_signal_stop(const char *key, struct lxc_conf *c,
5201 void *data)
5202 {
5203 c->stopsignal = 0;
5204 return 0;
5205 }
5206
5207 static inline int clr_config_start(const char *key, struct lxc_conf *c,
5208 void *data)
5209 {
5210 if (strequal(key + 10, "auto"))
5211 c->start_auto = 0;
5212 else if (strequal(key + 10, "delay"))
5213 c->start_delay = 0;
5214 else if (strequal(key + 10, "order"))
5215 c->start_order = 0;
5216
5217 return 0;
5218 }
5219
5220 static inline int clr_config_log_syslog(const char *key, struct lxc_conf *c,
5221 void *data)
5222 {
5223 free_disarm(c->syslog);
5224 return 0;
5225 }
5226
5227 static inline int clr_config_monitor(const char *key, struct lxc_conf *c,
5228 void *data)
5229 {
5230 c->monitor_unshare = 0;
5231 return 0;
5232 }
5233
5234 static inline int clr_config_monitor_signal_pdeath(const char *key,
5235 struct lxc_conf *c, void *data)
5236 {
5237 c->monitor_signal_pdeath = 0;
5238 return 0;
5239 }
5240
5241 static inline int clr_config_group(const char *key, struct lxc_conf *c,
5242 void *data)
5243 {
5244 return lxc_clear_groups(c);
5245 }
5246
5247 static inline int clr_config_environment(const char *key, struct lxc_conf *c,
5248 void *data)
5249 {
5250 return lxc_clear_environment(c);
5251 }
5252
5253 static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
5254 void *data)
5255 {
5256 free_disarm(c->execute_cmd);
5257 return 0;
5258 }
5259
5260 static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
5261 void *data)
5262 {
5263 free_disarm(c->init_cmd);
5264 return 0;
5265 }
5266
5267 static inline int clr_config_init_cwd(const char *key, struct lxc_conf *c,
5268 void *data)
5269 {
5270 free_disarm(c->init_cwd);
5271 return 0;
5272 }
5273
5274 static inline int clr_config_init_uid(const char *key, struct lxc_conf *c,
5275 void *data)
5276 {
5277 c->init_uid = 0;
5278 return 0;
5279 }
5280
5281 static inline int clr_config_init_gid(const char *key, struct lxc_conf *c,
5282 void *data)
5283 {
5284 c->init_gid = 0;
5285 return 0;
5286 }
5287
5288 static inline int clr_config_init_groups(const char *key, struct lxc_conf *c,
5289 void *data)
5290 {
5291 c->init_groups.size = 0;
5292 free_disarm(c->init_groups.list);
5293 return 0;
5294 }
5295
5296 static inline int clr_config_ephemeral(const char *key, struct lxc_conf *c,
5297 void *data)
5298 {
5299 c->ephemeral = 0;
5300 return 0;
5301 }
5302
5303 static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c,
5304 void *data)
5305 {
5306 c->no_new_privs = false;
5307 return 0;
5308 }
5309
5310 static inline int clr_config_prlimit(const char *key, struct lxc_conf *c,
5311 void *data)
5312 {
5313 return lxc_clear_limits(c, key);
5314 }
5315
5316 static inline int clr_config_sysctl(const char *key, struct lxc_conf *c,
5317 void *data)
5318 {
5319 return lxc_clear_sysctls(c, key);
5320 }
5321
5322 static inline int clr_config_proc(const char *key, struct lxc_conf *c,
5323 void *data)
5324 {
5325 return lxc_clear_procs(c, key);
5326 }
5327
5328 static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
5329 void *data)
5330 {
5331 return 0;
5332 }
5333
5334 static int clr_config_namespace_clone(const char *key,
5335 struct lxc_conf *lxc_conf, void *data)
5336 {
5337 lxc_conf->ns_clone = 0;
5338 return 0;
5339 }
5340
5341 static int clr_config_namespace_keep(const char *key, struct lxc_conf *lxc_conf,
5342 void *data)
5343 {
5344 lxc_conf->ns_keep = 0;
5345 return 0;
5346 }
5347
5348 static int clr_config_time_offset_boot(const char *key, struct lxc_conf *lxc_conf, void *data)
5349 {
5350 lxc_conf->timens.s_boot = 0;
5351 lxc_conf->timens.ns_boot = 0;
5352 return 0;
5353 }
5354
5355 static int clr_config_time_offset_monotonic(const char *key, struct lxc_conf *lxc_conf, void *data)
5356 {
5357 lxc_conf->timens.s_monotonic = 0;
5358 lxc_conf->timens.ns_monotonic = 0;
5359 return 0;
5360 }
5361
5362 static int clr_config_namespace_share(const char *key,
5363 struct lxc_conf *lxc_conf, void *data)
5364 {
5365 int ns_idx;
5366 const char *namespace;
5367
5368 namespace = key + STRLITERALLEN("lxc.namespace.share.");
5369 if (is_empty_string(namespace))
5370 return ret_errno(EINVAL);
5371
5372 ns_idx = lxc_namespace_2_ns_idx(namespace);
5373 if (ns_idx < 0)
5374 return ns_idx;
5375
5376 free(lxc_conf->ns_share[ns_idx]);
5377 lxc_conf->ns_share[ns_idx] = NULL;
5378
5379 return 0;
5380 }
5381
5382 static int get_config_includefiles(const char *key, char *retv, int inlen,
5383 struct lxc_conf *c, void *data)
5384 {
5385 return ret_errno(ENOSYS);
5386 }
5387
5388 struct config_net_info {
5389 char buf[NETWORK_SUBKEY_SIZE_MAX];
5390 const char *subkey;
5391 const struct lxc_config_net_t *ops;
5392 struct lxc_netdev *netdev;
5393 };
5394
5395 static int get_network_config_ops(const char *key, struct lxc_conf *lxc_conf,
5396 struct config_net_info *info, bool allocate)
5397 {
5398 int ret;
5399 int64_t tmpidx;
5400 unsigned int idx;
5401 const char *idx_start;
5402
5403 if (is_empty_string(key))
5404 return ret_errno(EINVAL);
5405
5406 /* check that this is a sensible network key */
5407 if (!strnequal("lxc.net.", key, STRLITERALLEN("lxc.net.")))
5408 return syserror_set(-EINVAL, "Invalid network configuration key \"%s\"", key);
5409
5410 /* lxc.net.<n> */
5411 /* beginning of index string */
5412 idx_start = key + STRLITERALLEN("lxc.net.");
5413 if (!isdigit(*idx_start))
5414 return syserror_set(-EINVAL, "Failed to detect digit in string \"%s\"", key + 8);
5415
5416 ret = lxc_safe_int64_residual(idx_start, &tmpidx, 10, info->buf, sizeof(info->buf));
5417 if (ret)
5418 return syserror("Failed to parse network index");
5419
5420 if (tmpidx < 0 || tmpidx >= INT_MAX)
5421 return syserror_set(-ERANGE, "Number of configured networks would overflow the counter");
5422 idx = (unsigned int)tmpidx;
5423
5424 info->netdev = lxc_get_netdev_by_idx(lxc_conf, idx, allocate);
5425 if (!info->netdev)
5426 return ret_errno(EINVAL);
5427
5428 /* Make sure subkey points to the empty string. */
5429 info->subkey = info->buf;
5430 if (is_empty_string(info->subkey))
5431 return ret_errno(ENOENT);
5432
5433 if (info->subkey[0] != '.')
5434 return syserror_set(-EINVAL, "Invalid subkey");
5435 info->subkey++;
5436
5437 /* lxc.net.<idx>.<subkey> */
5438 info->ops = lxc_get_config_net(info->subkey);
5439 if (info->ops == &unsupported_config_net_key)
5440 return syserror_set(-ENOENT, "Unknown network configuration key \"%s\"", key);
5441
5442 return 0;
5443 }
5444
5445 /* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
5446 * found. So we make sure next comes an integer, find the right callback (by
5447 * rewriting the key), and call it.
5448 */
5449 static int set_config_jump_table_net(const char *key, const char *value,
5450 struct lxc_conf *lxc_conf, void *data)
5451 {
5452 struct config_net_info info = {};
5453 int ret;
5454 const char *idxstring;
5455
5456 idxstring = key + STRLITERALLEN("lxc.net.");
5457 if (!isdigit(*idxstring))
5458 return ret_errno(EINVAL);
5459
5460 if (lxc_config_value_empty(value))
5461 return clr_config_jump_table_net(key, lxc_conf, data);
5462
5463 ret = get_network_config_ops(key, lxc_conf, &info, true);
5464 if (ret)
5465 return ret;
5466
5467 return info.ops->set(info.subkey, value, lxc_conf, info.netdev);
5468 }
5469
5470 static int clr_config_jump_table_net(const char *key, struct lxc_conf *lxc_conf,
5471 void *data)
5472 {
5473 struct config_net_info info = {};
5474 int ret;
5475 const char *idxstring;
5476
5477 idxstring = key + 8;
5478 if (!isdigit(*idxstring))
5479 return ret_errno(EINVAL);
5480
5481 /* The left conjunct is pretty self-explanatory. The right conjunct
5482 * checks whether the two pointers are equal. If they are we know that
5483 * this is not a key that is namespaced any further and so we are
5484 * supposed to clear the whole network.
5485 */
5486 if (isdigit(*idxstring) && (strrchr(key, '.') == (idxstring - 1))) {
5487 unsigned int rmnetdevidx;
5488
5489 ret = lxc_safe_uint(idxstring, &rmnetdevidx);
5490 if (ret < 0)
5491 return ret;
5492
5493 /* Remove network from network list. */
5494 lxc_remove_nic_by_idx(lxc_conf, rmnetdevidx);
5495 return 0;
5496 }
5497
5498 ret = get_network_config_ops(key, lxc_conf, &info, false);
5499 if (ret)
5500 return ret;
5501
5502 return info.ops->clr(info.subkey, lxc_conf, info.netdev);
5503 }
5504
5505 static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
5506 void *data)
5507 {
5508 struct lxc_netdev *netdev = data;
5509
5510 if (!netdev)
5511 return ret_errno(EINVAL);
5512
5513 lxc_clear_netdev(netdev);
5514
5515 return 0;
5516 }
5517
5518 static int clr_config_net_name(const char *key, struct lxc_conf *lxc_conf,
5519 void *data)
5520 {
5521 struct lxc_netdev *netdev = data;
5522
5523 if (!netdev)
5524 return ret_errno(EINVAL);
5525
5526 netdev->name[0] = '\0';
5527
5528 return 0;
5529 }
5530
5531 static int clr_config_net_flags(const char *key, struct lxc_conf *lxc_conf,
5532 void *data)
5533 {
5534 struct lxc_netdev *netdev = data;
5535
5536 if (!netdev)
5537 return ret_errno(EINVAL);
5538
5539 netdev->flags = 0;
5540
5541 return 0;
5542 }
5543
5544 static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
5545 void *data)
5546 {
5547 struct lxc_netdev *netdev = data;
5548
5549 if (!netdev)
5550 return ret_errno(EINVAL);
5551
5552 netdev->link[0] = '\0';
5553
5554 return 0;
5555 }
5556
5557 static int clr_config_net_l2proxy(const char *key, struct lxc_conf *lxc_conf,
5558 void *data)
5559 {
5560 struct lxc_netdev *netdev = data;
5561
5562 if (!netdev)
5563 return ret_errno(EINVAL);
5564
5565 netdev->l2proxy = false;
5566
5567 return 0;
5568 }
5569
5570 static int clr_config_net_macvlan_mode(const char *key,
5571 struct lxc_conf *lxc_conf, void *data)
5572 {
5573 struct lxc_netdev *netdev = data;
5574
5575 if (!netdev)
5576 return ret_errno(EINVAL);
5577
5578 if (netdev->type != LXC_NET_MACVLAN)
5579 return 0;
5580
5581 netdev->priv.macvlan_attr.mode = -1;
5582
5583 return 0;
5584 }
5585
5586 static int clr_config_net_ipvlan_mode(const char *key,
5587 struct lxc_conf *lxc_conf, void *data)
5588 {
5589 struct lxc_netdev *netdev = data;
5590
5591 if (!netdev)
5592 return ret_errno(EINVAL);
5593
5594 if (netdev->type != LXC_NET_IPVLAN)
5595 return 0;
5596
5597 netdev->priv.ipvlan_attr.mode = -1;
5598
5599 return 0;
5600 }
5601
5602 static int clr_config_net_ipvlan_isolation(const char *key,
5603 struct lxc_conf *lxc_conf, void *data)
5604 {
5605 struct lxc_netdev *netdev = data;
5606
5607 if (!netdev)
5608 return ret_errno(EINVAL);
5609
5610 if (netdev->type != LXC_NET_IPVLAN)
5611 return 0;
5612
5613 netdev->priv.ipvlan_attr.isolation = -1;
5614
5615 return 0;
5616 }
5617
5618 static int clr_config_net_veth_mode(const char *key,
5619 struct lxc_conf *lxc_conf, void *data)
5620 {
5621 struct lxc_netdev *netdev = data;
5622
5623 if (!netdev)
5624 return ret_errno(EINVAL);
5625
5626 if (netdev->type != LXC_NET_VETH)
5627 return 0;
5628
5629 netdev->priv.veth_attr.mode = -1;
5630
5631 return 0;
5632 }
5633
5634 static int clr_config_net_veth_n_rxqueues(const char *key, struct lxc_conf *lxc_conf,
5635 void *data)
5636 {
5637 struct lxc_netdev *netdev = data;
5638
5639 if (!netdev)
5640 return ret_errno(EINVAL);
5641
5642 if (netdev->type != LXC_NET_VETH)
5643 return 0;
5644
5645 netdev->priv.veth_attr.n_rxqueues = -1;
5646
5647 return 0;
5648 }
5649
5650 static int clr_config_net_veth_n_txqueues(const char *key, struct lxc_conf *lxc_conf,
5651 void *data)
5652 {
5653 struct lxc_netdev *netdev = data;
5654
5655 if (!netdev)
5656 return ret_errno(EINVAL);
5657
5658 if (netdev->type != LXC_NET_VETH)
5659 return 0;
5660
5661 netdev->priv.veth_attr.n_txqueues = -1;
5662
5663 return 0;
5664 }
5665
5666
5667 static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
5668 void *data)
5669 {
5670 struct lxc_netdev *netdev = data;
5671
5672 if (!netdev)
5673 return ret_errno(EINVAL);
5674
5675 if (netdev->type != LXC_NET_VETH)
5676 return 0;
5677
5678 netdev->priv.veth_attr.pair[0] = '\0';
5679
5680 return 0;
5681 }
5682
5683 static int clr_config_net_veth_vlan_id(const char *key, struct lxc_conf *lxc_conf,
5684 void *data)
5685 {
5686 struct lxc_netdev *netdev = data;
5687
5688 if (!netdev)
5689 return ret_errno(EINVAL);
5690
5691 if (netdev->type != LXC_NET_VETH)
5692 return 0;
5693
5694 netdev->priv.veth_attr.vlan_id = 0;
5695 netdev->priv.veth_attr.vlan_id_set = false;
5696
5697 return 0;
5698 }
5699
5700 static int clr_config_net_veth_vlan_tagged_id(const char *key,
5701 struct lxc_conf *lxc_conf, void *data)
5702 {
5703 struct lxc_netdev *netdev = data;
5704 struct lxc_list *cur, *next;
5705
5706 if (!netdev)
5707 return ret_errno(EINVAL);
5708
5709 if (netdev->type != LXC_NET_VETH)
5710 return 0;
5711
5712 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
5713 lxc_list_del(cur);
5714 free(cur);
5715 }
5716
5717 return 0;
5718 }
5719
5720
5721 static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
5722 void *data)
5723 {
5724 struct lxc_netdev *netdev = data;
5725
5726 if (!netdev)
5727 return ret_errno(EINVAL);
5728
5729 free_disarm(netdev->upscript);
5730
5731 return 0;
5732 }
5733
5734 static int clr_config_net_script_down(const char *key,
5735 struct lxc_conf *lxc_conf, void *data)
5736 {
5737 struct lxc_netdev *netdev = data;
5738
5739 if (!netdev)
5740 return ret_errno(EINVAL);
5741
5742 free_disarm(netdev->downscript);
5743
5744 return 0;
5745 }
5746
5747 static int clr_config_net_hwaddr(const char *key, struct lxc_conf *lxc_conf,
5748 void *data)
5749 {
5750 struct lxc_netdev *netdev = data;
5751
5752 if (!netdev)
5753 return ret_errno(EINVAL);
5754
5755 free_disarm(netdev->hwaddr);
5756
5757 return 0;
5758 }
5759
5760 static int clr_config_net_mtu(const char *key, struct lxc_conf *lxc_conf,
5761 void *data)
5762 {
5763 struct lxc_netdev *netdev = data;
5764
5765 if (!netdev)
5766 return ret_errno(EINVAL);
5767
5768 free_disarm(netdev->mtu);
5769
5770 return 0;
5771 }
5772
5773 static int clr_config_net_vlan_id(const char *key, struct lxc_conf *lxc_conf,
5774 void *data)
5775 {
5776 struct lxc_netdev *netdev = data;
5777
5778 if (!netdev)
5779 return ret_errno(EINVAL);
5780
5781 if (netdev->type != LXC_NET_VLAN)
5782 return 0;
5783
5784 netdev->priv.vlan_attr.vid = 0;
5785
5786 return 0;
5787 }
5788
5789 static int clr_config_net_ipv4_gateway(const char *key,
5790 struct lxc_conf *lxc_conf, void *data)
5791 {
5792 struct lxc_netdev *netdev = data;
5793
5794 if (!netdev)
5795 return ret_errno(EINVAL);
5796
5797 free_disarm(netdev->ipv4_gateway);
5798
5799 return 0;
5800 }
5801
5802 static int clr_config_net_ipv4_address(const char *key,
5803 struct lxc_conf *lxc_conf, void *data)
5804 {
5805 struct lxc_netdev *netdev = data;
5806 struct lxc_inetdev *inetdev, *ninetdev;
5807
5808 if (!netdev)
5809 return ret_errno(EINVAL);
5810
5811 list_for_each_entry_safe(inetdev, ninetdev, &netdev->ipv4_addresses, head) {
5812 list_del(&inetdev->head);
5813 free(inetdev);
5814 }
5815
5816 return 0;
5817 }
5818
5819 static int clr_config_net_veth_ipv4_route(const char *key,
5820 struct lxc_conf *lxc_conf, void *data)
5821 {
5822 struct lxc_netdev *netdev = data;
5823 struct lxc_inetdev *inetdev, *ninetdev;
5824
5825 if (!netdev)
5826 return ret_errno(EINVAL);
5827
5828 if (netdev->type != LXC_NET_VETH)
5829 return 0;
5830
5831 list_for_each_entry_safe(inetdev, ninetdev, &netdev->priv.veth_attr.ipv4_routes, head) {
5832 list_del(&inetdev->head);
5833 free(inetdev);
5834 }
5835
5836 return 0;
5837 }
5838
5839 static int clr_config_net_ipv6_gateway(const char *key,
5840 struct lxc_conf *lxc_conf, void *data)
5841 {
5842 struct lxc_netdev *netdev = data;
5843
5844 if (!netdev)
5845 return ret_errno(EINVAL);
5846
5847 free_disarm(netdev->ipv6_gateway);
5848
5849 return 0;
5850 }
5851
5852 static int clr_config_net_ipv6_address(const char *key,
5853 struct lxc_conf *lxc_conf, void *data)
5854 {
5855 struct lxc_netdev *netdev = data;
5856 struct lxc_inet6dev *inet6dev, *ninet6dev;
5857
5858 if (!netdev)
5859 return ret_errno(EINVAL);
5860
5861 list_for_each_entry_safe(inet6dev, ninet6dev, &netdev->ipv6_addresses, head) {
5862 list_del(&inet6dev->head);
5863 free(inet6dev);
5864 }
5865
5866 return 0;
5867 }
5868
5869 static int clr_config_net_veth_ipv6_route(const char *key,
5870 struct lxc_conf *lxc_conf, void *data)
5871 {
5872 struct lxc_netdev *netdev = data;
5873 struct lxc_inet6dev *inet6dev, *ninet6dev;
5874
5875 if (!netdev)
5876 return ret_errno(EINVAL);
5877
5878 if (netdev->type != LXC_NET_VETH)
5879 return 0;
5880
5881 list_for_each_entry_safe(inet6dev, ninet6dev, &netdev->priv.veth_attr.ipv6_routes, head) {
5882 list_del(&inet6dev->head);
5883 free(inet6dev);
5884 }
5885
5886 return 0;
5887 }
5888
5889 static int get_config_jump_table_net(const char *key, char *retv, int inlen,
5890 struct lxc_conf *c, void *data)
5891 {
5892 struct config_net_info info = {};
5893 int ret;
5894 const char *idxstring;
5895
5896 idxstring = key + STRLITERALLEN("lxc.net.");
5897 if (!isdigit(*idxstring))
5898 return ret_errno(EINVAL);
5899
5900 ret = get_network_config_ops(key, c, &info, false);
5901 if (ret)
5902 return ret;
5903
5904 return info.ops->get(info.subkey, retv, inlen, c, info.netdev);
5905 }
5906
5907 static int get_config_net_type(const char *key, char *retv, int inlen,
5908 struct lxc_conf *c, void *data)
5909 {
5910 int len;
5911 int fulllen = 0;
5912 struct lxc_netdev *netdev = data;
5913
5914 if (!netdev)
5915 return ret_errno(EINVAL);
5916
5917 if (!retv)
5918 inlen = 0;
5919 else
5920 memset(retv, 0, inlen);
5921
5922 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
5923
5924 return fulllen;
5925 }
5926
5927 static int get_config_net_flags(const char *key, char *retv, int inlen,
5928 struct lxc_conf *c, void *data)
5929 {
5930 int len;
5931 int fulllen = 0;
5932 struct lxc_netdev *netdev = data;
5933
5934 if (!netdev)
5935 return ret_errno(EINVAL);
5936
5937 if (!retv)
5938 inlen = 0;
5939 else
5940 memset(retv, 0, inlen);
5941
5942 if (netdev->flags & IFF_UP)
5943 strprint(retv, inlen, "up");
5944
5945 return fulllen;
5946 }
5947
5948 static int get_config_net_link(const char *key, char *retv, int inlen,
5949 struct lxc_conf *c, void *data)
5950 {
5951 int len;
5952 int fulllen = 0;
5953 struct lxc_netdev *netdev = data;
5954
5955 if (!netdev)
5956 return ret_errno(EINVAL);
5957
5958 if (!retv)
5959 inlen = 0;
5960 else
5961 memset(retv, 0, inlen);
5962
5963 if (netdev->link[0] != '\0')
5964 strprint(retv, inlen, "%s", netdev->link);
5965
5966 return fulllen;
5967 }
5968
5969 static int get_config_net_l2proxy(const char *key, char *retv, int inlen,
5970 struct lxc_conf *c, void *data)
5971 {
5972 struct lxc_netdev *netdev = data;
5973
5974 if (!netdev)
5975 return ret_errno(EINVAL);
5976
5977 return lxc_get_conf_bool(c, retv, inlen, netdev->l2proxy);
5978 }
5979
5980 static int get_config_net_name(const char *key, char *retv, int inlen,
5981 struct lxc_conf *c, void *data)
5982 {
5983 int len;
5984 int fulllen = 0;
5985 struct lxc_netdev *netdev = data;
5986
5987 if (!netdev)
5988 return ret_errno(EINVAL);
5989
5990 if (!retv)
5991 inlen = 0;
5992 else
5993 memset(retv, 0, inlen);
5994
5995 if (netdev->name[0] != '\0')
5996 strprint(retv, inlen, "%s", netdev->name);
5997
5998 return fulllen;
5999 }
6000
6001 static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
6002 struct lxc_conf *c, void *data)
6003 {
6004 int len;
6005 int fulllen = 0;
6006 const char *mode;
6007 struct lxc_netdev *netdev = data;
6008
6009 if (!netdev)
6010 return ret_errno(EINVAL);
6011
6012 if (netdev->type != LXC_NET_MACVLAN)
6013 return ret_errno(EINVAL);
6014
6015 if (!retv)
6016 inlen = 0;
6017 else
6018 memset(retv, 0, inlen);
6019
6020 switch (netdev->priv.macvlan_attr.mode) {
6021 case MACVLAN_MODE_PRIVATE:
6022 mode = "private";
6023 break;
6024 case MACVLAN_MODE_VEPA:
6025 mode = "vepa";
6026 break;
6027 case MACVLAN_MODE_BRIDGE:
6028 mode = "bridge";
6029 break;
6030 case MACVLAN_MODE_PASSTHRU:
6031 mode = "passthru";
6032 break;
6033 default:
6034 mode = "(invalid)";
6035 break;
6036 }
6037
6038 strprint(retv, inlen, "%s", mode);
6039
6040 return fulllen;
6041 }
6042
6043 static int get_config_net_ipvlan_mode(const char *key, char *retv, int inlen,
6044 struct lxc_conf *c, void *data)
6045 {
6046 int fulllen = 0;
6047 struct lxc_netdev *netdev = data;
6048 int len;
6049 const char *mode;
6050
6051 if (!netdev)
6052 return ret_errno(EINVAL);
6053
6054 if (netdev->type != LXC_NET_IPVLAN)
6055 return ret_errno(EINVAL);
6056
6057 if (!retv)
6058 inlen = 0;
6059 else
6060 memset(retv, 0, inlen);
6061
6062 switch (netdev->priv.ipvlan_attr.mode) {
6063 case IPVLAN_MODE_L3:
6064 mode = "l3";
6065 break;
6066 case IPVLAN_MODE_L3S:
6067 mode = "l3s";
6068 break;
6069 case IPVLAN_MODE_L2:
6070 mode = "l2";
6071 break;
6072 default:
6073 mode = "(invalid)";
6074 break;
6075 }
6076
6077 strprint(retv, inlen, "%s", mode);
6078
6079 return fulllen;
6080 }
6081
6082 static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inlen,
6083 struct lxc_conf *c, void *data)
6084 {
6085 int fulllen = 0;
6086 struct lxc_netdev *netdev = data;
6087 int len;
6088 const char *mode;
6089
6090 if (!netdev)
6091 return ret_errno(EINVAL);
6092
6093 if (netdev->type != LXC_NET_IPVLAN)
6094 return ret_errno(EINVAL);
6095
6096 if (!retv)
6097 inlen = 0;
6098 else
6099 memset(retv, 0, inlen);
6100
6101 switch (netdev->priv.ipvlan_attr.isolation) {
6102 case IPVLAN_ISOLATION_BRIDGE:
6103 mode = "bridge";
6104 break;
6105 case IPVLAN_ISOLATION_PRIVATE:
6106 mode = "private";
6107 break;
6108 case IPVLAN_ISOLATION_VEPA:
6109 mode = "vepa";
6110 break;
6111 default:
6112 mode = "(invalid)";
6113 break;
6114 }
6115
6116 strprint(retv, inlen, "%s", mode);
6117
6118 return fulllen;
6119 }
6120
6121 static int get_config_net_veth_mode(const char *key, char *retv, int inlen,
6122 struct lxc_conf *c, void *data)
6123 {
6124 int fulllen = 0;
6125 struct lxc_netdev *netdev = data;
6126 int len;
6127 const char *mode;
6128
6129 if (!netdev)
6130 return ret_errno(EINVAL);
6131
6132 if (netdev->type != LXC_NET_VETH)
6133 return ret_errno(EINVAL);
6134
6135 if (!retv)
6136 inlen = 0;
6137 else
6138 memset(retv, 0, inlen);
6139
6140 switch (netdev->priv.veth_attr.mode) {
6141 case VETH_MODE_BRIDGE:
6142 mode = "bridge";
6143 break;
6144 case VETH_MODE_ROUTER:
6145 mode = "router";
6146 break;
6147 default:
6148 mode = "(invalid)";
6149 break;
6150 }
6151
6152 strprint(retv, inlen, "%s", mode);
6153
6154 return fulllen;
6155 }
6156
6157 static int get_config_net_veth_n_rxqueues(const char *key, char *retv, int inlen,
6158 struct lxc_conf *c, void *data)
6159 {
6160 int len;
6161 int fulllen = 0;
6162 struct lxc_netdev *netdev = data;
6163
6164 if (!netdev)
6165 return ret_errno(EINVAL);
6166
6167 if (netdev->type != LXC_NET_VETH)
6168 return ret_errno(EINVAL);
6169
6170 if (!retv)
6171 inlen = 0;
6172 else
6173 memset(retv, 0, inlen);
6174
6175 if (netdev->priv.veth_attr.n_rxqueues > 0)
6176 strprint(retv, inlen, "%d", netdev->priv.veth_attr.n_rxqueues);
6177
6178 return fulllen;
6179 }
6180
6181 static int get_config_net_veth_n_txqueues(const char *key, char *retv, int inlen,
6182 struct lxc_conf *c, void *data)
6183 {
6184 int len;
6185 int fulllen = 0;
6186 struct lxc_netdev *netdev = data;
6187
6188 if (!netdev)
6189 return ret_errno(EINVAL);
6190
6191 if (netdev->type != LXC_NET_VETH)
6192 return ret_errno(EINVAL);
6193
6194 if (!retv)
6195 inlen = 0;
6196 else
6197 memset(retv, 0, inlen);
6198
6199 if (netdev->priv.veth_attr.n_txqueues > 0)
6200 strprint(retv, inlen, "%d", netdev->priv.veth_attr.n_txqueues);
6201
6202 return fulllen;
6203 }
6204
6205 static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
6206 struct lxc_conf *c, void *data)
6207 {
6208 int len;
6209 int fulllen = 0;
6210 struct lxc_netdev *netdev = data;
6211
6212 if (!netdev)
6213 return ret_errno(EINVAL);
6214
6215 if (netdev->type != LXC_NET_VETH)
6216 return ret_errno(EINVAL);
6217
6218 if (!retv)
6219 inlen = 0;
6220 else
6221 memset(retv, 0, inlen);
6222
6223 strprint(retv, inlen, "%s",
6224 netdev->priv.veth_attr.pair[0] != '\0'
6225 ? netdev->priv.veth_attr.pair
6226 : netdev->priv.veth_attr.veth1);
6227
6228 return fulllen;
6229 }
6230
6231 static int get_config_net_veth_vlan_id(const char *key, char *retv, int inlen,
6232 struct lxc_conf *c, void *data)
6233 {
6234 int len;
6235 int fulllen = 0;
6236 struct lxc_netdev *netdev = data;
6237
6238 if (!netdev)
6239 return ret_errno(EINVAL);
6240
6241 if (netdev->type != LXC_NET_VETH)
6242 return ret_errno(EINVAL);
6243
6244 if (!retv)
6245 inlen = 0;
6246 else
6247 memset(retv, 0, inlen);
6248
6249 strprint(retv, inlen, "%d", netdev->priv.veth_attr.vlan_id);
6250
6251 return fulllen;
6252 }
6253
6254 static int get_config_net_veth_vlan_tagged_id(const char *key, char *retv,
6255 int inlen, struct lxc_conf *c,
6256 void *data)
6257 {
6258 int len;
6259 size_t listlen;
6260 struct lxc_list *it;
6261 int fulllen = 0;
6262 struct lxc_netdev *netdev = data;
6263
6264 if (!netdev)
6265 return ret_errno(EINVAL);
6266
6267 if (netdev->type != LXC_NET_VETH)
6268 return ret_errno(EINVAL);
6269
6270 if (!retv)
6271 inlen = 0;
6272 else
6273 memset(retv, 0, inlen);
6274
6275 listlen = lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids);
6276
6277 lxc_list_for_each(it, &netdev->priv.veth_attr.vlan_tagged_ids) {
6278 unsigned short i = PTR_TO_USHORT(it->elem);
6279 strprint(retv, inlen, "%u%s", i, (listlen-- > 1) ? "\n" : "");
6280 }
6281
6282 return fulllen;
6283 }
6284
6285 static int get_config_net_script_up(const char *key, char *retv, int inlen,
6286 struct lxc_conf *c, void *data)
6287 {
6288 int len;
6289 int fulllen = 0;
6290 struct lxc_netdev *netdev = data;
6291
6292 if (!netdev)
6293 return ret_errno(EINVAL);
6294
6295 if (!retv)
6296 inlen = 0;
6297 else
6298 memset(retv, 0, inlen);
6299
6300 if (netdev->upscript)
6301 strprint(retv, inlen, "%s", netdev->upscript);
6302
6303 return fulllen;
6304 }
6305
6306 static int get_config_net_script_down(const char *key, char *retv, int inlen,
6307 struct lxc_conf *c, void *data)
6308 {
6309 int len;
6310 int fulllen = 0;
6311 struct lxc_netdev *netdev = data;
6312
6313 if (!netdev)
6314 return ret_errno(EINVAL);
6315
6316 if (!retv)
6317 inlen = 0;
6318 else
6319 memset(retv, 0, inlen);
6320
6321 if (netdev->downscript)
6322 strprint(retv, inlen, "%s", netdev->downscript);
6323
6324 return fulllen;
6325 }
6326
6327 static int get_config_net_hwaddr(const char *key, char *retv, int inlen,
6328 struct lxc_conf *c, void *data)
6329 {
6330 int len;
6331 int fulllen = 0;
6332 struct lxc_netdev *netdev = data;
6333
6334 if (!netdev)
6335 return ret_errno(EINVAL);
6336
6337 if (!retv)
6338 inlen = 0;
6339 else
6340 memset(retv, 0, inlen);
6341
6342 if (netdev->hwaddr)
6343 strprint(retv, inlen, "%s", netdev->hwaddr);
6344
6345 return fulllen;
6346 }
6347
6348 static int get_config_net_mtu(const char *key, char *retv, int inlen,
6349 struct lxc_conf *c, void *data)
6350 {
6351 int len;
6352 int fulllen = 0;
6353 struct lxc_netdev *netdev = data;
6354
6355 if (!netdev)
6356 return ret_errno(EINVAL);
6357
6358 if (!retv)
6359 inlen = 0;
6360 else
6361 memset(retv, 0, inlen);
6362
6363 if (netdev->mtu)
6364 strprint(retv, inlen, "%s", netdev->mtu);
6365
6366 return fulllen;
6367 }
6368
6369 static int get_config_net_vlan_id(const char *key, char *retv, int inlen,
6370 struct lxc_conf *c, void *data)
6371 {
6372 int len;
6373 int fulllen = 0;
6374 struct lxc_netdev *netdev = data;
6375
6376 if (!netdev)
6377 return ret_errno(EINVAL);
6378
6379 if (netdev->type != LXC_NET_VLAN)
6380 return ret_errno(EINVAL);
6381
6382 if (!retv)
6383 inlen = 0;
6384 else
6385 memset(retv, 0, inlen);
6386
6387 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
6388
6389 return fulllen;
6390 }
6391
6392 static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
6393 struct lxc_conf *c, void *data)
6394 {
6395 int len;
6396 char buf[INET_ADDRSTRLEN];
6397 int fulllen = 0;
6398 struct lxc_netdev *netdev = data;
6399
6400 if (!netdev)
6401 return ret_errno(EINVAL);
6402
6403 if (!retv)
6404 inlen = 0;
6405 else
6406 memset(retv, 0, inlen);
6407
6408 if (netdev->ipv4_gateway_auto) {
6409 strprint(retv, inlen, "auto");
6410 } else if (netdev->ipv4_gateway_dev) {
6411 strprint(retv, inlen, "dev");
6412 } else if (netdev->ipv4_gateway) {
6413 if (!inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf)))
6414 return -errno;
6415 strprint(retv, inlen, "%s", buf);
6416 }
6417
6418 return fulllen;
6419 }
6420
6421 static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
6422 struct lxc_conf *c, void *data)
6423 {
6424 int fulllen = 0;
6425 struct lxc_netdev *netdev = data;
6426 int len;
6427 size_t listlen;
6428 char buf[INET_ADDRSTRLEN];
6429 struct lxc_inetdev *inetdev;
6430
6431 if (!netdev)
6432 return ret_errno(EINVAL);
6433
6434 if (!retv)
6435 inlen = 0;
6436 else
6437 memset(retv, 0, inlen);
6438
6439 listlen = list_len(inetdev, &netdev->ipv4_addresses, head);
6440
6441 list_for_each_entry(inetdev, &netdev->ipv4_addresses, head) {
6442 if (!inet_ntop(AF_INET, &inetdev->addr, buf, sizeof(buf)))
6443 return -errno;
6444 strprint(retv, inlen, "%s/%u%s", buf, inetdev->prefix,
6445 (listlen-- > 1) ? "\n" : "");
6446 }
6447
6448 return fulllen;
6449 }
6450
6451 static int get_config_net_veth_ipv4_route(const char *key, char *retv, int inlen,
6452 struct lxc_conf *c, void *data)
6453 {
6454 int len;
6455 size_t listlen;
6456 char buf[INET_ADDRSTRLEN];
6457 struct lxc_inetdev *inetdev;
6458 int fulllen = 0;
6459 struct lxc_netdev *netdev = data;
6460
6461 if (!netdev)
6462 return ret_errno(EINVAL);
6463
6464 if (netdev->type != LXC_NET_VETH)
6465 return ret_errno(EINVAL);
6466
6467 if (!retv)
6468 inlen = 0;
6469 else
6470 memset(retv, 0, inlen);
6471
6472 listlen = list_len(inetdev, &netdev->priv.veth_attr.ipv4_routes, head);
6473 list_for_each_entry(inetdev, &netdev->priv.veth_attr.ipv4_routes, head) {
6474 if (!inet_ntop(AF_INET, &inetdev->addr, buf, sizeof(buf)))
6475 return -errno;
6476 strprint(retv, inlen, "%s/%u%s", buf, inetdev->prefix,
6477 (listlen-- > 1) ? "\n" : "");
6478 }
6479
6480 return fulllen;
6481 }
6482
6483 static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
6484 struct lxc_conf *c, void *data)
6485 {
6486 int len;
6487 char buf[INET6_ADDRSTRLEN];
6488 int fulllen = 0;
6489 struct lxc_netdev *netdev = data;
6490
6491 if (!netdev)
6492 return ret_errno(EINVAL);
6493
6494 if (!retv)
6495 inlen = 0;
6496 else
6497 memset(retv, 0, inlen);
6498
6499 if (netdev->ipv6_gateway_auto) {
6500 strprint(retv, inlen, "auto");
6501 } else if (netdev->ipv6_gateway_dev) {
6502 strprint(retv, inlen, "dev");
6503 } else if (netdev->ipv6_gateway) {
6504 if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf)))
6505 return -errno;
6506 strprint(retv, inlen, "%s", buf);
6507 }
6508
6509 return fulllen;
6510 }
6511
6512 static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
6513 struct lxc_conf *c, void *data)
6514 {
6515 int len;
6516 size_t listlen;
6517 char buf[INET6_ADDRSTRLEN];
6518 int fulllen = 0;
6519 struct lxc_netdev *netdev = data;
6520 struct lxc_inet6dev *inet6dev;
6521
6522 if (!netdev)
6523 return ret_errno(EINVAL);
6524
6525 if (!retv)
6526 inlen = 0;
6527 else
6528 memset(retv, 0, inlen);
6529
6530 listlen = list_len(inet6dev, &netdev->ipv6_addresses, head);
6531 list_for_each_entry(inet6dev, &netdev->ipv6_addresses, head) {
6532 if (!inet_ntop(AF_INET6, &inet6dev->addr, buf, sizeof(buf)))
6533 return -errno;
6534 strprint(retv, inlen, "%s/%u%s", buf, inet6dev->prefix,
6535 (listlen-- > 1) ? "\n" : "");
6536 }
6537
6538 return fulllen;
6539 }
6540
6541 static int get_config_net_veth_ipv6_route(const char *key, char *retv, int inlen,
6542 struct lxc_conf *c, void *data)
6543 {
6544 int len;
6545 size_t listlen;
6546 char buf[INET6_ADDRSTRLEN];
6547 struct lxc_inet6dev *inet6dev;
6548 int fulllen = 0;
6549 struct lxc_netdev *netdev = data;
6550
6551 if (!netdev)
6552 return ret_errno(EINVAL);
6553
6554 if (netdev->type != LXC_NET_VETH)
6555 return ret_errno(EINVAL);
6556
6557 if (!retv)
6558 inlen = 0;
6559 else
6560 memset(retv, 0, inlen);
6561
6562 listlen = list_len(inet6dev, &netdev->priv.veth_attr.ipv6_routes, head);
6563 list_for_each_entry(inet6dev, &netdev->priv.veth_attr.ipv6_routes, head) {
6564 if (!inet_ntop(AF_INET6, &inet6dev->addr, buf, sizeof(buf)))
6565 return -errno;
6566 strprint(retv, inlen, "%s/%u%s", buf, inet6dev->prefix,
6567 (listlen-- > 1) ? "\n" : "");
6568 }
6569
6570 return fulllen;
6571 }
6572
6573 int lxc_list_config_items(char *retv, int inlen)
6574 {
6575 size_t i;
6576 int len;
6577 int fulllen = 0;
6578
6579 if (!retv)
6580 inlen = 0;
6581 else
6582 memset(retv, 0, inlen);
6583
6584 for (i = 0; i < ARRAY_SIZE(config_jump_table); i++) {
6585 char *s = config_jump_table[i].name;
6586
6587 if (s[strlen(s) - 1] == '.')
6588 continue;
6589
6590 strprint(retv, inlen, "%s\n", s);
6591 }
6592
6593 return fulllen;
6594 }
6595
6596 int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
6597 int inlen)
6598 {
6599 int len;
6600 int fulllen = 0;
6601
6602 if (!retv)
6603 inlen = 0;
6604 else
6605 memset(retv, 0, inlen);
6606
6607 if (strequal(key, "lxc.apparmor")) {
6608 strprint(retv, inlen, "allow_incomplete\n");
6609 strprint(retv, inlen, "allow_nesting\n");
6610 strprint(retv, inlen, "profile\n");
6611 strprint(retv, inlen, "raw\n");
6612 } else if (strequal(key, "lxc.cgroup")) {
6613 strprint(retv, inlen, "dir\n");
6614 } else if (strequal(key, "lxc.selinux")) {
6615 strprint(retv, inlen, "context\n");
6616 strprint(retv, inlen, "context.keyring\n");
6617 } else if (strequal(key, "lxc.mount")) {
6618 strprint(retv, inlen, "auto\n");
6619 strprint(retv, inlen, "entry\n");
6620 strprint(retv, inlen, "fstab\n");
6621 } else if (strequal(key, "lxc.rootfs")) {
6622 strprint(retv, inlen, "mount\n");
6623 strprint(retv, inlen, "options\n");
6624 strprint(retv, inlen, "path\n");
6625 } else if (strequal(key, "lxc.uts")) {
6626 strprint(retv, inlen, "name\n");
6627 } else if (strequal(key, "lxc.hook")) {
6628 strprint(retv, inlen, "autodev\n");
6629 strprint(retv, inlen, "autodevtmpfssize\n");
6630 strprint(retv, inlen, "clone\n");
6631 strprint(retv, inlen, "destroy\n");
6632 strprint(retv, inlen, "mount\n");
6633 strprint(retv, inlen, "post-stop\n");
6634 strprint(retv, inlen, "pre-mount\n");
6635 strprint(retv, inlen, "pre-start\n");
6636 strprint(retv, inlen, "start-host\n");
6637 strprint(retv, inlen, "start\n");
6638 strprint(retv, inlen, "stop\n");
6639 } else if (strequal(key, "lxc.cap")) {
6640 strprint(retv, inlen, "drop\n");
6641 strprint(retv, inlen, "keep\n");
6642 } else if (strequal(key, "lxc.console")) {
6643 strprint(retv, inlen, "logfile\n");
6644 strprint(retv, inlen, "path\n");
6645 } else if (strequal(key, "lxc.seccomp")) {
6646 strprint(retv, inlen, "profile\n");
6647 } else if (strequal(key, "lxc.signal")) {
6648 strprint(retv, inlen, "halt\n");
6649 strprint(retv, inlen, "reboot\n");
6650 strprint(retv, inlen, "stop\n");
6651 } else if (strequal(key, "lxc.start")) {
6652 strprint(retv, inlen, "auto\n");
6653 strprint(retv, inlen, "delay\n");
6654 strprint(retv, inlen, "order\n");
6655 } else if (strequal(key, "lxc.monitor")) {
6656 strprint(retv, inlen, "unshare\n");
6657 } else if (strequal(key, "lxc.keyring")) {
6658 strprint(retv, inlen, "session\n");
6659 } else {
6660 fulllen = ret_errno(EINVAL);
6661 }
6662
6663 return fulllen;
6664 }
6665
6666 int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
6667 {
6668 struct config_net_info info = {};
6669 struct lxc_netdev *netdev;
6670 int len, ret;
6671 const char *idxstring;
6672 int fulllen = 0;
6673
6674 idxstring = key + STRLITERALLEN("lxc.net.");
6675 if (!isdigit(*idxstring))
6676 return ret_errno(EINVAL);
6677
6678 ret = get_network_config_ops(key, c, &info, false);
6679 if (ret) {
6680 if (ret != -ENOENT)
6681 return ret_errno(EINVAL);
6682 }
6683 netdev = info.netdev;
6684
6685 if (!retv)
6686 inlen = 0;
6687 else
6688 memset(retv, 0, inlen);
6689
6690 strprint(retv, inlen, "type\n");
6691 strprint(retv, inlen, "script.up\n");
6692 strprint(retv, inlen, "script.down\n");
6693
6694 if (netdev->type != LXC_NET_EMPTY) {
6695 strprint(retv, inlen, "flags\n");
6696 strprint(retv, inlen, "link\n");
6697 strprint(retv, inlen, "name\n");
6698 strprint(retv, inlen, "hwaddr\n");
6699 strprint(retv, inlen, "mtu\n");
6700 strprint(retv, inlen, "ipv6.address\n");
6701 strprint(retv, inlen, "ipv6.gateway\n");
6702 strprint(retv, inlen, "ipv4.address\n");
6703 strprint(retv, inlen, "ipv4.gateway\n");
6704 }
6705
6706 switch (netdev->type) {
6707 case LXC_NET_VETH:
6708 strprint(retv, inlen, "veth.pair\n");
6709 strprint(retv, inlen, "veth.ipv4.route\n");
6710 strprint(retv, inlen, "veth.ipv6.route\n");
6711 strprint(retv, inlen, "veth.vlan.id\n");
6712 break;
6713 case LXC_NET_MACVLAN:
6714 strprint(retv, inlen, "macvlan.mode\n");
6715 break;
6716 case LXC_NET_IPVLAN:
6717 strprint(retv, inlen, "ipvlan.mode\n");
6718 strprint(retv, inlen, "ipvlan.isolation\n");
6719 break;
6720 case LXC_NET_VLAN:
6721 strprint(retv, inlen, "vlan.id\n");
6722 break;
6723 case LXC_NET_PHYS:
6724 break;
6725 }
6726
6727 return fulllen;
6728 }
6729
6730 static int set_config_sched_core(const char *key, const char *value,
6731 struct lxc_conf *lxc_conf, void *data)
6732 {
6733 int ret;
6734 unsigned int nr;
6735
6736 if (lxc_config_value_empty(value))
6737 return clr_config_sched_core(key, lxc_conf, data);
6738
6739 ret = lxc_safe_uint(value, &nr);
6740 if (ret)
6741 return ret_errno(EINVAL);
6742
6743 if (nr != 0 && nr != 1)
6744 return ret_errno(EINVAL);
6745
6746 lxc_conf->sched_core = (nr == 1);
6747 return 0;
6748 }
6749
6750 static int get_config_sched_core(const char *key, char *retv, int inlen,
6751 struct lxc_conf *c, void *data)
6752 {
6753 return lxc_get_conf_bool(c, retv, inlen, c->sched_core);
6754 }
6755
6756 static int clr_config_sched_core(const char *key, struct lxc_conf *c, void *data)
6757 {
6758 c->sched_core = false;
6759 return 0;
6760 }