]> sourceware.org Git - systemtap.git/commitdiff
PR11112: Check the full %m/M buffer, and limit the length
authorJosh Stone <jistone@redhat.com>
Tue, 22 Dec 2009 02:26:47 +0000 (18:26 -0800)
committerJosh Stone <jistone@redhat.com>
Tue, 22 Dec 2009 02:44:02 +0000 (18:44 -0800)
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

index 8c624a2fe685dfdfacfca3edd9e46e8f39cebc82..81b8bef51fdb2492ba316d83b1e3b26c4a4242f4 100644 (file)
@@ -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;
       }
This page took 0.036384 seconds and 5 git commands to generate.