]> git.pld-linux.org Git - packages/lttng-modules.git/blob - kernel-4.15-timers.patch
0e412ec63fc06c544f1dc07c2a6ebf7c8ebe1358
[packages/lttng-modules.git] / kernel-4.15-timers.patch
1 From 1fd97f9f4f773e3e9dfc787e9c90b1418fa5a7d4 Mon Sep 17 00:00:00 2001
2 From: Michael Jeanson <mjeanson@efficios.com>
3 Date: Wed, 29 Nov 2017 17:03:21 -0500
4 Subject: [PATCH] timer API transition for kernel 4.15
5
6 The timer API changes starting from kernel 4.15.0.
7
8 There's an interresting LWN article on this subject:
9
10   https://lwn.net/Articles/735887/
11
12 Check these upstream commits for more details:
13
14   commit 686fef928bba6be13cabe639f154af7d72b63120
15   Author: Kees Cook <keescook@chromium.org>
16   Date:   Thu Sep 28 06:38:17 2017 -0700
17
18     timer: Prepare to change timer callback argument type
19
20     Modern kernel callback systems pass the structure associated with a
21     given callback to the callback function. The timer callback remains one
22     of the legacy cases where an arbitrary unsigned long argument continues
23     to be passed as the callback argument. This has several problems:
24
25     - This bloats the timer_list structure with a normally redundant
26       .data field.
27
28     - No type checking is being performed, forcing callbacks to do
29       explicit type casts of the unsigned long argument into the object
30       that was passed, rather than using container_of(), as done in most
31       of the other callback infrastructure.
32
33     - Neighboring buffer overflows can overwrite both the .function and
34       the .data field, providing attackers with a way to elevate from a buffer
35       overflow into a simplistic ROP-like mechanism that allows calling
36       arbitrary functions with a controlled first argument.
37
38     - For future Control Flow Integrity work, this creates a unique function
39       prototype for timer callbacks, instead of allowing them to continue to
40       be clustered with other void functions that take a single unsigned long
41       argument.
42
43     This adds a new timer initialization API, which will ultimately replace
44     the existing setup_timer(), setup_{deferrable,pinned,etc}_timer() family,
45     named timer_setup() (to mirror hrtimer_setup(), making instances of its
46     use much easier to grep for).
47
48     In order to support the migration of existing timers into the new
49     callback arguments, timer_setup() casts its arguments to the existing
50     legacy types, and explicitly passes the timer pointer as the legacy
51     data argument. Once all setup_*timer() callers have been replaced with
52     timer_setup(), the casts can be removed, and the data argument can be
53     dropped with the timer expiration code changed to just pass the timer
54     to the callback directly.
55
56 :
57     Modern kernel callback systems pass the structure associated with a
58     given callback to the callback function. The timer callback remains one
59     of the legacy cases where an arbitrary unsigned long argument continues
60     to be passed as the callback argument. This has several problems:
61
62     - This bloats the timer_list structure with a normally redundant
63       .data field.
64
65     - No type checking is being performed, forcing callbacks to do
66       explicit type casts of the unsigned long argument into the object
67       that was passed, rather than using container_of(), as done in most
68       of the other callback infrastructure.
69
70     - Neighboring buffer overflows can overwrite both the .function and
71       the .data field, providing attackers with a way to elevate from a buffer
72       overflow into a simplistic ROP-like mechanism that allows calling
73       arbitrary functions with a controlled first argument.
74
75     - For future Control Flow Integrity work, this creates a unique function
76       prototype for timer callbacks, instead of allowing them to continue to
77       be clustered with other void functions that take a single unsigned long
78       argument.
79
80     This adds a new timer initialization API, which will ultimately replace
81     the existing setup_timer(), setup_{deferrable,pinned,etc}_timer() family,
82     named timer_setup() (to mirror hrtimer_setup(), making instances of its
83     use much easier to grep for).
84
85     In order to support the migration of existing timers into the new
86     callback arguments, timer_setup() casts its arguments to the existing
87     legacy types, and explicitly passes the timer pointer as the legacy
88     data argument. Once all setup_*timer() callers have been replaced with
89     timer_setup(), the casts can be removed, and the data argument can be
90     dropped with the timer expiration code changed to just pass the timer
91     to the callback directly.
92
93     Since the regular pattern of using container_of() during local variable
94     declaration repeats the need for the variable type declaration
95     to be included, this adds a helper modeled after other from_*()
96     helpers that wrap container_of(), named from_timer(). This helper uses
97     typeof(*variable), removing the type redundancy and minimizing the need
98     for line wraps in forthcoming conversions from "unsigned data long" to
99     "struct timer_list *" in the timer callbacks:
100
101     -void callback(unsigned long data)
102     +void callback(struct timer_list *t)
103     {
104     -   struct some_data_structure *local = (struct some_data_structure *)data;
105     +   struct some_data_structure *local = from_timer(local, t, timer);
106
107     Finally, in order to support the handful of timer users that perform
108     open-coded assignments of the .function (and .data) fields, provide
109     cast macros (TIMER_FUNC_TYPE and TIMER_DATA_TYPE) that can be used
110     temporarily. Once conversion has been completed, these can be globally
111     trivially removed.
112
113     ...
114
115   commit e99e88a9d2b067465adaa9c111ada99a041bef9a
116   Author: Kees Cook <keescook@chromium.org>
117   Date:   Mon Oct 16 14:43:17 2017 -0700
118
119     treewide: setup_timer() -> timer_setup()
120
121     This converts all remaining cases of the old setup_timer() API into using
122     timer_setup(), where the callback argument is the structure already
123     holding the struct timer_list. These should have no behavioral changes,
124     since they just change which pointer is passed into the callback with
125     the same available pointers after conversion. It handles the following
126     examples, in addition to some other variations.
127
128     ...
129
130   commit 185981d54a60ae90942c6ba9006b250f3348cef2
131   Author: Kees Cook <keescook@chromium.org>
132   Date:   Wed Oct 4 16:26:58 2017 -0700
133
134     timer: Remove init_timer_pinned() in favor of timer_setup()
135
136     This refactors the only users of init_timer_pinned() to use
137     the new timer_setup() and from_timer(). Drops the definition of
138     init_timer_pinned().
139
140     ...
141
142 Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
143 Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
144 ---
145  lib/ringbuffer/ring_buffer_frontend.c | 27 +++++++------
146  wrapper/timer.h                       | 72 ++++++++++++++++++++++++++++-------
147  2 files changed, 72 insertions(+), 27 deletions(-)
148
149 diff --git a/lib/ringbuffer/ring_buffer_frontend.c b/lib/ringbuffer/ring_buffer_frontend.c
150 index bdd31ad..abd9757 100644
151 --- a/lib/ringbuffer/ring_buffer_frontend.c
152 +++ b/lib/ringbuffer/ring_buffer_frontend.c
153 @@ -314,9 +314,9 @@ int lib_ring_buffer_create(struct lib_ring_buffer *buf,
154         return ret;
155  }
156  
157 -static void switch_buffer_timer(unsigned long data)
158 +static void switch_buffer_timer(LTTNG_TIMER_FUNC_ARG_TYPE t)
159  {
160 -       struct lib_ring_buffer *buf = (struct lib_ring_buffer *)data;
161 +       struct lib_ring_buffer *buf = lttng_from_timer(buf, t, switch_timer);
162         struct channel *chan = buf->backend.chan;
163         const struct lib_ring_buffer_config *config = &chan->backend.config;
164  
165 @@ -341,22 +341,22 @@ static void lib_ring_buffer_start_switch_timer(struct lib_ring_buffer *buf)
166  {
167         struct channel *chan = buf->backend.chan;
168         const struct lib_ring_buffer_config *config = &chan->backend.config;
169 +       unsigned int flags = 0;
170  
171         if (!chan->switch_timer_interval || buf->switch_timer_enabled)
172                 return;
173  
174         if (config->alloc == RING_BUFFER_ALLOC_PER_CPU)
175 -               lttng_init_timer_pinned(&buf->switch_timer);
176 -       else
177 -               init_timer(&buf->switch_timer);
178 +               flags = LTTNG_TIMER_PINNED;
179  
180 -       buf->switch_timer.function = switch_buffer_timer;
181 +       lttng_timer_setup(&buf->switch_timer, switch_buffer_timer, flags, buf);
182         buf->switch_timer.expires = jiffies + chan->switch_timer_interval;
183 -       buf->switch_timer.data = (unsigned long)buf;
184 +
185         if (config->alloc == RING_BUFFER_ALLOC_PER_CPU)
186                 add_timer_on(&buf->switch_timer, buf->backend.cpu);
187         else
188                 add_timer(&buf->switch_timer);
189 +
190         buf->switch_timer_enabled = 1;
191  }
192  
193 @@ -377,9 +377,9 @@ static void lib_ring_buffer_stop_switch_timer(struct lib_ring_buffer *buf)
194  /*
195   * Polling timer to check the channels for data.
196   */
197 -static void read_buffer_timer(unsigned long data)
198 +static void read_buffer_timer(LTTNG_TIMER_FUNC_ARG_TYPE t)
199  {
200 -       struct lib_ring_buffer *buf = (struct lib_ring_buffer *)data;
201 +       struct lib_ring_buffer *buf = lttng_from_timer(buf, t, read_timer);
202         struct channel *chan = buf->backend.chan;
203         const struct lib_ring_buffer_config *config = &chan->backend.config;
204  
205 @@ -406,6 +406,7 @@ static void lib_ring_buffer_start_read_timer(struct lib_ring_buffer *buf)
206  {
207         struct channel *chan = buf->backend.chan;
208         const struct lib_ring_buffer_config *config = &chan->backend.config;
209 +       unsigned int flags;
210  
211         if (config->wakeup != RING_BUFFER_WAKEUP_BY_TIMER
212             || !chan->read_timer_interval
213 @@ -413,18 +414,16 @@ static void lib_ring_buffer_start_read_timer(struct lib_ring_buffer *buf)
214                 return;
215  
216         if (config->alloc == RING_BUFFER_ALLOC_PER_CPU)
217 -               lttng_init_timer_pinned(&buf->read_timer);
218 -       else
219 -               init_timer(&buf->read_timer);
220 +               flags = LTTNG_TIMER_PINNED;
221  
222 -       buf->read_timer.function = read_buffer_timer;
223 +       lttng_timer_setup(&buf->read_timer, read_buffer_timer, flags, buf);
224         buf->read_timer.expires = jiffies + chan->read_timer_interval;
225 -       buf->read_timer.data = (unsigned long)buf;
226  
227         if (config->alloc == RING_BUFFER_ALLOC_PER_CPU)
228                 add_timer_on(&buf->read_timer, buf->backend.cpu);
229         else
230                 add_timer(&buf->read_timer);
231 +
232         buf->read_timer_enabled = 1;
233  }
234  
235 diff --git a/wrapper/timer.h b/wrapper/timer.h
236 index c1c0c95..4fc9828 100644
237 --- a/wrapper/timer.h
238 +++ b/wrapper/timer.h
239 @@ -27,30 +27,76 @@
240  #include <linux/timer.h>
241  #include <lttng-kernel-version.h>
242  
243 +/*
244 + * In the olden days, pinned timers were initialized normaly with init_timer()
245 + * and then modified with mod_timer_pinned().
246 + *
247 + * Then came kernel 4.8.0 and they had to be initilized as pinned with
248 + * init_timer_pinned() and then modified as regular timers with mod_timer().
249 + *
250 + * Then came kernel 4.15.0 with a new timer API where init_timer() is no more.
251 + * It's replaced by timer_setup() where pinned is now part of timer flags.
252 + */
253 +
254 +
255 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0))
256 +
257 +#define LTTNG_TIMER_PINNED             TIMER_PINNED
258 +#define LTTNG_TIMER_FUNC_ARG_TYPE      struct timer_list *
259 +
260 +#define lttng_mod_timer_pinned(timer, expires) \
261 +       mod_timer(timer, expires)
262 +
263 +#define lttng_from_timer(var, callback_timer, timer_fieldname) \
264 +       from_timer(var, callback_timer, timer_fieldname)
265 +
266 +#define lttng_timer_setup(timer, callback, flags, unused) \
267 +       timer_setup(timer, callback, flags)
268 +
269  
270 -#if (LTTNG_RT_VERSION_CODE >= LTTNG_RT_KERNEL_VERSION(4,6,4,8) \
271 +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) */
272 +
273 +
274 +# if (LTTNG_RT_VERSION_CODE >= LTTNG_RT_KERNEL_VERSION(4,6,4,8) \
275         || LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
276  
277 -#define lttng_init_timer_pinned(timer)                                 \
278 +#define lttng_init_timer_pinned(timer) \
279         init_timer_pinned(timer)
280  
281 -static inline int lttng_mod_timer_pinned(struct timer_list *timer,
282 -               unsigned long expires)
283 -{
284 -       return mod_timer(timer, expires);
285 -}
286 +#define lttng_mod_timer_pinned(timer, expires) \
287 +       mod_timer(timer, expires)
288  
289 -#else
290 +# else /* LTTNG_RT_VERSION_CODE >= LTTNG_RT_KERNEL_VERSION(4,6,4,8) */
291  
292 -#define lttng_init_timer_pinned(timer)                                 \
293 +#define lttng_init_timer_pinned(timer) \
294         init_timer(timer)
295  
296 -static inline int lttng_mod_timer_pinned(struct timer_list *timer,
297 -               unsigned long expires)
298 +#define lttng_mod_timer_pinned(timer, expires) \
299 +       mod_timer_pinned(timer, expires)
300 +
301 +# endif /* LTTNG_RT_VERSION_CODE >= LTTNG_RT_KERNEL_VERSION(4,6,4,8) */
302 +
303 +
304 +#define LTTNG_TIMER_PINNED             TIMER_PINNED
305 +#define LTTNG_TIMER_FUNC_ARG_TYPE      unsigned long
306 +
307 +/* timer_fieldname is unused prior to 4.15. */
308 +#define lttng_from_timer(var, timer_data, timer_fieldname) \
309 +       ((typeof(var))timer_data)
310 +
311 +static inline void lttng_timer_setup(struct timer_list *timer,
312 +               void (*function)(LTTNG_TIMER_FUNC_ARG_TYPE),
313 +               unsigned int flags, void *data)
314  {
315 -       return mod_timer_pinned(timer, expires);
316 +       if (flags & LTTNG_TIMER_PINNED)
317 +               lttng_init_timer_pinned(timer);
318 +       else
319 +               init_timer(timer);
320 +
321 +       timer->function = function;
322 +       timer->data = (unsigned long)data;
323  }
324  
325 -#endif
326 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) */
327  
328  #endif /* _LTTNG_WRAPPER_TIMER_H */
This page took 0.098661 seconds and 2 git commands to generate.