@@ -217,6 +217,214 @@ int trace_event_get_offsets(struct trace_event_call *call)
217
217
return tail -> offset + tail -> size ;
218
218
}
219
219
220
+ /*
221
+ * Check if the referenced field is an array and return true,
222
+ * as arrays are OK to dereference.
223
+ */
224
+ static bool test_field (const char * fmt , struct trace_event_call * call )
225
+ {
226
+ struct trace_event_fields * field = call -> class -> fields_array ;
227
+ const char * array_descriptor ;
228
+ const char * p = fmt ;
229
+ int len ;
230
+
231
+ if (!(len = str_has_prefix (fmt , "REC->" )))
232
+ return false;
233
+ fmt += len ;
234
+ for (p = fmt ; * p ; p ++ ) {
235
+ if (!isalnum (* p ) && * p != '_' )
236
+ break ;
237
+ }
238
+ len = p - fmt ;
239
+
240
+ for (; field -> type ; field ++ ) {
241
+ if (strncmp (field -> name , fmt , len ) ||
242
+ field -> name [len ])
243
+ continue ;
244
+ array_descriptor = strchr (field -> type , '[' );
245
+ /* This is an array and is OK to dereference. */
246
+ return array_descriptor != NULL ;
247
+ }
248
+ return false;
249
+ }
250
+
251
+ /*
252
+ * Examine the print fmt of the event looking for unsafe dereference
253
+ * pointers using %p* that could be recorded in the trace event and
254
+ * much later referenced after the pointer was freed. Dereferencing
255
+ * pointers are OK, if it is dereferenced into the event itself.
256
+ */
257
+ static void test_event_printk (struct trace_event_call * call )
258
+ {
259
+ u64 dereference_flags = 0 ;
260
+ bool first = true;
261
+ const char * fmt , * c , * r , * a ;
262
+ int parens = 0 ;
263
+ char in_quote = 0 ;
264
+ int start_arg = 0 ;
265
+ int arg = 0 ;
266
+ int i ;
267
+
268
+ fmt = call -> print_fmt ;
269
+
270
+ if (!fmt )
271
+ return ;
272
+
273
+ for (i = 0 ; fmt [i ]; i ++ ) {
274
+ switch (fmt [i ]) {
275
+ case '\\' :
276
+ i ++ ;
277
+ if (!fmt [i ])
278
+ return ;
279
+ continue ;
280
+ case '"' :
281
+ case '\'' :
282
+ /*
283
+ * The print fmt starts with a string that
284
+ * is processed first to find %p* usage,
285
+ * then after the first string, the print fmt
286
+ * contains arguments that are used to check
287
+ * if the dereferenced %p* usage is safe.
288
+ */
289
+ if (first ) {
290
+ if (fmt [i ] == '\'' )
291
+ continue ;
292
+ if (in_quote ) {
293
+ arg = 0 ;
294
+ first = false;
295
+ /*
296
+ * If there was no %p* uses
297
+ * the fmt is OK.
298
+ */
299
+ if (!dereference_flags )
300
+ return ;
301
+ }
302
+ }
303
+ if (in_quote ) {
304
+ if (in_quote == fmt [i ])
305
+ in_quote = 0 ;
306
+ } else {
307
+ in_quote = fmt [i ];
308
+ }
309
+ continue ;
310
+ case '%' :
311
+ if (!first || !in_quote )
312
+ continue ;
313
+ i ++ ;
314
+ if (!fmt [i ])
315
+ return ;
316
+ switch (fmt [i ]) {
317
+ case '%' :
318
+ continue ;
319
+ case 'p' :
320
+ /* Find dereferencing fields */
321
+ switch (fmt [i + 1 ]) {
322
+ case 'B' : case 'R' : case 'r' :
323
+ case 'b' : case 'M' : case 'm' :
324
+ case 'I' : case 'i' : case 'E' :
325
+ case 'U' : case 'V' : case 'N' :
326
+ case 'a' : case 'd' : case 'D' :
327
+ case 'g' : case 't' : case 'C' :
328
+ case 'O' : case 'f' :
329
+ if (WARN_ONCE (arg == 63 ,
330
+ "Too many args for event: %s" ,
331
+ trace_event_name (call )))
332
+ return ;
333
+ dereference_flags |= 1ULL << arg ;
334
+ }
335
+ break ;
336
+ default :
337
+ {
338
+ bool star = false;
339
+ int j ;
340
+
341
+ /* Increment arg if %*s exists. */
342
+ for (j = 0 ; fmt [i + j ]; j ++ ) {
343
+ if (isdigit (fmt [i + j ]) ||
344
+ fmt [i + j ] == '.' )
345
+ continue ;
346
+ if (fmt [i + j ] == '*' ) {
347
+ star = true;
348
+ continue ;
349
+ }
350
+ if ((fmt [i + j ] == 's' ) && star )
351
+ arg ++ ;
352
+ break ;
353
+ }
354
+ break ;
355
+ } /* default */
356
+
357
+ } /* switch */
358
+ arg ++ ;
359
+ continue ;
360
+ case '(' :
361
+ if (in_quote )
362
+ continue ;
363
+ parens ++ ;
364
+ continue ;
365
+ case ')' :
366
+ if (in_quote )
367
+ continue ;
368
+ parens -- ;
369
+ if (WARN_ONCE (parens < 0 ,
370
+ "Paren mismatch for event: %s\narg='%s'\n%*s" ,
371
+ trace_event_name (call ),
372
+ fmt + start_arg ,
373
+ (i - start_arg ) + 5 , "^" ))
374
+ return ;
375
+ continue ;
376
+ case ',' :
377
+ if (in_quote || parens )
378
+ continue ;
379
+ i ++ ;
380
+ while (isspace (fmt [i ]))
381
+ i ++ ;
382
+ start_arg = i ;
383
+ if (!(dereference_flags & (1ULL << arg )))
384
+ goto next_arg ;
385
+
386
+ /* Find the REC-> in the argument */
387
+ c = strchr (fmt + i , ',' );
388
+ r = strstr (fmt + i , "REC->" );
389
+ if (r && (!c || r < c )) {
390
+ /*
391
+ * Addresses of events on the buffer,
392
+ * or an array on the buffer is
393
+ * OK to dereference.
394
+ * There's ways to fool this, but
395
+ * this is to catch common mistakes,
396
+ * not malicious code.
397
+ */
398
+ a = strchr (fmt + i , '&' );
399
+ if ((a && (a < r )) || test_field (r , call ))
400
+ dereference_flags &= ~(1ULL << arg );
401
+ }
402
+ next_arg :
403
+ i -- ;
404
+ arg ++ ;
405
+ }
406
+ }
407
+
408
+ /*
409
+ * If you triggered the below warning, the trace event reported
410
+ * uses an unsafe dereference pointer %p*. As the data stored
411
+ * at the trace event time may no longer exist when the trace
412
+ * event is printed, dereferencing to the original source is
413
+ * unsafe. The source of the dereference must be copied into the
414
+ * event itself, and the dereference must access the copy instead.
415
+ */
416
+ if (WARN_ON_ONCE (dereference_flags )) {
417
+ arg = 1 ;
418
+ while (!(dereference_flags & 1 )) {
419
+ dereference_flags >>= 1 ;
420
+ arg ++ ;
421
+ }
422
+ pr_warn ("event %s has unsafe dereference of argument %d\n" ,
423
+ trace_event_name (call ), arg );
424
+ pr_warn ("print_fmt: %s\n" , fmt );
425
+ }
426
+ }
427
+
220
428
int trace_event_raw_init (struct trace_event_call * call )
221
429
{
222
430
int id ;
@@ -225,6 +433,8 @@ int trace_event_raw_init(struct trace_event_call *call)
225
433
if (!id )
226
434
return - ENODEV ;
227
435
436
+ test_event_printk (call );
437
+
228
438
return 0 ;
229
439
}
230
440
EXPORT_SYMBOL_GPL (trace_event_raw_init );
0 commit comments