diff options
author | Marcin Slusarz <marcin.slusarz@gmail.com> | 2010-07-27 19:18:01 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-08-13 15:23:16 -0400 |
commit | 1aa54bca6ee0d07ebcafb8ca8074b624d80724aa (patch) | |
tree | 815f3c1d184b61958ee48eb868ed28b1e5aab278 /kernel/trace/trace.c | |
parent | 2a37a3df57c44e947271758a1aa4bea7bff9feab (diff) |
tracing: Sanitize value returned from write(trace_marker, "...", len)
When userspace code writes non-new-line-terminated string to trace_marker
file, write handler appends new-line and returns number of bytes written
to trace buffer, so
write(fd, "abc", 3) will return 4
That's unexpected and unfortunately it confuses glibc's fprintf function.
Example:
int main() {
fprintf(stderr, "abc");
return 0;
}
$ gcc test.c -o test
$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer
$ ./test 2>/sys/kernel/debug/tracing/trace_marker
results in infinite loop:
write(fd, "abc", 3) = 4
write(fd, "", 1) = 0
write(fd, "", 1) = 0
write(fd, "", 1) = 0
write(fd, "", 1) = 0
write(fd, "", 1) = 0
write(fd, "", 1) = 0
write(fd, "", 1) = 0
(...)
...and kernel trace buffer full of empty markers.
Fix it by sanitizing write return value.
Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
LKML-Reference: <20100727231801.GB2826@joi.lan>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r-- | kernel/trace/trace.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 086d36316805..88b42d14d32d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -3498,6 +3498,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
3498 | size_t cnt, loff_t *fpos) | 3498 | size_t cnt, loff_t *fpos) |
3499 | { | 3499 | { |
3500 | char *buf; | 3500 | char *buf; |
3501 | size_t written; | ||
3501 | 3502 | ||
3502 | if (tracing_disabled) | 3503 | if (tracing_disabled) |
3503 | return -EINVAL; | 3504 | return -EINVAL; |
@@ -3519,11 +3520,15 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
3519 | } else | 3520 | } else |
3520 | buf[cnt] = '\0'; | 3521 | buf[cnt] = '\0'; |
3521 | 3522 | ||
3522 | cnt = mark_printk("%s", buf); | 3523 | written = mark_printk("%s", buf); |
3523 | kfree(buf); | 3524 | kfree(buf); |
3524 | *fpos += cnt; | 3525 | *fpos += written; |
3525 | 3526 | ||
3526 | return cnt; | 3527 | /* don't tell userspace we wrote more - it might confuse them */ |
3528 | if (written > cnt) | ||
3529 | written = cnt; | ||
3530 | |||
3531 | return written; | ||
3527 | } | 3532 | } |
3528 | 3533 | ||
3529 | static int tracing_clock_show(struct seq_file *m, void *v) | 3534 | static int tracing_clock_show(struct seq_file *m, void *v) |