summaryrefslogtreecommitdiffstats
path: root/translate.cxx
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-12-21 18:26:47 -0800
committerJosh Stone <jistone@redhat.com>2009-12-21 18:44:02 -0800
commit63db23df87bf6408c0947053288b771d863ecf36 (patch)
tree6f32163dc8db6da09000d589c590e5fdb9a4e8b1 /translate.cxx
parent0f4e0b6fed0ee334cf33073be381ee22925b59a7 (diff)
downloadsystemtap-steved-63db23df87bf6408c0947053288b771d863ecf36.tar.gz
systemtap-steved-63db23df87bf6408c0947053288b771d863ecf36.tar.xz
systemtap-steved-63db23df87bf6408c0947053288b771d863ecf36.zip
PR11112: Check the full %m/M buffer, and limit the length
We already had code in place to try a deref on the requested memory buffer, but it was missing the static-precision case. Thus, it was possible to craft an address that would pass the check on the first byte but would pagefault at the end of the buffer. While we're at it, we should also be limiting the number of bytes in such a read, so even legitimately-huge buffers won't chew up kernel time. I've arbitrarily chosen 1024 as the limit, but we can revisit that later. (see also PR10490) TODO: we need a reliable testcase where a starting address is valid but the end address is bogus. In PR11112, the reproducer was using a huge precision to run off the heap, but we need something that will consistently work even with <1024 length.
Diffstat (limited to 'translate.cxx')
-rw-r--r--translate.cxx39
1 files changed, 26 insertions, 13 deletions
diff --git a/translate.cxx b/translate.cxx
index 8c624a2f..81b8bef5 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -4264,20 +4264,33 @@ c_unparser::visit_print_format (print_format* e)
if (components[i].prectype == print_format::prec_dynamic)
prec_ix = arg_ix++;
- /* Generate a noop call to deref_buffer for %m. */
+ /* %m and %M need special care for digging into memory. */
if (components[i].type == print_format::conv_memory
- || components[i].type == print_format::conv_memory_hex) {
- this->probe_or_function_needs_deref_fault_handler = true;
- o->newline() << "deref_buffer (0, " << tmp[arg_ix].value() << ", ";
- if (prec_ix == -1)
- if (width_ix != -1)
- prec_ix = width_ix;
- if (prec_ix != -1)
- o->line() << tmp[prec_ix].value();
- else
- o->line() << "1";
- o->line() << ");";
- }
+ || components[i].type == print_format::conv_memory_hex)
+ {
+ string mem_size;
+ if (prec_ix != -1)
+ mem_size = tmp[prec_ix].value();
+ else if (components[i].prectype == print_format::prec_static &&
+ components[i].precision > 0)
+ mem_size = lex_cast(components[i].precision) + "LL";
+ else
+ mem_size = "1LL";
+
+ /* Limit how much can be printed at a time. (see also PR10490) */
+ o->newline() << "if (" << mem_size << " > 1024) {";
+ o->newline(1) << "snprintf(c->error_buffer, sizeof(c->error_buffer), "
+ << "\"%lld is too many bytes for a memory dump\", "
+ << mem_size << ");";
+ o->newline() << "c->last_error = c->error_buffer;";
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
+
+ /* Generate a noop call to deref_buffer. */
+ this->probe_or_function_needs_deref_fault_handler = true;
+ o->newline() << "deref_buffer (0, " << tmp[arg_ix].value() << ", "
+ << mem_size << " ?: 1LL);";
+ }
++arg_ix;
}