[PATCH 1/4] ns: prepare time namespace for clone3()

From: Adrian Reber
Date: Tue Mar 17 2020 - 04:34:05 EST


To enable clone3()ing a process directly into a new time namespace with
a clock offset, this changes the time namespace code by renaming the
variable proc_timens_offset (which was used to set a timens offset via
/proc) to set_timens_offset to avoid confusion why it will be used in
clone3() without being related to /proc.

This also moves out the code of actually setting the clock offsets to
its own function to be later used via clone3().

Signed-off-by: Adrian Reber <areber@xxxxxxxxxx>
---
fs/proc/base.c | 4 +-
include/linux/time_namespace.h | 16 +++--
kernel/time/namespace.c | 126 +++++++++++++++++----------------
3 files changed, 78 insertions(+), 68 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index c7c64272b0fa..2ca68f11ff0e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1554,7 +1554,7 @@ static ssize_t timens_offsets_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct inode *inode = file_inode(file);
- struct proc_timens_offset offsets[2];
+ struct set_timens_offset offsets[2];
char *kbuf = NULL, *pos, *next_line;
struct task_struct *p;
int ret, noffsets;
@@ -1572,7 +1572,7 @@ static ssize_t timens_offsets_write(struct file *file, const char __user *buf,
ret = -EINVAL;
noffsets = 0;
for (pos = kbuf; pos; pos = next_line) {
- struct proc_timens_offset *off = &offsets[noffsets];
+ struct set_timens_offset *off = &offsets[noffsets];
int err;

/* Find the end of line and ensure we don't look past it */
diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h
index 824d54e057eb..fb4ca4402a2a 100644
--- a/include/linux/time_namespace.h
+++ b/include/linux/time_namespace.h
@@ -30,6 +30,15 @@ struct time_namespace {

extern struct time_namespace init_time_ns;

+/*
+ * This structure is used to set the time namespace offset
+ * via /proc as well as via clone3().
+ */
+struct set_timens_offset {
+ int clockid;
+ struct timespec64 val;
+};
+
#ifdef CONFIG_TIME_NS
extern int vdso_join_timens(struct task_struct *task,
struct time_namespace *ns);
@@ -54,13 +63,8 @@ static inline void put_time_ns(struct time_namespace *ns)

void proc_timens_show_offsets(struct task_struct *p, struct seq_file *m);

-struct proc_timens_offset {
- int clockid;
- struct timespec64 val;
-};
-
int proc_timens_set_offset(struct file *file, struct task_struct *p,
- struct proc_timens_offset *offsets, int n);
+ struct set_timens_offset *offsets, int n);

static inline void timens_add_monotonic(struct timespec64 *ts)
{
diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c
index 12858507d75a..839efa7c6886 100644
--- a/kernel/time/namespace.c
+++ b/kernel/time/namespace.c
@@ -307,6 +307,69 @@ static int timens_install(struct nsproxy *nsproxy, struct ns_common *new)
return 0;
}

+static int timens_set_offset(struct task_struct *p, struct time_namespace *ns,
+ struct set_timens_offset *offsets, int noffsets)
+{
+ struct timespec64 tp;
+ int i, err;
+
+ for (i = 0; i < noffsets; i++) {
+ struct set_timens_offset *off = &offsets[i];
+
+ switch (off->clockid) {
+ case CLOCK_MONOTONIC:
+ ktime_get_ts64(&tp);
+ break;
+ case CLOCK_BOOTTIME:
+ ktime_get_boottime_ts64(&tp);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (off->val.tv_sec > KTIME_SEC_MAX ||
+ off->val.tv_sec < -KTIME_SEC_MAX)
+ return -ERANGE;
+
+ tp = timespec64_add(tp, off->val);
+ /*
+ * KTIME_SEC_MAX is divided by 2 to be sure that KTIME_MAX is
+ * still unreachable.
+ */
+ if (tp.tv_sec < 0 || tp.tv_sec > KTIME_SEC_MAX / 2)
+ return -ERANGE;
+ }
+
+ mutex_lock(&offset_lock);
+ if (ns->frozen_offsets) {
+ err = -EACCES;
+ goto out_unlock;
+ }
+
+ err = 0;
+ /* Don't report errors after this line */
+ for (i = 0; i < noffsets; i++) {
+ struct set_timens_offset *off = &offsets[i];
+ struct timespec64 *offset = NULL;
+
+ switch (off->clockid) {
+ case CLOCK_MONOTONIC:
+ offset = &ns->offsets.monotonic;
+ break;
+ case CLOCK_BOOTTIME:
+ offset = &ns->offsets.boottime;
+ break;
+ }
+
+ *offset = off->val;
+ }
+
+out_unlock:
+ mutex_unlock(&offset_lock);
+
+ return err;
+}
+
int timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk)
{
struct ns_common *nsc = &nsproxy->time_ns_for_children->ns;
@@ -356,12 +419,11 @@ void proc_timens_show_offsets(struct task_struct *p, struct seq_file *m)
}

int proc_timens_set_offset(struct file *file, struct task_struct *p,
- struct proc_timens_offset *offsets, int noffsets)
+ struct set_timens_offset *offsets, int noffsets)
{
struct ns_common *ns;
struct time_namespace *time_ns;
- struct timespec64 tp;
- int i, err;
+ int err;

ns = timens_for_children_get(p);
if (!ns)
@@ -373,63 +435,7 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p,
return -EPERM;
}

- for (i = 0; i < noffsets; i++) {
- struct proc_timens_offset *off = &offsets[i];
-
- switch (off->clockid) {
- case CLOCK_MONOTONIC:
- ktime_get_ts64(&tp);
- break;
- case CLOCK_BOOTTIME:
- ktime_get_boottime_ts64(&tp);
- break;
- default:
- err = -EINVAL;
- goto out;
- }
-
- err = -ERANGE;
-
- if (off->val.tv_sec > KTIME_SEC_MAX ||
- off->val.tv_sec < -KTIME_SEC_MAX)
- goto out;
-
- tp = timespec64_add(tp, off->val);
- /*
- * KTIME_SEC_MAX is divided by 2 to be sure that KTIME_MAX is
- * still unreachable.
- */
- if (tp.tv_sec < 0 || tp.tv_sec > KTIME_SEC_MAX / 2)
- goto out;
- }
-
- mutex_lock(&offset_lock);
- if (time_ns->frozen_offsets) {
- err = -EACCES;
- goto out_unlock;
- }
-
- err = 0;
- /* Don't report errors after this line */
- for (i = 0; i < noffsets; i++) {
- struct proc_timens_offset *off = &offsets[i];
- struct timespec64 *offset = NULL;
-
- switch (off->clockid) {
- case CLOCK_MONOTONIC:
- offset = &time_ns->offsets.monotonic;
- break;
- case CLOCK_BOOTTIME:
- offset = &time_ns->offsets.boottime;
- break;
- }
-
- *offset = off->val;
- }
-
-out_unlock:
- mutex_unlock(&offset_lock);
-out:
+ err = timens_set_offset(p, time_ns, offsets, noffsets);
put_time_ns(time_ns);

return err;

base-commit: 8b614cb8f1dcac8ca77cf4dd85f46ef3055f8238
--
2.24.1