From 63db23df87bf6408c0947053288b771d863ecf36 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 21 Dec 2009 18:26:47 -0800 Subject: 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. --- translate.cxx | 39 ++++++++++++++++++++++++++------------- 1 file 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; } -- cgit