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

UDF: CWE-400 (Uncontrolled Resource Consumption)

    XMLWordPrintable

Details

    • Can result in hang or crash

    Description

      The metadata Length attribute is strictly defined in the SQL Standard (under SQL_DESC_DISPLAY_SIZE) as
      the maximum number of bytes needed to display the data in character form.

      The corresponding value for SQL_DESC_DISPLAY_SIZE in MariaDB/MySQL is the length attribute in MYSQL_FIELD_METADATA, which is descibed in the MySQL documentation:

      The width of the field. This corresponds to the display length, in bytes. The server determines the length value before it generates the result set, so this is the minimum length required for a data type capable of holding the largest possible value from the result column, without knowing in advance the actual values that will be produced by the query for the result set.

      Especially client applications using the binary (prepared statement) protocol rely on this value: Before fetching non fixed-type data such as strings or blobs, they have to allocate a buffer of field_length size for fetching values into the buffer afterwards.

      UDF's (user defined functions can use this for exploiting clients by OOM attacks):

      The UDF API provides an interface, where the UDF register its capabilities, such as length,type, null capability etc. Unfortunately there is no functionality for validating length (BSON GetInt for example sets length=31 for Integer type instead of 21). Even worse, if a length of 0 was specified, the server (udfhandler::fix_fields) sets the width to MAX_BLOB_WIDTH:

      bool
      udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
      			uint arg_count, Item **arguments)
      {
        ..
        func->max_length=MY_MIN(initid.max_length,MAX_BLOB_WIDTH);
        ..
      }
      

      As the attached udf test() function (which sets length to 0) demonstrates, this might end up in strange results which can be used for OOM attacks.

      SELECT test(1) returns type LONGLONG with a length of 16777216 bytes. Unless you have a 56Mbit CPU, this value is wrong.

      Applications, which trust this value might already allocate 16777216 bytes in case they have to fetch from LONGLONG into STRING buffer.

      Furthermore this value seems to be internally trusted as valid, so further operations might end up in even higher length values:

      SELECT cast(test(1) as CHAR) changes the type to LONG_BLOB and returns a length of 268435456.

      So instead of allocating 1 (or 2 bytes including terminating zero) the application allocates 0.25GB for a column. As the attached client_oom.c demonstrates this might end up in an OOM error while processing the data (vm.overcommit_memory=2 was set).

      Disclaimer: This issue was neither discovered nor written by AI

      Attachments

        Activity

          People

            serg Sergei Golubchik
            georg Georg Richter
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Git Integration

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