From: Christian Brauner Date: Thu, 25 Jun 2020 12:39:29 +0000 (+0200) Subject: lxc: add time namespace support X-Git-Tag: lxc-5.0.0~407^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70fd7fc9ba5d1d88119c14d42bdb9d4d19801738;p=thirdparty%2Flxc.git lxc: add time namespace support Signed-off-by: Christian Brauner --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 4aafca3cb..48cb74891 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/conf.h b/src/lxc/conf.h index b72afbaa5..7f54539e0 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 68403e65e..c92e19820 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(time_offset_boot); +lxc_config_define(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.share", set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, }, + { "lxc.time.offset.boot", set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, }, + { "lxc.time.offset.monotonic", set_config_time_offset_monotonic, get_config_time_offset_monotonic, clr_config_time_offset_monotonic, }, + { "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,76 @@ static int set_config_namespace_keep(const char *key, const char *value, return 0; } +static int set_config_time_offset_boot(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + int ret; + char *unit; + int64_t offset = 0; + char buf[STRLITERALLEN("ms") + 1]; + + if (lxc_config_value_empty(value)) + return clr_config_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. */ + 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(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); + + return 0; +} + +static int set_config_time_offset_monotonic(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + int ret; + char *unit; + int64_t offset = 0; + char buf[STRLITERALLEN("ms") + 1]; + + if (lxc_config_value_empty(value)) + return clr_config_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. + 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(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); + + return 0; +} + static int set_config_namespace_share(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { @@ -4497,6 +4571,46 @@ static int get_config_namespace_keep(const char *key, char *retv, int inlen, return fulllen; } +static int get_config_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_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 +5144,20 @@ static int clr_config_namespace_keep(const char *key, struct lxc_conf *lxc_conf, return 0; } +static int clr_config_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_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/file_utils.c b/src/lxc/file_utils.c index 1689cbaa7..85e24fea2 100644 --- a/src/lxc/file_utils.c +++ b/src/lxc/file_utils.c @@ -512,3 +512,30 @@ 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 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(" ") + INTTYPE_TO_STRLEN(int64_t) + 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 %" PRId64 " %" PRId64, clk_id, s_offset, ns_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 f9c8abe03..6f11ec9d7 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 s_offset, int64_t ns_offset); #endif /* __LXC_FILE_UTILS_H */ diff --git a/src/lxc/namespace.c b/src/lxc/namespace.c index f2e017563..a46923078 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 84976f60f..59b26fa60 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 fd969c433..16e519e99 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 dcb1160e4..3d0d31a6c 100644 --- a/src/lxc/string_utils.c +++ b/src/lxc/string_utils.c @@ -667,6 +667,51 @@ 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 && residual_len != 0) + return ret_errno(EINVAL); + + while (isspace(*numstr)) + numstr++; + + 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 0f7d2ff21..2ce377442 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);