Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-40645

Slave Crash on Malformed User_var_log_event

    XMLWordPrintable

Details

    • Can result in hang or crash
    • Q3/2026 Replic. Development

    Description

      A crafted DECIMAL user variable event makes bin2decimal() allocate and
      copy a size taken entirely from two attacker-supplied bytes.

      bin2decimal() has no parameter telling it how many bytes are available
      (strings/decimal.c:1424):

        int bin_size= decimal_bin_size(precision, scale);
        sanity(to);
        d_copy= (uchar*) my_alloca(bin_size);
        memcpy(d_copy, from, bin_size);
      

      decimal_bin_size() guards its inputs with DBUG_ASSERT(precision > 0)
      and DBUG_ASSERT(scale <= precision) only, so release builds proceed with
      anything. my_alloca is real alloca in this build.

      Precision and scale arrive as val[0] and val[1]. Three call sites
      pass them through:

      • the applier, User_var_log_event::do_apply_event
        (sql/log_event_server.cc:4563), which checks only val_len < 3
      • pack_info (sql/log_event_server.cc:4356), which checks nothing, not
        even val_len >= 3
      • mysqlbinlog (sql/log_event_client.cc:2489), which checks nothing

      The constructor does bound val_len against the event
      (sql/log_event.cc:3064), so val_len is honest, but nothing ties
      decimal_bin_size(val[0], val[1]) to it. val_len of 3 with a precision
      of 65 already asks for 30 bytes where 1 is available.

      Two things enlarge that. val is const char *
      (sql/log_event.h:3317), so a 0xFF precision byte is -1, and the
      my_decimal(const uchar*, decimal_digits_t, decimal_digits_t) constructor
      narrows it to uint16, giving 65535 and a 29127 byte read. Worse, when
      scale exceeds precision, intg0x in decimal_bin_size goes negative and
      dig2bytes[intg0x] reads out of the adjacent powers10 array, which
      returns 1000000000. Precision 0xFC with scale 0xFF therefore yields a
      bin_size of 1000029127: a 954 MB alloca and a 954 MB memcpy.
      Release builds carry -fstack-protector but not
      -fstack-clash-protection, and the SQL thread stack is 292 KB.

      Note that the negative dig2bytes index does not depend on the signedness
      of char, so it is reachable on every platform. Note also that
      bin_size is never negative for any of the 65536 reachable byte pairs; the
      out of bounds static array read returns a large positive instead.

      --- a/sql/log_event_server.cc
      +++ b/sql/log_event_server.cc
      @@ User_var_log_event::write(), case DECIMAL_RESULT
             val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
      +      /* Leave val_len honest and lie about the metadata. */
      +      DBUG_EXECUTE_IF("corrupt_user_var_decimal_precision",
      +                      buf2[0]= (char) 0xFC; buf2[1]= (char) 0xFF;);
             break;
      

      --source include/have_debug.inc
      --source include/have_log_bin.inc
       
      set @@session.debug_dbug= "+d,corrupt_user_var_decimal_precision";
      set @a= 1.5;
      create table t1 (a decimal(10,5));
      insert into t1 values (@a);
      set @@session.debug_dbug= "";
       
      # pack_info() reaches bin2decimal() with precision 65532 and scale 65535, so
      # decimal_bin_size() returns 1000029127 and the alloca moves the stack
      # pointer roughly 954 MB.
      --source include/show_binlog_events.inc
      

      Attachments

        Activity

          People

            janlindstrom Jan Lindström
            bnestere Brandon Nesterenko
            Jan Lindström Jan Lindström
            Sergei Golubchik Sergei Golubchik
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - 1d Original Estimate - 1d
                1d
                Remaining:
                Remaining Estimate - 0d
                0d
                Logged:
                Time Spent - 1d 3h
                1d 3h

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.