diff options
author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2014-06-20 23:31:26 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2014-07-01 07:13:37 -0400 |
commit | 6d2289f3faa71dcc5bba15c7aeba4f31c185b6df (patch) | |
tree | 8425f1195f29a670dcb1ad00e56ee1836514ab02 /kernel | |
parent | 36aabfff50b6a03bcfd2c3cfbd7b83eb0a9ce0c1 (diff) |
tracing: Make trace_seq_putmem_hex() more robust
Currently trace_seq_putmem_hex() can only take as a parameter a pointer
to something that is 8 bytes or less, otherwise it will overflow the
buffer. This is protected by a macro that encompasses the call to
trace_seq_putmem_hex() that has a BUILD_BUG_ON() for the variable before
it is passed in. This is not very robust and if trace_seq_putmem_hex() ever
gets used outside that macro it will cause issues.
Instead of only being able to produce a hex output of memory that is for
a single word, change it to be more robust and allow any size input.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_output.h | 1 | ||||
-rw-r--r-- | kernel/trace/trace_seq.c | 26 |
2 files changed, 19 insertions, 8 deletions
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h index bf7daf2237ed..80b25b585a70 100644 --- a/kernel/trace/trace_output.h +++ b/kernel/trace/trace_output.h | |||
@@ -43,7 +43,6 @@ do { \ | |||
43 | 43 | ||
44 | #define SEQ_PUT_HEX_FIELD_RET(s, x) \ | 44 | #define SEQ_PUT_HEX_FIELD_RET(s, x) \ |
45 | do { \ | 45 | do { \ |
46 | BUILD_BUG_ON(sizeof(x) > MAX_MEMHEX_BYTES); \ | ||
47 | if (!trace_seq_putmem_hex(s, &(x), sizeof(x))) \ | 46 | if (!trace_seq_putmem_hex(s, &(x), sizeof(x))) \ |
48 | return TRACE_TYPE_PARTIAL_LINE; \ | 47 | return TRACE_TYPE_PARTIAL_LINE; \ |
49 | } while (0) | 48 | } while (0) |
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c index 0fabca773e51..88c0f80f0a1f 100644 --- a/kernel/trace/trace_seq.c +++ b/kernel/trace/trace_seq.c | |||
@@ -291,6 +291,7 @@ int trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len) | |||
291 | } | 291 | } |
292 | EXPORT_SYMBOL_GPL(trace_seq_putmem); | 292 | EXPORT_SYMBOL_GPL(trace_seq_putmem); |
293 | 293 | ||
294 | #define MAX_MEMHEX_BYTES 8U | ||
294 | #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) | 295 | #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) |
295 | 296 | ||
296 | /** | 297 | /** |
@@ -310,22 +311,33 @@ int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, | |||
310 | { | 311 | { |
311 | unsigned char hex[HEX_CHARS]; | 312 | unsigned char hex[HEX_CHARS]; |
312 | const unsigned char *data = mem; | 313 | const unsigned char *data = mem; |
314 | unsigned int start_len; | ||
313 | int i, j; | 315 | int i, j; |
316 | int cnt = 0; | ||
314 | 317 | ||
315 | if (s->full) | 318 | if (s->full) |
316 | return 0; | 319 | return 0; |
317 | 320 | ||
321 | while (len) { | ||
322 | start_len = min(len, HEX_CHARS - 1); | ||
318 | #ifdef __BIG_ENDIAN | 323 | #ifdef __BIG_ENDIAN |
319 | for (i = 0, j = 0; i < len; i++) { | 324 | for (i = 0, j = 0; i < start_len; i++) { |
320 | #else | 325 | #else |
321 | for (i = len-1, j = 0; i >= 0; i--) { | 326 | for (i = start_len-1, j = 0; i >= 0; i--) { |
322 | #endif | 327 | #endif |
323 | hex[j++] = hex_asc_hi(data[i]); | 328 | hex[j++] = hex_asc_hi(data[i]); |
324 | hex[j++] = hex_asc_lo(data[i]); | 329 | hex[j++] = hex_asc_lo(data[i]); |
325 | } | 330 | } |
326 | hex[j++] = ' '; | 331 | if (WARN_ON_ONCE(j == 0 || j/2 > len)) |
332 | break; | ||
333 | |||
334 | /* j increments twice per loop */ | ||
335 | len -= j / 2; | ||
336 | hex[j++] = ' '; | ||
327 | 337 | ||
328 | return trace_seq_putmem(s, hex, j); | 338 | cnt += trace_seq_putmem(s, hex, j); |
339 | } | ||
340 | return cnt; | ||
329 | } | 341 | } |
330 | EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); | 342 | EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); |
331 | 343 | ||