The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/3461

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
From fdd0753cf752b944c7a2ad96427ef5af2aadfac2 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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);
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to