Support time namespace

"time" namespace was introduced in Linux v5.6
support new time namespace to set boottime and monotonic time offset

Example runtime spec

"timeOffsets": {
    "monotonic": {
        "secs": 172800,
        "nanosecs": 0
    },
    "boottime": {
        "secs": 604800,
        "nanosecs": 0
    }
}

Signed-off-by: Chethan Suresh <chethan.suresh@sony.com>
This commit is contained in:
Chethan Suresh
2023-08-03 10:12:01 +05:30
parent dbe8434359
commit ebc2e7c435
9 changed files with 61 additions and 0 deletions
+3
View File
@@ -216,6 +216,9 @@ type Config struct {
// Do not try to remount a bind mount again after the first attempt failed on source // Do not try to remount a bind mount again after the first attempt failed on source
// filesystems that have nodev, noexec, nosuid, noatime, relatime, strictatime, nodiratime set // filesystems that have nodev, noexec, nosuid, noatime, relatime, strictatime, nodiratime set
NoMountFallback bool `json:"no_mount_fallback,omitempty"` NoMountFallback bool `json:"no_mount_fallback,omitempty"`
// TimeOffsets specifies the offset for supporting time namespaces.
TimeOffsets map[string]specs.LinuxTimeOffset `json:"time_offsets,omitempty"`
} }
type ( type (
+4
View File
@@ -14,6 +14,7 @@ const (
NEWIPC NamespaceType = "NEWIPC" NEWIPC NamespaceType = "NEWIPC"
NEWUSER NamespaceType = "NEWUSER" NEWUSER NamespaceType = "NEWUSER"
NEWCGROUP NamespaceType = "NEWCGROUP" NEWCGROUP NamespaceType = "NEWCGROUP"
NEWTIME NamespaceType = "NEWTIME"
) )
var ( var (
@@ -38,6 +39,8 @@ func NsName(ns NamespaceType) string {
return "uts" return "uts"
case NEWCGROUP: case NEWCGROUP:
return "cgroup" return "cgroup"
case NEWTIME:
return "time"
} }
return "" return ""
} }
@@ -72,6 +75,7 @@ func NamespaceTypes() []NamespaceType {
NEWPID, NEWPID,
NEWNS, NEWNS,
NEWCGROUP, NEWCGROUP,
NEWTIME,
} }
} }
@@ -17,6 +17,7 @@ var namespaceInfo = map[NamespaceType]int{
NEWUTS: unix.CLONE_NEWUTS, NEWUTS: unix.CLONE_NEWUTS,
NEWPID: unix.CLONE_NEWPID, NEWPID: unix.CLONE_NEWPID,
NEWCGROUP: unix.CLONE_NEWCGROUP, NEWCGROUP: unix.CLONE_NEWCGROUP,
NEWTIME: unix.CLONE_NEWTIME,
} }
// CloneFlags parses the container's Namespaces options to set the correct // CloneFlags parses the container's Namespaces options to set the correct
@@ -106,6 +106,12 @@ func namespaces(config *configs.Config) error {
} }
} }
if config.Namespaces.Contains(configs.NEWTIME) {
if _, err := os.Stat("/proc/self/timens_offsets"); os.IsNotExist(err) {
return errors.New("time namespaces aren't enabled in the kernel")
}
}
return nil return nil
} }
+12
View File
@@ -2321,6 +2321,18 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
}) })
} }
// write boottime and monotonic time ns offsets.
if c.config.Namespaces.Contains(configs.NEWTIME) && c.config.TimeOffsets != nil {
var offsetSpec bytes.Buffer
for clock, offset := range c.config.TimeOffsets {
fmt.Fprintf(&offsetSpec, "%s %d %d\n", clock, offset.Secs, offset.Nanosecs)
}
r.AddData(&Bytemsg{
Type: TimeOffsetsAttr,
Value: offsetSpec.Bytes(),
})
}
return bytes.NewReader(r.Serialize()), nil return bytes.NewReader(r.Serialize()), nil
} }
+1
View File
@@ -23,6 +23,7 @@ const (
GidmapPathAttr uint16 = 27289 GidmapPathAttr uint16 = 27289
MountSourcesAttr uint16 = 27290 MountSourcesAttr uint16 = 27290
IdmapSourcesAttr uint16 = 27291 IdmapSourcesAttr uint16 = 27291
TimeOffsetsAttr uint16 = 27292
) )
type Int32msg struct { type Int32msg struct {
+3
View File
@@ -28,5 +28,8 @@
#ifndef CLONE_NEWNET #ifndef CLONE_NEWNET
# define CLONE_NEWNET 0x40000000 /* New network namespace */ # define CLONE_NEWNET 0x40000000 /* New network namespace */
#endif #endif
#ifndef CLONE_NEWTIME
# define CLONE_NEWTIME 0x00000080 /* New time namespace */
#endif
#endif /* NSENTER_NAMESPACE_H */ #endif /* NSENTER_NAMESPACE_H */
+27
View File
@@ -104,6 +104,10 @@ struct nlconfig_t {
/* Idmap sources opened outside the container userns which will be id mapped. */ /* Idmap sources opened outside the container userns which will be id mapped. */
char *idmapsources; char *idmapsources;
size_t idmapsources_len; size_t idmapsources_len;
/* Time NS offsets. */
char *timensoffset;
size_t timensoffset_len;
}; };
/* /*
@@ -122,6 +126,7 @@ struct nlconfig_t {
#define GIDMAPPATH_ATTR 27289 #define GIDMAPPATH_ATTR 27289
#define MOUNT_SOURCES_ATTR 27290 #define MOUNT_SOURCES_ATTR 27290
#define IDMAP_SOURCES_ATTR 27291 #define IDMAP_SOURCES_ATTR 27291
#define TIMENSOFFSET_ATTR 27292
/* /*
* Use the raw syscall for versions of glibc which don't include a function for * Use the raw syscall for versions of glibc which don't include a function for
@@ -351,6 +356,8 @@ static int nsflag(char *name)
return CLONE_NEWUSER; return CLONE_NEWUSER;
else if (!strcmp(name, "uts")) else if (!strcmp(name, "uts"))
return CLONE_NEWUTS; return CLONE_NEWUTS;
else if (!strcmp(name, "time"))
return CLONE_NEWTIME;
/* If we don't recognise a name, fallback to 0. */ /* If we don't recognise a name, fallback to 0. */
return 0; return 0;
@@ -445,6 +452,10 @@ static void nl_parse(int fd, struct nlconfig_t *config)
config->idmapsources = current; config->idmapsources = current;
config->idmapsources_len = payload_len; config->idmapsources_len = payload_len;
break; break;
case TIMENSOFFSET_ATTR:
config->timensoffset = current;
config->timensoffset_len = payload_len;
break;
default: default:
bail("unknown netlink message type %d", nlattr->nla_type); bail("unknown netlink message type %d", nlattr->nla_type);
} }
@@ -747,6 +758,17 @@ void receive_idmapsources(int sockfd)
receive_fd_sources(sockfd, "_LIBCONTAINER_IDMAP_FDS"); receive_fd_sources(sockfd, "_LIBCONTAINER_IDMAP_FDS");
} }
static void update_timens(char *map, size_t map_len)
{
if (map == NULL || map_len == 0)
return;
write_log(DEBUG, "update /proc/self/timens_offsets to '%s'", map);
if (write_file(map, map_len, "/proc/self/timens_offsets") < 0) {
if (errno != EPERM)
bail("failed to update /proc/self/timens_offsets");
}
}
void nsexec(void) void nsexec(void)
{ {
int pipenum; int pipenum;
@@ -1185,6 +1207,11 @@ void nsexec(void)
bail("failed to sync with parent: SYNC_MOUNT_IDMAP_ACK: got %u", s); bail("failed to sync with parent: SYNC_MOUNT_IDMAP_ACK: got %u", s);
} }
/*
* set boottime and monotonic timens offsets.
*/
update_timens(config.timensoffset, config.timensoffset_len);
/* /*
* TODO: What about non-namespace clone flags that we're dropping here? * TODO: What about non-namespace clone flags that we're dropping here?
* *
+4
View File
@@ -49,6 +49,7 @@ func initMaps() {
specs.IPCNamespace: configs.NEWIPC, specs.IPCNamespace: configs.NEWIPC,
specs.UTSNamespace: configs.NEWUTS, specs.UTSNamespace: configs.NEWUTS,
specs.CgroupNamespace: configs.NEWCGROUP, specs.CgroupNamespace: configs.NEWCGROUP,
specs.TimeNamespace: configs.NEWTIME,
} }
mountPropagationMapping = map[string]int{ mountPropagationMapping = map[string]int{
@@ -435,6 +436,9 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema, MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
} }
} }
// update timens offsets
config.TimeOffsets = spec.Linux.TimeOffsets
} }
// Set the host UID that should own the container's cgroup. // Set the host UID that should own the container's cgroup.