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/trace | |
| 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/trace')
| -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 | ||
