Skip to content

MDEV-40385 use-of-uninitialized-value in Binary_string::c_ptr()#5448

Open
LukeYL026 wants to merge 2 commits into
MariaDB:11.4from
LukeYL026:mdev-40385-cptr-use-of-uninitialized-value
Open

MDEV-40385 use-of-uninitialized-value in Binary_string::c_ptr()#5448
LukeYL026 wants to merge 2 commits into
MariaDB:11.4from
LukeYL026:mdev-40385-cptr-use-of-uninitialized-value

Conversation

@LukeYL026

@LukeYL026 LukeYL026 commented Jul 23, 2026

Copy link
Copy Markdown

Description

SELECT KDF('','',1000,256) triggered an MSAN use-of-uninitialized-value
report originating in Binary_string::c_ptr() (sql/sql_string.h) reached from
Item_func_kdf::val_str() (sql/item_strfunc.cc).

In Item_func_kdf::val_str(String *buf) the optional 4th argument (kdf_name)
was evaluated into the shared result buffer buf and then read as a C
string:

if (String *s= args[3]->val_str(buf))      // buf == the shared result buffer
{
  if (strcasecmp(s->c_ptr(), "hkdf") == 0)
  ...

The issue is when args[3] is an integer literal (here 256), Item_int::val_str() writes the digits "256" (length 3) into the buffer, and String::alloc() intentionally skips reallocation when the buffer is already large enough — so the buffer stays non-alloced and is left without a trailing NUL.

c_ptr() then executes:

if (unlikely(!alloced && !Ptr[str_length]))   // reads Ptr[3]
  return Ptr;

Because the buffer is not alloced, c_ptr() first reads Ptr[str_length]
(i.e. buf[3]) to decide whether a terminator already exists. That byte is
validly addressable (the buffer is large) but was never initialized, so MSAN
flags a use-of-uninitialized-value. Valgrind does not flag it because that stack
byte was typically written by an earlier call frame; only MSAN re-poisons the
stack scope, which is why the report is MSAN-only.

Fix

sql/item_strfunc.cc, Item_func_kdf::val_str():

  • Use s->c_ptr_safe() instead of s->c_ptr(). c_ptr_safe() never reads
    Ptr[str_length]; it writes the terminator (or reallocates), removing the
    uninitialized read regardless of the buffer's alloced state.

Behaviour is unchanged for callers: a non-matching kdf_name still yields the
ER_STD_INVALID_ARGUMENT warning and NULL, and valid names (pbkdf2_hmac,
hkdf) still work.

Release Notes

Resolved uninitialized read deficiency in Binary_string::c_ptr() via item_func_kdf::val_str().

How can this PR be tested?

Because this stray read is harmless without a sanitizer, related MTR tests need to be run on an MSAN build to observe regression. Run MTR on an MSAN build by adding build flag-DWITH_MSAN=ON (clang), which requires MSAN-instrumented system
libraries — see
https://mariadb.com/kb/en/compile-and-using-mariadb-with-sanitizers-asan-ubsan-tsan-msan/

The following test and result files were added as regression tests:

  • mysql-test/main/mdev40385.test
  • mysql-test/main/mdev40385.result

Basing the PR against the correct MariaDB version

Based against 11.4, the oldest maintained LTS affected. The JIRA MSAN matrix
shows 10.6 and 10.11 as unaffected because the KDF() function does not
exist there; the defect is present from 11.4 onward.

Copyright

All new code of the whole pull request, including one or several files that are
either new files or modified ones, are contributed under the BSD-new license. I
am contributing on behalf of my employer Amazon Web Services, Inc.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@LukeYL026
LukeYL026 force-pushed the mdev-40385-cptr-use-of-uninitialized-value branch from 1a3f8b8 to 17d6a3a Compare July 23, 2026 18:25
@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Jul 24, 2026
@gkodinov gkodinov self-assigned this Jul 24, 2026

@gkodinov gkodinov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! This is a preliminary review.

Comment thread sql/item_strfunc.cc Outdated
SELECT KDF('','',1000,256) triggered an MSAN use-of-uninitialized-value
report in Binary_string::c_ptr() (sql/sql_string.h) reached from
Item_func_kdf::val_str().

The optional 4th argument (kdf_name) was evaluated into a result buffer
and then read as a C string with c_ptr(). When that argument is an
integer literal such as 256, Item_int::val_str() writes the digits "256"
into the buffer without appending a trailing NUL, and String::alloc()
intentionally skips reallocation, so the buffer stays non-"alloced" and
unterminated. c_ptr() then reads Ptr[str_length] to test for an existing
terminator, reading an uninitialized byte. The buffer is a stack-resident
ValueBuffer from Protocol::send_result_set_row, so the byte is validly
addressable but never initialized; only MSAN re-poisons the stack scope,
which is why the report is MSAN-only and Valgrind does not flag it.

Use c_ptr_safe() instead of c_ptr() when reading the kdf_name argument.
c_ptr_safe() writes the NUL terminator after a capacity check without
first reading Ptr[str_length], while c_ptr() reads that byte to detect an
existing terminator. Behaviour is unchanged: a non-matching kdf_name still
yields ER_STD_INVALID_ARGUMENT and NULL, and valid names (pbkdf2_hmac,
hkdf) still work.

The regression test main.mdev40385 reproduces the report only under an
MSAN-instrumented build; on a normal build it passes on both the unfixed
and fixed server because the stray read is harmless without a sanitizer.

All new code of the whole pull request, including one or several files that
are either new files or modified ones, are contributed under the BSD-new
license. I am contributing on behalf of my employer Amazon Web Services,
Inc.
@LukeYL026
LukeYL026 force-pushed the mdev-40385-cptr-use-of-uninitialized-value branch from 17d6a3a to c08441e Compare July 24, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

2 participants