[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