summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-06-21 07:31:26 +0400
committerSteven Rostedt <rostedt@goodmis.org>2014-07-01 15:13:37 +0400
commit6d2289f3faa71dcc5bba15c7aeba4f31c185b6df (patch)
tree8425f1195f29a670dcb1ad00e56ee1836514ab02
parent36aabfff50b6a03bcfd2c3cfbd7b83eb0a9ce0c1 (diff)
downloadlinux-6d2289f3faa71dcc5bba15c7aeba4f31c185b6df.tar.xz
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>
-rw-r--r--include/linux/trace_seq.h2
-rw-r--r--kernel/trace/trace_output.h1
-rw-r--r--kernel/trace/trace_seq.c26
3 files changed, 19 insertions, 10 deletions
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index 1f05317f51c4..8283762ab7ef 100644
--- a/include/linux/trace_seq.h
+++ b/include/linux/trace_seq.h
@@ -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.
*/
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 { \
#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)
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)
}
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);