Skip to content

PS-11938 [8.4] Reject non-constant managed type and managed name in a… - #6289

Merged
jankowsk merged 1 commit into
percona:8.4from
jankowsk:PS-11938-8.4
Oct 29, 2026
Merged

jankowsk merged 1 commit into
percona:8.4from
jankowsk:PS-11938-8.4

Conversation

@jankowsk

Copy link
Copy Markdown
Contributor

…synchronous_connection_failover_add_managed

https://perconadev.atlassian.net/browse/PS-11938

Problem

asynchronous_connection_failover_add_managed() crashes the server when its managed-type argument is a non-constant expression of length 16, for example a CHAR(16) column, or when its managed-name argument is a non-constant expression of a valid UUID text length (32, 36 or 38), for example a CHAR(36) column:

SELECT asynchronous_connection_failover_add_managed('ch1', mt,
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '127.0.0.1', 3310, '', 80, 60)
FROM t;
SELECT asynchronous_connection_failover_add_managed('ch1',
'GroupReplication', mn, '127.0.0.1', 3310, '', 80, 60)
FROM t;

The crash happens in the UDF init function, which runs before the SUPER / REPLICATION_SLAVE_ADMIN check, so any account that can execute the SELECT reaches it: an unprivileged-user denial of service.

Analysis

The UDF init validates the managed type by comparing UDF_ARGS::args[1] with "GroupReplication", and the managed name by parsing args[2] as a UUID (binary_log::Uuid::is_valid). For a non-constant argument the server leaves args[i] == nullptr while args->lengths[i] holds the column maximum length. When that length is 16 (managed type) the length guard passes and the comparison dereferences the NULL pointer (add_managed_init -> memcmp); when it is a valid UUID text length (managed name) the parser dereferences it (Uuid::parse -> read_section). These are the only two arguments dereferenced during init: channel, hostname and network_namespace are read from the per-row value in the UDF body, where a non-constant argument is valid, and the integer arguments already reject a NULL pointer. They are left unchanged.

This is separate from Bug#39603374, which replaced strcmp() with a length-bounded memcmp() over the managed type; that fix does not add the missing NULL checks and both crashes remain on current upstream.

Fix

Reject a non-constant (NULL) managed-type or managed-name argument with ER_CANT_INITIALIZE_UDF, the same way the integer arguments are already validated, before the comparison and before the UUID parse.

Test case added. It exercises the rejected calls from an account that has only SELECT on the table, since that account reaches the init function, and checks that a well-formed call from it is still refused by the privilege check.

…synchronous_connection_failover_add_managed

https://perconadev.atlassian.net/browse/PS-11938

Problem
-------
asynchronous_connection_failover_add_managed() crashes the server when
its managed-type argument is a non-constant expression of length 16,
for example a CHAR(16) column, or when its managed-name argument is a
non-constant expression of a valid UUID text length (32, 36 or 38), for
example a CHAR(36) column:

  SELECT asynchronous_connection_failover_add_managed('ch1', mt,
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '127.0.0.1', 3310, '', 80, 60)
  FROM t;
  SELECT asynchronous_connection_failover_add_managed('ch1',
    'GroupReplication', mn, '127.0.0.1', 3310, '', 80, 60)
  FROM t;

The crash happens in the UDF init function, which runs before the
SUPER / REPLICATION_SLAVE_ADMIN check, so any account that can execute
the SELECT reaches it: an unprivileged-user denial of service.

Analysis
--------
The UDF init validates the managed type by comparing UDF_ARGS::args[1]
with "GroupReplication", and the managed name by parsing args[2] as a
UUID (binary_log::Uuid::is_valid). For a non-constant argument the
server leaves args[i] == nullptr while args->lengths[i] holds the
column maximum length. When that length is 16 (managed type) the length
guard passes and the comparison dereferences the NULL pointer
(add_managed_init -> memcmp); when it is a valid UUID text length
(managed name) the parser dereferences it (Uuid::parse -> read_section).
These are the only two arguments dereferenced during init: channel,
hostname and network_namespace are read from the per-row value in the
UDF body, where a non-constant argument is valid, and the integer
arguments already reject a NULL pointer. They are left unchanged.

This is separate from Bug#39603374, which replaced strcmp() with a
length-bounded memcmp() over the managed type; that fix does not add
the missing NULL checks and both crashes remain on current upstream.

Fix
---
Reject a non-constant (NULL) managed-type or managed-name argument with
ER_CANT_INITIALIZE_UDF, the same way the integer arguments are already
validated, before the comparison and before the UUID parse.

Test case added. It exercises the rejected calls from an account that
has only SELECT on the table, since that account reaches the init
function, and checks that a well-formed call from it is still refused
by the privilege check.
@jankowsk

jankowsk commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

@jaideepkarande jaideepkarande left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@jankowsk
jankowsk merged commit 78ce755 into percona:8.4 Oct 29, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants