Repository navigation
PS-11938 [9.7] Reject non-constant managed type and managed name in a… - #6291
Merged
Merged
Conversation
…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.
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…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.