1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_TIMENS_H
3 #define _LINUX_TIMENS_H
4 
5 
6 #include <linux/sched.h>
7 #include <linux/nsproxy.h>
8 #include <linux/ns_common.h>
9 #include <linux/err.h>
10 #include <linux/time64.h>
11 
12 struct user_namespace;
13 extern struct user_namespace init_user_ns;
14 
15 struct vm_area_struct;
16 
17 struct timens_offsets {
18 	struct timespec64 monotonic;
19 	struct timespec64 boottime;
20 };
21 
22 struct time_namespace {
23 	struct user_namespace	*user_ns;
24 	struct ucounts		*ucounts;
25 	struct ns_common	ns;
26 	struct timens_offsets	offsets;
27 	struct page		*vvar_page;
28 	/* If set prevents changing offsets after any task joined namespace. */
29 	bool			frozen_offsets;
30 } __randomize_layout;
31 
32 extern struct time_namespace init_time_ns;
33 
34 #ifdef CONFIG_TIME_NS
35 extern int vdso_join_timens(struct task_struct *task,
36 			    struct time_namespace *ns);
37 extern void timens_commit(struct task_struct *tsk, struct time_namespace *ns);
38 
get_time_ns(struct time_namespace * ns)39 static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
40 {
41 	refcount_inc(&ns->ns.count);
42 	return ns;
43 }
44 
45 struct time_namespace *copy_time_ns(unsigned long flags,
46 				    struct user_namespace *user_ns,
47 				    struct time_namespace *old_ns);
48 void free_time_ns(struct time_namespace *ns);
49 void timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk);
50 struct page *find_timens_vvar_page(struct vm_area_struct *vma);
51 
put_time_ns(struct time_namespace * ns)52 static inline void put_time_ns(struct time_namespace *ns)
53 {
54 	if (refcount_dec_and_test(&ns->ns.count))
55 		free_time_ns(ns);
56 }
57 
58 void proc_timens_show_offsets(struct task_struct *p, struct seq_file *m);
59 
60 struct proc_timens_offset {
61 	int			clockid;
62 	struct timespec64	val;
63 };
64 
65 int proc_timens_set_offset(struct file *file, struct task_struct *p,
66 			   struct proc_timens_offset *offsets, int n);
67 
timens_add_monotonic(struct timespec64 * ts)68 static inline void timens_add_monotonic(struct timespec64 *ts)
69 {
70 	struct timens_offsets *ns_offsets = &current->nsproxy->time_ns->offsets;
71 
72 	*ts = timespec64_add(*ts, ns_offsets->monotonic);
73 }
74 
timens_add_boottime(struct timespec64 * ts)75 static inline void timens_add_boottime(struct timespec64 *ts)
76 {
77 	struct timens_offsets *ns_offsets = &current->nsproxy->time_ns->offsets;
78 
79 	*ts = timespec64_add(*ts, ns_offsets->boottime);
80 }
81 
timens_add_boottime_ns(u64 nsec)82 static inline u64 timens_add_boottime_ns(u64 nsec)
83 {
84 	struct timens_offsets *ns_offsets = &current->nsproxy->time_ns->offsets;
85 
86 	return nsec + timespec64_to_ns(&ns_offsets->boottime);
87 }
88 
timens_sub_boottime(struct timespec64 * ts)89 static inline void timens_sub_boottime(struct timespec64 *ts)
90 {
91 	struct timens_offsets *ns_offsets = &current->nsproxy->time_ns->offsets;
92 
93 	*ts = timespec64_sub(*ts, ns_offsets->boottime);
94 }
95 
96 ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim,
97 				struct timens_offsets *offsets);
98 
timens_ktime_to_host(clockid_t clockid,ktime_t tim)99 static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
100 {
101 	struct time_namespace *ns = current->nsproxy->time_ns;
102 
103 	if (likely(ns == &init_time_ns))
104 		return tim;
105 
106 	return do_timens_ktime_to_host(clockid, tim, &ns->offsets);
107 }
108 
109 #else
vdso_join_timens(struct task_struct * task,struct time_namespace * ns)110 static inline int vdso_join_timens(struct task_struct *task,
111 				   struct time_namespace *ns)
112 {
113 	return 0;
114 }
115 
timens_commit(struct task_struct * tsk,struct time_namespace * ns)116 static inline void timens_commit(struct task_struct *tsk,
117 				 struct time_namespace *ns)
118 {
119 }
120 
get_time_ns(struct time_namespace * ns)121 static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
122 {
123 	return NULL;
124 }
125 
put_time_ns(struct time_namespace * ns)126 static inline void put_time_ns(struct time_namespace *ns)
127 {
128 }
129 
130 static inline
copy_time_ns(unsigned long flags,struct user_namespace * user_ns,struct time_namespace * old_ns)131 struct time_namespace *copy_time_ns(unsigned long flags,
132 				    struct user_namespace *user_ns,
133 				    struct time_namespace *old_ns)
134 {
135 	if (flags & CLONE_NEWTIME)
136 		return ERR_PTR(-EINVAL);
137 
138 	return old_ns;
139 }
140 
timens_on_fork(struct nsproxy * nsproxy,struct task_struct * tsk)141 static inline void timens_on_fork(struct nsproxy *nsproxy,
142 				 struct task_struct *tsk)
143 {
144 	return;
145 }
146 
find_timens_vvar_page(struct vm_area_struct * vma)147 static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
148 {
149 	return NULL;
150 }
151 
timens_add_monotonic(struct timespec64 * ts)152 static inline void timens_add_monotonic(struct timespec64 *ts) { }
timens_add_boottime(struct timespec64 * ts)153 static inline void timens_add_boottime(struct timespec64 *ts) { }
154 
timens_add_boottime_ns(u64 nsec)155 static inline u64 timens_add_boottime_ns(u64 nsec)
156 {
157 	return nsec;
158 }
159 
timens_sub_boottime(struct timespec64 * ts)160 static inline void timens_sub_boottime(struct timespec64 *ts) { }
161 
timens_ktime_to_host(clockid_t clockid,ktime_t tim)162 static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
163 {
164 	return tim;
165 }
166 #endif
167 
168 struct vdso_data *arch_get_vdso_data(void *vvar_page);
169 
170 #endif /* _LINUX_TIMENS_H */
171