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

server_audit_file_path overflows a startup stack buffer and aborts mariadbd

    XMLWordPrintable

Details

    • Bug
    • Status: Confirmed (View Workflow)
    • Major
    • Resolution: Unresolved
    • 10.11, 11.4, 11.8, 12.3, 13.0, 12.3.3
    • 10.11, 11.4, 11.8, 12.3, 13.0
    • Plugin - Audit
    • None

    Description

      At startup, the Server Audit plugin accepts a long existing directory through
      `server_audit_file_path`. The startup option path does not apply the length
      check used by the dynamic variable update. `start_logging()` then appends the
      default file name in a fixed stack buffer.

      With a 981-byte existing directory, the official 12.3.3 `mariadbd` aborts with
      glibc's buffer-overflow detector and signal 6. A short directory using the same
      plugin and options starts normally and creates `server_audit.log`.

      Steps to reproduce

      Run on a disposable Docker host. The script creates only temporary synthetic
      directories. It runs a short-path control first and then the long-path trigger.

      set -eu
      IMAGE='mariadb@sha256:dd9b303aed4f4890ed09f766d8ca9ddfd176c0c6f6267feff53b3192ec65a979'
      CONTROL='mdev-audit-path-control'
      TRIGGER='mdev-audit-path-trigger'
      OWNER="edbf-report-mcfg07-$$"
      D=$(mktemp -d)
       
      owned_remove() {
        NAME=$1
        if docker inspect --format '{{ index .Config.Labels "io.encryptiondbfuzz.owner" }}' \
             "$NAME" 2>/dev/null | grep -Fqx "$OWNER"; then
          docker rm -f "$NAME" >/dev/null 2>&1 || true
        fi
      }
      cleanup() {
        owned_remove "$CONTROL"
        owned_remove "$TRIGGER"
        rm -r "$D" >/dev/null 2>&1 || true
      }
      trap cleanup EXIT
       
      chmod 0777 "$D"
      mkdir "$D/control"
      chmod 0777 "$D/control"
      HOST_PATH=$D
      CONTAINER_PATH=/edbf-audit
      for I in 0 1 2 3 4; do
        PAD=$(printf '%0190d' 0 | tr 0 a)
        PART="p${I}_${PAD}"
        HOST_PATH="$HOST_PATH/$PART"
        CONTAINER_PATH="$CONTAINER_PATH/$PART"
        mkdir "$HOST_PATH"
        chmod 0777 "$HOST_PATH"
      done
      echo "trigger_path_length=${#CONTAINER_PATH}"
       
      COMMON_ARGS="--plugin-load-add=server_audit.so --server-audit-logging=ON --server-audit-output-type=file"
       
      # Control: same plugin and options, but a short existing directory.
      docker run --detach --name "$CONTROL" \
        --label "io.encryptiondbfuzz.owner=$OWNER" \
        --network none --read-only --cap-drop ALL \
        --security-opt no-new-privileges=true --pids-limit 160 \
        --memory 1g --cpus 1 --user 999:999 \
        --tmpfs /var/lib/mysql:rw,nosuid,nodev,size=512m,uid=999,gid=999 \
        --tmpfs /run/mysqld:rw,nosuid,nodev,size=16m,uid=999,gid=999 \
        --tmpfs /tmp:rw,nosuid,nodev,size=64m,uid=999,gid=999 \
        --mount type=bind,src="$D",dst=/edbf-audit \
        --env MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 \
        "$IMAGE" $COMMON_ARGS --server-audit-file-path=/edbf-audit/control
       
      READY=0
      for I in $(seq 1 90); do
        if docker exec --user 999:999 "$CONTROL" mariadb --protocol=socket \
             --socket=/run/mysqld/mysqld.sock -uroot -NBe 'SELECT @@port' \
             2>/dev/null | grep -qx 3306; then
          READY=1
          break
        fi
        sleep 1
      done
      test "$READY" -eq 1
      docker exec --user 999:999 "$CONTROL" \
        test -f /edbf-audit/control/server_audit.log
      echo 'short_path_control=healthy'
      owned_remove "$CONTROL"
       
      # Trigger: the path exists and is 981 bytes long inside the container.
      docker run --detach --name "$TRIGGER" \
        --label "io.encryptiondbfuzz.owner=$OWNER" \
        --network none --read-only --cap-drop ALL \
        --security-opt no-new-privileges=true --pids-limit 160 \
        --memory 1g --cpus 1 --user 999:999 \
        --tmpfs /var/lib/mysql:rw,nosuid,nodev,size=512m,uid=999,gid=999 \
        --tmpfs /run/mysqld:rw,nosuid,nodev,size=16m,uid=999,gid=999 \
        --tmpfs /tmp:rw,nosuid,nodev,size=64m,uid=999,gid=999 \
        --mount type=bind,src="$D",dst=/edbf-audit \
        --env MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 \
        "$IMAGE" $COMMON_ARGS --server-audit-file-path="$CONTAINER_PATH"
       
      timeout 90 docker wait "$TRIGGER" >/dev/null
      echo "trigger_exit_code=$(docker inspect --format '{{.State.ExitCode}}' "$TRIGGER")"
      echo "trigger_oom_killed=$(docker inspect --format '{{.State.OOMKilled}}' "$TRIGGER")"
      docker logs "$TRIGGER" 2>&1 | grep -E \
        'buffer overflow detected|got signal 6|server_audit\.so|initialize_audit_plugin|plugin_init'
      

      Actual result

      The short-path control became ready and created its audit file:

      short_path_control=healthy
      

      The trigger container was not OOM-killed. `mariadbd` exited 1 and its error log
      contained:

      trigger_path_length=981
      trigger_exit_code=1
      trigger_oom_killed=false
      *** buffer overflow detected ***: terminated
      /usr/sbin/mariadbd got signal 6 ;
      server_audit.so(+0x3912)
      server_audit.so(+0x79c5)
      initialize_audit_plugin
      plugin_init
      mysqld_main
      

      Expected result

      Startup must validate `server_audit_file_path` before copying or appending to a
      fixed buffer. An overlong value should produce a bounded configuration error;
      it must not overwrite the stack or terminate `mariadbd`.

      Attachments

        Issue Links

          Activity

            People

              holyfoot Alexey Botchkov
              csfuzz csfuzz
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:

                Time Tracking

                  Estimated:
                  Original Estimate - 0d
                  0d
                  Remaining:
                  Remaining Estimate - 1d
                  1d
                  Logged:
                  Time Spent - Not Specified
                  Not Specified

                  Git Integration

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