[lxc-devel] [lxc/master] time namespace support
brauner on Github
lxc-bot at linuxcontainers.org
Thu Jun 25 20:59:38 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200625/e653de27/attachment-0001.bin>
-------------- next part --------------
From fdd0753cf752b944c7a2ad96427ef5af2aadfac2 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 25 Jun 2020 14:39:29 +0200
Subject: [PATCH 1/4] file_utils: add timens_offset_write() helper
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/file_utils.c | 26 ++++++++++++++++++++++++++
src/lxc/file_utils.h | 1 +
2 files changed, 27 insertions(+)
diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c
index 1689cbaa7f..77e71d7849 100644
--- a/src/lxc/file_utils.c
+++ b/src/lxc/file_utils.c
@@ -512,3 +512,29 @@ FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer)
#endif
return f;
}
+
+int timens_offset_write(clockid_t clk_id, int64_t offset)
+{
+ __do_close int fd = -EBADF;
+ int ret;
+ ssize_t len;
+ char buf[INTTYPE_TO_STRLEN(int) + STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) +
+ STRLITERALLEN(" 0") + 1];
+
+ if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW)
+ clk_id = CLOCK_MONOTONIC;
+
+ fd = open("/proc/self/timens_offsets", O_WRONLY | O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset);
+ if (len < 0 || len >= sizeof(buf))
+ return ret_errno(EFBIG);
+
+ ret = lxc_write_nointr(fd, buf, len);
+ if (ret < 0 || (size_t)ret != len)
+ return -EIO;
+
+ return 0;
+}
diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h
index f9c8abe033..eeaf02811b 100644
--- a/src/lxc/file_utils.h
+++ b/src/lxc/file_utils.h
@@ -82,5 +82,6 @@ extern int lxc_open_dirfd(const char *dir);
extern FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer);
extern FILE *fopen_cached(const char *path, const char *mode,
void **caller_freed_buffer);
+extern int timens_offset_write(clockid_t clk_id, int64_t offset);
#endif /* __LXC_FILE_UTILS_H */
From d95c52158b785b4c9754c3c9f902e2a4b5813d65 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 25 Jun 2020 15:55:10 +0200
Subject: [PATCH 2/4] conf: add time namespace infrastructure
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/conf.h | 12 ++
src/lxc/confile.c | 336 ++++++++++++++++++++++++++++-------------
src/lxc/string_utils.c | 48 ++++++
src/lxc/string_utils.h | 2 +
4 files changed, 294 insertions(+), 104 deletions(-)
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index b72afbaa56..7f54539e0f 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -233,6 +233,16 @@ struct device_item {
int global_rule;
};
+struct timens_offsets {
+ /* Currently, either s_boot or ns_boot is set, but not both. */
+ int64_t s_boot;
+ int64_t ns_boot;
+
+ /* Currently, either s_monotonic or ns_monotonic is set, but not both. */
+ int64_t s_monotonic;
+ int64_t ns_monotonic;
+};
+
struct lxc_conf {
/* Pointer to the name of the container. Do not free! */
const char *name;
@@ -401,6 +411,8 @@ struct lxc_conf {
/* Absolute path (in the container) to the shared mount point */
char *path_cont;
} shmount;
+
+ struct timens_offsets timens;
};
extern int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 68403e65e0..1a378f740f 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -104,6 +104,8 @@ lxc_config_define(mount_auto);
lxc_config_define(mount_fstab);
lxc_config_define(namespace_clone);
lxc_config_define(namespace_keep);
+lxc_config_define(namespace_time_offset_boot);
+lxc_config_define(namespace_time_offset_monotonic);
lxc_config_define(namespace_share);
lxc_config_define(net);
lxc_config_define(net_flags);
@@ -166,110 +168,112 @@ lxc_config_define(proc);
* has to be placed above lxc.ab.
*/
static struct lxc_config_t config_jump_table[] = {
- { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
- { "lxc.apparmor.profile", set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
- { "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
- { "lxc.apparmor.allow_nesting", set_config_apparmor_allow_nesting, get_config_apparmor_allow_nesting, clr_config_apparmor_allow_nesting, },
- { "lxc.apparmor.raw", set_config_apparmor_raw, get_config_apparmor_raw, clr_config_apparmor_raw, },
- { "lxc.autodev.tmpfs.size", set_config_autodev_tmpfs_size, get_config_autodev_tmpfs_size, clr_config_autodev_tmpfs_size, },
- { "lxc.autodev", set_config_autodev, get_config_autodev, clr_config_autodev, },
- { "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
- { "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
- { "lxc.cgroup2", set_config_cgroup2_controller, get_config_cgroup2_controller, clr_config_cgroup2_controller, },
- { "lxc.cgroup.dir.monitor", set_config_cgroup_monitor_dir, get_config_cgroup_monitor_dir, clr_config_cgroup_monitor_dir, },
- { "lxc.cgroup.dir.container.inner",set_config_cgroup_container_inner_dir, get_config_cgroup_container_inner_dir, clr_config_cgroup_container_inner_dir,},
- { "lxc.cgroup.dir.container", set_config_cgroup_container_dir, get_config_cgroup_container_dir, clr_config_cgroup_container_dir, },
- { "lxc.cgroup.dir", set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
- { "lxc.cgroup.relative", set_config_cgroup_relative, get_config_cgroup_relative, clr_config_cgroup_relative, },
- { "lxc.cgroup", set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
- { "lxc.console.buffer.size", set_config_console_buffer_size, get_config_console_buffer_size, clr_config_console_buffer_size, },
- { "lxc.console.logfile", set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
- { "lxc.console.path", set_config_console_path, get_config_console_path, clr_config_console_path, },
- { "lxc.console.rotate", set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
- { "lxc.console.size", set_config_console_size, get_config_console_size, clr_config_console_size, },
- { "lxc.environment", set_config_environment, get_config_environment, clr_config_environment, },
- { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
- { "lxc.execute.cmd", set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
- { "lxc.group", set_config_group, get_config_group, clr_config_group, },
- { "lxc.hook.autodev", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.clone", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.destroy", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.post-stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.pre-mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.pre-start", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.start", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.start-host", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.hook.version", set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, },
- { "lxc.hook", set_config_hooks, get_config_hooks, clr_config_hooks, },
- { "lxc.idmap", set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
- { "lxc.include", set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
- { "lxc.init.cmd", set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
- { "lxc.init.gid", set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
- { "lxc.init.uid", set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
- { "lxc.init.cwd", set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, },
- { "lxc.keyring.session", set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session },
- { "lxc.log.file", set_config_log_file, get_config_log_file, clr_config_log_file, },
- { "lxc.log.level", set_config_log_level, get_config_log_level, clr_config_log_level, },
- { "lxc.log.syslog", set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
- { "lxc.monitor.unshare", set_config_monitor, get_config_monitor, clr_config_monitor, },
- { "lxc.monitor.signal.pdeath", set_config_monitor_signal_pdeath, get_config_monitor_signal_pdeath, clr_config_monitor_signal_pdeath, },
- { "lxc.mount.auto", set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
- { "lxc.mount.entry", set_config_mount, get_config_mount, clr_config_mount, },
- { "lxc.mount.fstab", set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
- { "lxc.namespace.clone", set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
- { "lxc.namespace.keep", set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
- { "lxc.namespace.share", set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
- { "lxc.net.flags", set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
- { "lxc.net.hwaddr", set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
- { "lxc.net.ipv4.address", set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
- { "lxc.net.ipv4.gateway", set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
- { "lxc.net.ipv6.address", set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
- { "lxc.net.ipv6.gateway", set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
- { "lxc.net.link", set_config_net_link, get_config_net_link, clr_config_net_link, },
- { "lxc.net.l2proxy", set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
- { "lxc.net.macvlan.mode", set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
- { "lxc.net.ipvlan.mode", set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
- { "lxc.net.ipvlan.isolation", set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
- { "lxc.net.mtu", set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
- { "lxc.net.name", set_config_net_name, get_config_net_name, clr_config_net_name, },
- { "lxc.net.script.down", set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
- { "lxc.net.script.up", set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
- { "lxc.net.type", set_config_net_type, get_config_net_type, clr_config_net_type, },
- { "lxc.net.vlan.id", set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
- { "lxc.net.veth.mode", set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
- { "lxc.net.veth.pair", set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
- { "lxc.net.veth.ipv4.route", set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
- { "lxc.net.veth.ipv6.route", set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
- { "lxc.net.veth.vlan.id", set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
- { "lxc.net.veth.vlan.tagged.id", set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
- { "lxc.net.", set_config_net_nic, get_config_net_nic, clr_config_net_nic, },
- { "lxc.net", set_config_net, get_config_net, clr_config_net, },
- { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
- { "lxc.prlimit", set_config_prlimit, get_config_prlimit, clr_config_prlimit, },
- { "lxc.pty.max", set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
- { "lxc.rootfs.managed", set_config_rootfs_managed, get_config_rootfs_managed, clr_config_rootfs_managed, },
- { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
- { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
- { "lxc.rootfs.path", set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
- { "lxc.seccomp.allow_nesting", set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, },
- { "lxc.seccomp.notify.cookie", set_config_seccomp_notify_cookie, get_config_seccomp_notify_cookie, clr_config_seccomp_notify_cookie, },
- { "lxc.seccomp.notify.proxy", set_config_seccomp_notify_proxy, get_config_seccomp_notify_proxy, clr_config_seccomp_notify_proxy, },
- { "lxc.seccomp.profile", set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
- { "lxc.selinux.context.keyring", set_config_selinux_context_keyring, get_config_selinux_context_keyring, clr_config_selinux_context_keyring },
- { "lxc.selinux.context", set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
- { "lxc.signal.halt", set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
- { "lxc.signal.reboot", set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
- { "lxc.signal.stop", set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
- { "lxc.start.auto", set_config_start, get_config_start, clr_config_start, },
- { "lxc.start.delay", set_config_start, get_config_start, clr_config_start, },
- { "lxc.start.order", set_config_start, get_config_start, clr_config_start, },
- { "lxc.tty.dir", set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
- { "lxc.tty.max", set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
- { "lxc.uts.name", set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
- { "lxc.sysctl", set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
- { "lxc.proc", set_config_proc, get_config_proc, clr_config_proc, },
+ { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
+ { "lxc.apparmor.profile", set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
+ { "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
+ { "lxc.apparmor.allow_nesting", set_config_apparmor_allow_nesting, get_config_apparmor_allow_nesting, clr_config_apparmor_allow_nesting, },
+ { "lxc.apparmor.raw", set_config_apparmor_raw, get_config_apparmor_raw, clr_config_apparmor_raw, },
+ { "lxc.autodev.tmpfs.size", set_config_autodev_tmpfs_size, get_config_autodev_tmpfs_size, clr_config_autodev_tmpfs_size, },
+ { "lxc.autodev", set_config_autodev, get_config_autodev, clr_config_autodev, },
+ { "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
+ { "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
+ { "lxc.cgroup2", set_config_cgroup2_controller, get_config_cgroup2_controller, clr_config_cgroup2_controller, },
+ { "lxc.cgroup.dir.monitor", set_config_cgroup_monitor_dir, get_config_cgroup_monitor_dir, clr_config_cgroup_monitor_dir, },
+ { "lxc.cgroup.dir.container.inner", set_config_cgroup_container_inner_dir, get_config_cgroup_container_inner_dir, clr_config_cgroup_container_inner_dir, },
+ { "lxc.cgroup.dir.container", set_config_cgroup_container_dir, get_config_cgroup_container_dir, clr_config_cgroup_container_dir, },
+ { "lxc.cgroup.dir", set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
+ { "lxc.cgroup.relative", set_config_cgroup_relative, get_config_cgroup_relative, clr_config_cgroup_relative, },
+ { "lxc.cgroup", set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
+ { "lxc.console.buffer.size", set_config_console_buffer_size, get_config_console_buffer_size, clr_config_console_buffer_size, },
+ { "lxc.console.logfile", set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
+ { "lxc.console.path", set_config_console_path, get_config_console_path, clr_config_console_path, },
+ { "lxc.console.rotate", set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
+ { "lxc.console.size", set_config_console_size, get_config_console_size, clr_config_console_size, },
+ { "lxc.environment", set_config_environment, get_config_environment, clr_config_environment, },
+ { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
+ { "lxc.execute.cmd", set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
+ { "lxc.group", set_config_group, get_config_group, clr_config_group, },
+ { "lxc.hook.autodev", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.clone", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.destroy", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.post-stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.pre-mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.pre-start", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.start", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.start-host", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.hook.version", set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, },
+ { "lxc.hook", set_config_hooks, get_config_hooks, clr_config_hooks, },
+ { "lxc.idmap", set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
+ { "lxc.include", set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
+ { "lxc.init.cmd", set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
+ { "lxc.init.gid", set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
+ { "lxc.init.uid", set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
+ { "lxc.init.cwd", set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, },
+ { "lxc.keyring.session", set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session },
+ { "lxc.log.file", set_config_log_file, get_config_log_file, clr_config_log_file, },
+ { "lxc.log.level", set_config_log_level, get_config_log_level, clr_config_log_level, },
+ { "lxc.log.syslog", set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
+ { "lxc.monitor.unshare", set_config_monitor, get_config_monitor, clr_config_monitor, },
+ { "lxc.monitor.signal.pdeath", set_config_monitor_signal_pdeath, get_config_monitor_signal_pdeath, clr_config_monitor_signal_pdeath, },
+ { "lxc.mount.auto", set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
+ { "lxc.mount.entry", set_config_mount, get_config_mount, clr_config_mount, },
+ { "lxc.mount.fstab", set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
+ { "lxc.namespace.clone", set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
+ { "lxc.namespace.keep", set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
+ { "lxc.namespace.time.offset.boot", set_config_namespace_time_offset_boot, get_config_namespace_time_offset_boot, clr_config_namespace_time_offset_boot, },
+ { "lxc.namespace.time.offset.monotonic", set_config_namespace_time_offset_monotonic, get_config_namespace_time_offset_monotonic, clr_config_namespace_time_offset_monotonic, },
+ { "lxc.namespace.share", set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
+ { "lxc.net.flags", set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
+ { "lxc.net.hwaddr", set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
+ { "lxc.net.ipv4.address", set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
+ { "lxc.net.ipv4.gateway", set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
+ { "lxc.net.ipv6.address", set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
+ { "lxc.net.ipv6.gateway", set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
+ { "lxc.net.link", set_config_net_link, get_config_net_link, clr_config_net_link, },
+ { "lxc.net.l2proxy", set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
+ { "lxc.net.macvlan.mode", set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
+ { "lxc.net.ipvlan.mode", set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
+ { "lxc.net.ipvlan.isolation", set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
+ { "lxc.net.mtu", set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
+ { "lxc.net.name", set_config_net_name, get_config_net_name, clr_config_net_name, },
+ { "lxc.net.script.down", set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
+ { "lxc.net.script.up", set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
+ { "lxc.net.type", set_config_net_type, get_config_net_type, clr_config_net_type, },
+ { "lxc.net.vlan.id", set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
+ { "lxc.net.veth.mode", set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
+ { "lxc.net.veth.pair", set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
+ { "lxc.net.veth.ipv4.route", set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
+ { "lxc.net.veth.ipv6.route", set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
+ { "lxc.net.veth.vlan.id", set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
+ { "lxc.net.veth.vlan.tagged.id", set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
+ { "lxc.net.", set_config_net_nic, get_config_net_nic, clr_config_net_nic, },
+ { "lxc.net", set_config_net, get_config_net, clr_config_net, },
+ { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
+ { "lxc.prlimit", set_config_prlimit, get_config_prlimit, clr_config_prlimit, },
+ { "lxc.pty.max", set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
+ { "lxc.rootfs.managed", set_config_rootfs_managed, get_config_rootfs_managed, clr_config_rootfs_managed, },
+ { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
+ { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
+ { "lxc.rootfs.path", set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
+ { "lxc.seccomp.allow_nesting", set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, },
+ { "lxc.seccomp.notify.cookie", set_config_seccomp_notify_cookie, get_config_seccomp_notify_cookie, clr_config_seccomp_notify_cookie, },
+ { "lxc.seccomp.notify.proxy", set_config_seccomp_notify_proxy, get_config_seccomp_notify_proxy, clr_config_seccomp_notify_proxy, },
+ { "lxc.seccomp.profile", set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
+ { "lxc.selinux.context.keyring", set_config_selinux_context_keyring, get_config_selinux_context_keyring, clr_config_selinux_context_keyring },
+ { "lxc.selinux.context", set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
+ { "lxc.signal.halt", set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
+ { "lxc.signal.reboot", set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
+ { "lxc.signal.stop", set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
+ { "lxc.start.auto", set_config_start, get_config_start, clr_config_start, },
+ { "lxc.start.delay", set_config_start, get_config_start, clr_config_start, },
+ { "lxc.start.order", set_config_start, get_config_start, clr_config_start, },
+ { "lxc.tty.dir", set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
+ { "lxc.tty.max", set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
+ { "lxc.uts.name", set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
+ { "lxc.sysctl", set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
+ { "lxc.proc", set_config_proc, get_config_proc, clr_config_proc, },
};
static const size_t config_jump_table_size = sizeof(config_jump_table) / sizeof(struct lxc_config_t);
@@ -2812,6 +2816,74 @@ static int set_config_namespace_keep(const char *key, const char *value,
return 0;
}
+static int set_config_namespace_time_offset_boot(const char *key, const char *value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ int ret;
+ int64_t offset = 0;
+ char buf[STRLITERALLEN("ms") + 1];
+
+ if (lxc_config_value_empty(value))
+ return clr_config_namespace_time_offset_boot(key, lxc_conf, data);
+
+ ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ // TODO: Handle overflow.
+ if (strcmp(buf, "h") == 0) {
+ lxc_conf->timens.s_boot *= 3600;
+ } else if (strcmp(buf, "m") == 0) {
+ lxc_conf->timens.s_boot *= 60;
+ } else if (strcmp(buf, "s") == 0) {
+ lxc_conf->timens.s_boot = offset;
+ } else if (strcmp(buf, "ms") == 0) {
+ lxc_conf->timens.ns_boot *= 1000000;
+ } else if (strcmp(buf, "us") == 0) {
+ lxc_conf->timens.ns_boot *= 1000;
+ } else if (strcmp(buf, "ns") == 0) {
+ lxc_conf->timens.ns_boot = offset;
+ } else {
+ return ret_errno(EINVAL);
+ }
+
+ return 0;
+}
+
+static int set_config_namespace_time_offset_monotonic(const char *key, const char *value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ int ret;
+ int64_t offset = 0;
+ char buf[STRLITERALLEN("ms") + 1];
+
+ if (lxc_config_value_empty(value))
+ return clr_config_namespace_time_offset_monotonic(key, lxc_conf, data);
+
+ ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ // TODO: Handle overflow.
+ if (strcmp(buf, "h") == 0) {
+ lxc_conf->timens.s_monotonic *= 3600;
+ } else if (strcmp(buf, "m") == 0) {
+ lxc_conf->timens.s_monotonic *= 60;
+ } else if (strcmp(buf, "s") == 0) {
+ lxc_conf->timens.s_monotonic = offset;
+ } else if (strcmp(buf, "ms") == 0) {
+ lxc_conf->timens.ns_monotonic *= 1000000;
+ } else if (strcmp(buf, "us") == 0) {
+ lxc_conf->timens.ns_monotonic *= 1000;
+ } else if (strcmp(buf, "ns") == 0) {
+ lxc_conf->timens.ns_monotonic = offset;
+ } else {
+ return ret_errno(EINVAL);
+ }
+
+ return 0;
+}
+
static int set_config_namespace_share(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
@@ -4497,6 +4569,46 @@ static int get_config_namespace_keep(const char *key, char *retv, int inlen,
return fulllen;
}
+static int get_config_namespace_time_offset_boot(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ int len;
+ int fulllen = 0;
+
+ if (!retv)
+ inlen = 0;
+ else
+ memset(retv, 0, inlen);
+
+ if (c->timens.s_boot) {
+ strprint(retv, inlen, "%" PRId64 " s\n", c->timens.s_boot);
+ } else {
+ strprint(retv, inlen, "%" PRId64 " ns\n", c->timens.ns_boot);
+ }
+
+ return fulllen;
+}
+
+static int get_config_namespace_time_offset_monotonic(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ int len;
+ int fulllen = 0;
+
+ if (!retv)
+ inlen = 0;
+ else
+ memset(retv, 0, inlen);
+
+ if (c->timens.s_monotonic) {
+ strprint(retv, inlen, "%" PRId64 "s\n", c->timens.s_monotonic);
+ } else {
+ strprint(retv, inlen, "%" PRId64 "ns\n", c->timens.ns_monotonic);
+ }
+
+ return fulllen;
+}
+
static int get_config_namespace_share(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
@@ -5030,6 +5142,22 @@ static int clr_config_namespace_keep(const char *key, struct lxc_conf *lxc_conf,
return 0;
}
+static int clr_config_namespace_time_offset_boot(const char *key, struct lxc_conf *lxc_conf,
+ void *data)
+{
+ lxc_conf->timens.s_boot = 0;
+ lxc_conf->timens.ns_boot = 0;
+ return 0;
+}
+
+static int clr_config_namespace_time_offset_monotonic(const char *key, struct lxc_conf *lxc_conf,
+ void *data)
+{
+ lxc_conf->timens.s_monotonic = 0;
+ lxc_conf->timens.ns_monotonic = 0;
+ return 0;
+}
+
static int clr_config_namespace_share(const char *key,
struct lxc_conf *lxc_conf, void *data)
{
diff --git a/src/lxc/string_utils.c b/src/lxc/string_utils.c
index dcb1160e4c..dd55abd74d 100644
--- a/src/lxc/string_utils.c
+++ b/src/lxc/string_utils.c
@@ -667,6 +667,54 @@ int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
return 0;
}
+int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, char *residual,
+ size_t residual_len)
+{
+ char *remaining = NULL;
+ int64_t u;
+
+ if (residual && residual_len == 0)
+ return ret_errno(EINVAL);
+
+ if (residual_len != 0 && residual)
+ return ret_errno(EINVAL);
+
+ while (isspace(*numstr))
+ numstr++;
+
+ if (*numstr == '-')
+ return -EINVAL;
+
+ errno = 0;
+ u = strtoll(numstr, &remaining, base);
+ if (errno == ERANGE && u == INT64_MAX)
+ return -ERANGE;
+
+ if (remaining == numstr)
+ return -EINVAL;
+
+ if (residual) {
+ size_t len = 0;
+
+ if (*remaining == '\0') {
+ memset(residual, 0, residual_len);
+ goto out;
+ }
+
+ len = strlen(remaining);
+ if (len >= residual_len)
+ return -EINVAL;
+
+ memcpy(residual, remaining, len);
+ } else if (*remaining != '\0') {
+ return -EINVAL;
+ }
+
+out:
+ *converted = u;
+ return 0;
+}
+
int lxc_safe_int(const char *numstr, int *converted)
{
char *err = NULL;
diff --git a/src/lxc/string_utils.h b/src/lxc/string_utils.h
index 0f7d2ff21e..2ce3774423 100644
--- a/src/lxc/string_utils.h
+++ b/src/lxc/string_utils.h
@@ -76,6 +76,8 @@ extern int lxc_safe_long(const char *numstr, long int *converted);
extern int lxc_safe_long_long(const char *numstr, long long int *converted);
extern int lxc_safe_ulong(const char *numstr, unsigned long *converted);
extern int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base);
+extern int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, char *residual,
+ size_t residual_len);
/* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */
extern int parse_byte_size_string(const char *s, int64_t *converted);
From 690550d47d251188f541cf179170a4b29203b89e Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 25 Jun 2020 16:11:21 +0200
Subject: [PATCH 3/4] lxc: add time namespace support
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/conf.c | 1 +
src/lxc/confile.c | 48 +++++++++++++++++----------------
src/lxc/file_utils.c | 9 ++++---
src/lxc/file_utils.h | 2 +-
src/lxc/namespace.c | 3 ++-
src/lxc/namespace.h | 1 +
src/lxc/start.c | 60 ++++++++++++++++++++++++++++++++++++++++++
src/lxc/string_utils.c | 5 +---
8 files changed, 97 insertions(+), 32 deletions(-)
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 4aafca3cbb..48cb74891f 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2599,6 +2599,7 @@ struct lxc_conf *lxc_conf_init(void)
new->init_gid = 0;
memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX);
+ memset(&new->timens, 0, sizeof(struct timens_offsets));
seccomp_conf_init(new);
return new;
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 1a378f740f..83355c0d19 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -222,9 +222,9 @@ static struct lxc_config_t config_jump_table[] = {
{ "lxc.mount.fstab", set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
{ "lxc.namespace.clone", set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
{ "lxc.namespace.keep", set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
+ { "lxc.namespace.share", set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
{ "lxc.namespace.time.offset.boot", set_config_namespace_time_offset_boot, get_config_namespace_time_offset_boot, clr_config_namespace_time_offset_boot, },
{ "lxc.namespace.time.offset.monotonic", set_config_namespace_time_offset_monotonic, get_config_namespace_time_offset_monotonic, clr_config_namespace_time_offset_monotonic, },
- { "lxc.namespace.share", set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
{ "lxc.net.flags", set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
{ "lxc.net.hwaddr", set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
{ "lxc.net.ipv4.address", set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
@@ -2820,6 +2820,7 @@ static int set_config_namespace_time_offset_boot(const char *key, const char *va
struct lxc_conf *lxc_conf, void *data)
{
int ret;
+ char *unit;
int64_t offset = 0;
char buf[STRLITERALLEN("ms") + 1];
@@ -2831,17 +2832,18 @@ static int set_config_namespace_time_offset_boot(const char *key, const char *va
return ret;
// TODO: Handle overflow.
- if (strcmp(buf, "h") == 0) {
- lxc_conf->timens.s_boot *= 3600;
- } else if (strcmp(buf, "m") == 0) {
- lxc_conf->timens.s_boot *= 60;
- } else if (strcmp(buf, "s") == 0) {
+ unit = lxc_trim_whitespace_in_place(buf);
+ if (strcmp(unit, "h") == 0) {
+ lxc_conf->timens.s_boot = offset * 3600;
+ } else if (strcmp(unit, "m") == 0) {
+ lxc_conf->timens.s_boot = offset * 60;
+ } else if (strcmp(unit, "s") == 0) {
lxc_conf->timens.s_boot = offset;
- } else if (strcmp(buf, "ms") == 0) {
- lxc_conf->timens.ns_boot *= 1000000;
- } else if (strcmp(buf, "us") == 0) {
- lxc_conf->timens.ns_boot *= 1000;
- } else if (strcmp(buf, "ns") == 0) {
+ } else if (strcmp(unit, "ms") == 0) {
+ lxc_conf->timens.ns_boot = offset * 1000000;
+ } else if (strcmp(unit, "us") == 0) {
+ lxc_conf->timens.ns_boot = offset * 1000;
+ } else if (strcmp(unit, "ns") == 0) {
lxc_conf->timens.ns_boot = offset;
} else {
return ret_errno(EINVAL);
@@ -2851,9 +2853,10 @@ static int set_config_namespace_time_offset_boot(const char *key, const char *va
}
static int set_config_namespace_time_offset_monotonic(const char *key, const char *value,
- struct lxc_conf *lxc_conf, void *data)
+ struct lxc_conf *lxc_conf, void *data)
{
int ret;
+ char *unit;
int64_t offset = 0;
char buf[STRLITERALLEN("ms") + 1];
@@ -2865,17 +2868,18 @@ static int set_config_namespace_time_offset_monotonic(const char *key, const cha
return ret;
// TODO: Handle overflow.
- if (strcmp(buf, "h") == 0) {
- lxc_conf->timens.s_monotonic *= 3600;
- } else if (strcmp(buf, "m") == 0) {
- lxc_conf->timens.s_monotonic *= 60;
- } else if (strcmp(buf, "s") == 0) {
+ unit = lxc_trim_whitespace_in_place(buf);
+ if (strcmp(unit, "h") == 0) {
+ lxc_conf->timens.s_monotonic = offset * 3600;
+ } else if (strcmp(unit, "m") == 0) {
+ lxc_conf->timens.s_monotonic = offset * 60;
+ } else if (strcmp(unit, "s") == 0) {
lxc_conf->timens.s_monotonic = offset;
- } else if (strcmp(buf, "ms") == 0) {
- lxc_conf->timens.ns_monotonic *= 1000000;
- } else if (strcmp(buf, "us") == 0) {
- lxc_conf->timens.ns_monotonic *= 1000;
- } else if (strcmp(buf, "ns") == 0) {
+ } else if (strcmp(unit, "ms") == 0) {
+ lxc_conf->timens.ns_monotonic = offset * 1000000;
+ } else if (strcmp(unit, "us") == 0) {
+ lxc_conf->timens.ns_monotonic = offset * 1000;
+ } else if (strcmp(unit, "ns") == 0) {
lxc_conf->timens.ns_monotonic = offset;
} else {
return ret_errno(EINVAL);
diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c
index 77e71d7849..85e24fea20 100644
--- a/src/lxc/file_utils.c
+++ b/src/lxc/file_utils.c
@@ -513,13 +513,14 @@ FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer)
return f;
}
-int timens_offset_write(clockid_t clk_id, int64_t offset)
+int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset)
{
__do_close int fd = -EBADF;
int ret;
ssize_t len;
- char buf[INTTYPE_TO_STRLEN(int) + STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) +
- STRLITERALLEN(" 0") + 1];
+ char buf[INTTYPE_TO_STRLEN(int) +
+ STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) +
+ STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) + 1];
if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW)
clk_id = CLOCK_MONOTONIC;
@@ -528,7 +529,7 @@ int timens_offset_write(clockid_t clk_id, int64_t offset)
if (fd < 0)
return -errno;
- len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset);
+ len = snprintf(buf, sizeof(buf), "%d %" PRId64 " %" PRId64, clk_id, s_offset, ns_offset);
if (len < 0 || len >= sizeof(buf))
return ret_errno(EFBIG);
diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h
index eeaf02811b..6f11ec9d7a 100644
--- a/src/lxc/file_utils.h
+++ b/src/lxc/file_utils.h
@@ -82,6 +82,6 @@ extern int lxc_open_dirfd(const char *dir);
extern FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer);
extern FILE *fopen_cached(const char *path, const char *mode,
void **caller_freed_buffer);
-extern int timens_offset_write(clockid_t clk_id, int64_t offset);
+extern int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset);
#endif /* __LXC_FILE_UTILS_H */
diff --git a/src/lxc/namespace.c b/src/lxc/namespace.c
index f2e0175630..a46923078d 100644
--- a/src/lxc/namespace.c
+++ b/src/lxc/namespace.c
@@ -44,7 +44,8 @@ const struct ns_info ns_info[LXC_NS_MAX] = {
[LXC_NS_UTS] = { "uts", CLONE_NEWUTS, "CLONE_NEWUTS", "LXC_UTS_NS" },
[LXC_NS_IPC] = { "ipc", CLONE_NEWIPC, "CLONE_NEWIPC", "LXC_IPC_NS" },
[LXC_NS_NET] = { "net", CLONE_NEWNET, "CLONE_NEWNET", "LXC_NET_NS" },
- [LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS" }
+ [LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS" },
+ [LXC_NS_TIME] = { "time", CLONE_NEWTIME, "CLONE_NEWTIME", "LXC_TIME_NS" },
};
int lxc_namespace_2_cloneflag(const char *namespace)
diff --git a/src/lxc/namespace.h b/src/lxc/namespace.h
index 84976f60f2..59b26fa60d 100644
--- a/src/lxc/namespace.h
+++ b/src/lxc/namespace.h
@@ -15,6 +15,7 @@ enum {
LXC_NS_IPC,
LXC_NS_NET,
LXC_NS_CGROUP,
+ LXC_NS_TIME,
LXC_NS_MAX
};
diff --git a/src/lxc/start.c b/src/lxc/start.c
index fd969c4332..16e519e993 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1205,6 +1205,55 @@ static int do_start(void *data)
}
}
+ if (handler->ns_clone_flags & CLONE_NEWTIME) {
+ ret = unshare(CLONE_NEWTIME);
+ if (ret < 0) {
+ if (errno != EINVAL) {
+ SYSERROR("Failed to unshare CLONE_NEWTIME");
+ goto out_warn_father;
+ }
+
+ handler->ns_clone_flags &= ~CLONE_NEWTIME;
+ SYSINFO("Kernel does not support CLONE_NEWTIME");
+ } else {
+ __do_close int timens_fd = -EBADF;
+
+ INFO("Unshared CLONE_NEWTIME");
+
+ if (handler->conf->timens.s_boot)
+ ret = timens_offset_write(CLOCK_BOOTTIME, handler->conf->timens.s_boot, 0);
+ else if (handler->conf->timens.ns_boot)
+ ret = timens_offset_write(CLOCK_BOOTTIME, 0, handler->conf->timens.ns_boot);
+ if (ret) {
+ SYSERROR("Failed to write CLONE_BOOTTIME offset");
+ goto out_warn_father;
+ }
+ TRACE("Wrote CLOCK_BOOTTIME offset");
+
+ if (handler->conf->timens.s_monotonic)
+ ret = timens_offset_write(CLOCK_MONOTONIC, handler->conf->timens.s_monotonic, 0);
+ else if (handler->conf->timens.ns_monotonic)
+ ret = timens_offset_write(CLOCK_MONOTONIC, 0, handler->conf->timens.ns_monotonic);
+ if (ret) {
+ SYSERROR("Failed to write CLONE_MONOTONIC offset");
+ goto out_warn_father;
+ }
+ TRACE("Wrote CLOCK_MONOTONIC offset");
+
+ timens_fd = open("/proc/self/ns/time_for_children", O_RDONLY | O_CLOEXEC);
+ if (timens_fd < 0) {
+ SYSERROR("Failed to open \"/proc/self/ns/time_for_children\"");
+ goto out_warn_father;
+ }
+
+ ret = setns(timens_fd, CLONE_NEWTIME);
+ if (ret) {
+ SYSERROR("Failed to setns(%d(\"/proc/self/ns/time_for_children\"))", timens_fd);
+ goto out_warn_father;
+ }
+ }
+ }
+
/* Add the requested environment variables to the current environment to
* allow them to be used by the various hooks, such as the start hook
* below.
@@ -1452,6 +1501,8 @@ int resolve_clone_flags(struct lxc_handler *handler)
{
int i;
struct lxc_conf *conf = handler->conf;
+ bool wants_timens = conf->timens.s_boot || conf->timens.ns_boot ||
+ conf->timens.s_monotonic || conf->timens.ns_monotonic;
for (i = 0; i < LXC_NS_MAX; i++) {
if (conf->ns_keep) {
@@ -1470,6 +1521,9 @@ int resolve_clone_flags(struct lxc_handler *handler)
if (i == LXC_NS_CGROUP && !cgns_supported())
continue;
+ if (i == LXC_NS_TIME && !wants_timens)
+ continue;
+
handler->ns_clone_flags |= ns_info[i].clone_flag;
}
@@ -1480,6 +1534,9 @@ int resolve_clone_flags(struct lxc_handler *handler)
TRACE("Sharing %s namespace", ns_info[i].proc_name);
}
+ if (wants_timens && (conf->ns_keep & ns_info[LXC_NS_TIME].clone_flag))
+ return log_trace_errno(-1, EINVAL, "Requested to keep time namespace while also specifying offsets");
+
return 0;
}
@@ -1614,6 +1671,9 @@ static int lxc_spawn(struct lxc_handler *handler)
/* The cgroup namespace gets unshare()ed not clone()ed. */
handler->ns_on_clone_flags &= ~CLONE_NEWCGROUP;
+ /* The time namespace (currently) gets unshare()ed not clone()ed. */
+ handler->ns_on_clone_flags &= ~CLONE_NEWTIME;
+
if (share_ns) {
pid_t attacher_pid;
diff --git a/src/lxc/string_utils.c b/src/lxc/string_utils.c
index dd55abd74d..3d0d31a6c6 100644
--- a/src/lxc/string_utils.c
+++ b/src/lxc/string_utils.c
@@ -676,15 +676,12 @@ int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, ch
if (residual && residual_len == 0)
return ret_errno(EINVAL);
- if (residual_len != 0 && residual)
+ if (!residual && residual_len != 0)
return ret_errno(EINVAL);
while (isspace(*numstr))
numstr++;
- if (*numstr == '-')
- return -EINVAL;
-
errno = 0;
u = strtoll(numstr, &remaining, base);
if (errno == ERANGE && u == INT64_MAX)
From e9886b3883aec7f0f28f132097039a60ab1ef16a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 25 Jun 2020 22:29:24 +0200
Subject: [PATCH 4/4] api: add time_namespace api extension
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
doc/api-extensions.md | 5 +++++
doc/lxc.container.conf.sgml.in | 27 +++++++++++++++++++++++++++
src/lxc/api_extensions.h | 1 +
3 files changed, 33 insertions(+)
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index e8b5eb0890..d7b915d283 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -122,3 +122,8 @@ When running on kernels that support pidfds LXC will rely on them for most opera
## cgroup\_advanced\_isolation
Privileged containers will usually be able to override the cgroup limits given to them. This introduces three new configuration keys `lxc.cgroup.dir.monitor`, `lxc.cgroup.dir.container`, and `lxc.cgroup.dir.container.inner`. The `lxc.cgroup.dir.monitor` and `lxc.cgroup.dir.container` keys can be used to set to place the `monitor` and the `container` into different cgroups. The `lxc.cgroup.dir.container.inner` key can be set to a cgroup that is concatenated with `lxc.cgroup.dir.container`. When `lxc.cgroup.dir.container.inner` is set the container will be placed into the `lxc.cgroup.dir.container.inner` cgroup but the limits will be set in the `lxc.cgroup.dir.container` cgroup. This way privileged containers cannot escape their cgroup limits.
+
+
+## time\_namespace
+
+This adds time namespace support to LXC.
diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 740a02f339..e6916ef109 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -1806,6 +1806,33 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.namespace.time.offset.boot</option>
+ </term>
+ <listitem>
+ <para>
+ Specify a positive or negative offset for the boottime clock. The
+ format accepts hours (h), minutes (m), seconds (s),
+ milliseconds (ms), microseconds (us), and nanoseconds (ns).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.namespace.time.offset.monotonic</option>
+ </term>
+ <listitem>
+ <para>
+ Specify a positive or negative offset for the montonic clock. The
+ format accepts hours (h), minutes (m), seconds (s),
+ milliseconds (ms), microseconds (us), and nanoseconds (ns).
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect2>
diff --git a/src/lxc/api_extensions.h b/src/lxc/api_extensions.h
index 2bbdc5e43a..8061784c85 100644
--- a/src/lxc/api_extensions.h
+++ b/src/lxc/api_extensions.h
@@ -41,6 +41,7 @@ static char *api_extensions[] = {
"pidfd",
"cgroup_advanced_isolation",
"network_bridge_vlan",
+ "time_namespace",
};
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
More information about the lxc-devel
mailing list