tracing: Make trace_seq_putmem_hex() more robust
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>
Sat, 21 Jun 2014 03:31:26 +0000 (23:31 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Tue, 1 Jul 2014 11:13:37 +0000 (07:13 -0400)
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>
include/linux/trace_seq.h
kernel/trace/trace_output.h
kernel/trace/trace_seq.c

index 1f05317f51c4adfcf9f992e3831132f322a4300a..8283762ab7ef1cf69881500ce00b9de3ea875d89 100644 (file)
@@ -25,8 +25,6 @@ trace_seq_init(struct trace_seq *s)
        s->full = 0;
 }
 
-#define MAX_MEMHEX_BYTES       8
-
 /*
  * Currently only defined when tracing is enabled.
  */
index bf7daf2237edf4465f7dc3d53dff02e7d71a3367..80b25b585a700b9e703bb75eda4b53dcd71594e7 100644 (file)
@@ -43,7 +43,6 @@ do {                                                  \
 
 #define SEQ_PUT_HEX_FIELD_RET(s, x)                    \
 do {                                                   \
-       BUILD_BUG_ON(sizeof(x) > MAX_MEMHEX_BYTES);     \
        if (!trace_seq_putmem_hex(s, &(x), sizeof(x)))  \
                return TRACE_TYPE_PARTIAL_LINE;         \
 } while (0)
index 0fabca773e51cc7317edbd620f1cc8ca4a6e4ee3..88c0f80f0a1f2a6283eb31460917e14a99f263b7 100644 (file)
@@ -291,6 +291,7 @@ int trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len)
 }
 EXPORT_SYMBOL_GPL(trace_seq_putmem);
 
+#define MAX_MEMHEX_BYTES       8U
 #define HEX_CHARS              (MAX_MEMHEX_BYTES*2 + 1)
 
 /**
@@ -310,22 +311,33 @@ int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
 {
        unsigned char hex[HEX_CHARS];
        const unsigned char *data = mem;
+       unsigned int start_len;
        int i, j;
+       int cnt = 0;
 
        if (s->full)
                return 0;
 
+       while (len) {
+               start_len = min(len, HEX_CHARS - 1);
 #ifdef __BIG_ENDIAN
-       for (i = 0, j = 0; i < len; i++) {
+               for (i = 0, j = 0; i < start_len; i++) {
 #else
-       for (i = len-1, j = 0; i >= 0; i--) {
+               for (i = start_len-1, j = 0; i >= 0; i--) {
 #endif
-               hex[j++] = hex_asc_hi(data[i]);
-               hex[j++] = hex_asc_lo(data[i]);
-       }
-       hex[j++] = ' ';
+                       hex[j++] = hex_asc_hi(data[i]);
+                       hex[j++] = hex_asc_lo(data[i]);
+               }
+               if (WARN_ON_ONCE(j == 0 || j/2 > len))
+                       break;
+
+               /* j increments twice per loop */
+               len -= j / 2;
+               hex[j++] = ' ';
 
-       return trace_seq_putmem(s, hex, j);
+               cnt += trace_seq_putmem(s, hex, j);
+       }
+       return cnt;
 }
 EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);