Unverified Commit b2ff0ccc by Stéphane Graber Committed by GitHub

Merge pull request #3461 from brauner/2020-06-25/time_namespace

time namespace support
parents f0a3c722 7fb5a8df
......@@ -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.
......@@ -1806,6 +1806,33 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>lxc.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.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>
......
......@@ -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);
......
......@@ -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;
......
......@@ -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,
......
......@@ -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)
{
......
......@@ -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;
}
......@@ -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 */
......@@ -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)
......
......@@ -15,6 +15,7 @@ enum {
LXC_NS_IPC,
LXC_NS_NET,
LXC_NS_CGROUP,
LXC_NS_TIME,
LXC_NS_MAX
};
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment