Skip to content
/ server Public

Commit 8437643

Browse files
rophyvuvova
authored andcommitted
MDEV-38431: fix database pointer calculation for long passwords
When a client connects with CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability and a password >= 251 bytes, the server incorrectly calculates the database name pointer. For passwords >= 251 bytes, LENENC uses a 3-byte prefix (0xFC + 2 bytes), but the old code assumed a 1-byte prefix. Fix by using the passwd pointer which has already been advanced past the length prefix by safe_net_field_length_ll(). Also fix db pointer calculation for old protocol (!CLIENT_SECURE_CONNECTION) where the password is null-terminated and needs +1 to skip the terminator.
1 parent 52a2b72 commit 8437643

File tree

3 files changed

+108
-8
lines changed

3 files changed

+108
-8
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# Setup
3+
#
4+
INSTALL PLUGIN IF NOT EXISTS cleartext_plugin_server SONAME '';
5+
Warnings:
6+
Note 1968 Plugin 'cleartext_plugin_server' already installed
7+
CREATE DATABASE mdev38431_db;
8+
#
9+
# Test 1: Short password - baseline test
10+
#
11+
CREATE USER shortuser IDENTIFIED VIA cleartext_plugin_server USING 'secret';
12+
GRANT ALL ON *.* TO shortuser;
13+
db
14+
mdev38431_db
15+
#
16+
# Test 2: Long password 260 bytes (triggers 3-byte LENENC)
17+
# Before fix: ERROR 1044 Access denied to database 'X' (garbage char)
18+
# After fix: Connects to mdev38431_db correctly
19+
#
20+
CREATE USER longuser IDENTIFIED VIA cleartext_plugin_server USING 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
21+
GRANT ALL ON *.* TO longuser;
22+
db
23+
mdev38431_db
24+
#
25+
# Test 3: Even longer password 500 bytes
26+
#
27+
CREATE USER verylonguser IDENTIFIED VIA cleartext_plugin_server USING 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
28+
GRANT ALL ON *.* TO verylonguser;
29+
db
30+
mdev38431_db
31+
#
32+
# Cleanup
33+
#
34+
DROP USER shortuser, longuser, verylonguser;
35+
DROP DATABASE mdev38431_db;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#
2+
# MDEV-38431: Auth Switch with Long Password Corrupts Database Name
3+
#
4+
# When password >= 251 bytes with CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA,
5+
# the length is encoded in 3 bytes (0xFC + 2 bytes). The server incorrectly
6+
# calculated the database pointer, causing connection to wrong database.
7+
#
8+
# Fix: Use 'passwd + passwd_len' instead of 'db + passwd_len + 1'
9+
#
10+
11+
--source include/not_embedded.inc
12+
--source include/have_plugin_auth.inc
13+
14+
--echo #
15+
--echo # Setup
16+
--echo #
17+
eval INSTALL PLUGIN IF NOT EXISTS cleartext_plugin_server SONAME '$PLUGIN_AUTH';
18+
CREATE DATABASE mdev38431_db;
19+
20+
--echo #
21+
--echo # Test 1: Short password - baseline test
22+
--echo #
23+
CREATE USER shortuser IDENTIFIED VIA cleartext_plugin_server USING 'secret';
24+
GRANT ALL ON *.* TO shortuser;
25+
26+
# Connect with short password and verify database
27+
--exec $MYSQL -h 127.0.0.1 -P $MASTER_MYPORT --default-auth=mysql_clear_password -u shortuser -p"secret" --database=mdev38431_db -e "SELECT DATABASE() AS db"
28+
29+
--echo #
30+
--echo # Test 2: Long password 260 bytes (triggers 3-byte LENENC)
31+
--echo # Before fix: ERROR 1044 Access denied to database 'X' (garbage char)
32+
--echo # After fix: Connects to mdev38431_db correctly
33+
--echo #
34+
35+
# Create password with 260 'a' characters
36+
--let $long_pwd=`SELECT REPEAT('a', 260)`
37+
eval CREATE USER longuser IDENTIFIED VIA cleartext_plugin_server USING '$long_pwd';
38+
GRANT ALL ON *.* TO longuser;
39+
40+
# This connection uses --default-auth=mysql_clear_password to trigger auth switch
41+
# With a password >= 251 bytes, the client sends password length in 3-byte format
42+
# The bug caused the server to read database name from wrong offset
43+
--exec $MYSQL -h 127.0.0.1 -P $MASTER_MYPORT --default-auth=mysql_clear_password -u longuser -p"$long_pwd" --database=mdev38431_db -e "SELECT DATABASE() AS db"
44+
45+
--echo #
46+
--echo # Test 3: Even longer password 500 bytes
47+
--echo #
48+
--let $very_long_pwd=`SELECT REPEAT('b', 500)`
49+
eval CREATE USER verylonguser IDENTIFIED VIA cleartext_plugin_server USING '$very_long_pwd';
50+
GRANT ALL ON *.* TO verylonguser;
51+
52+
--exec $MYSQL -h 127.0.0.1 -P $MASTER_MYPORT --default-auth=mysql_clear_password -u verylonguser -p"$very_long_pwd" --database=mdev38431_db -e "SELECT DATABASE() AS db"
53+
54+
--echo #
55+
--echo # Cleanup
56+
--echo #
57+
DROP USER shortuser, longuser, verylonguser;
58+
DROP DATABASE mdev38431_db;
59+
# Note: Do not uninstall cleartext_plugin_server as it was pre-loaded by MTR

sql/sql_acl.cc

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13846,25 +13846,31 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
1384613846
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
1384713847
*passwd > 127 and become 2**32-127+ after casting to uint.
1384813848
*/
13849-
ulonglong len;
1385013849
size_t passwd_len;
1385113850

1385213851
if (!(thd->client_capabilities & CLIENT_SECURE_CONNECTION))
13853-
len= strlen(passwd);
13852+
{
13853+
passwd_len= strlen(passwd);
13854+
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
13855+
passwd + passwd_len + 1 : 0; /* +1 to skip null terminator */
13856+
}
1385413857
else if (!(thd->client_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA))
13855-
len= (uchar)(*passwd++);
13858+
{
13859+
passwd_len= (uchar)(*passwd++);
13860+
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
13861+
passwd + passwd_len : 0;
13862+
}
1385613863
else
1385713864
{
13858-
len= safe_net_field_length_ll((uchar**)&passwd,
13865+
ulonglong len= safe_net_field_length_ll((uchar**)&passwd,
1385913866
net->read_pos + pkt_len - (uchar*)passwd);
1386013867
if (len > pkt_len)
1386113868
return packet_error;
13869+
passwd_len= (size_t)len;
13870+
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
13871+
passwd + passwd_len : 0;
1386213872
}
1386313873

13864-
passwd_len= (size_t)len;
13865-
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
13866-
db + passwd_len + 1 : 0;
13867-
1386813874
if (passwd == NULL ||
1386913875
passwd + passwd_len + MY_TEST(db) > (char*) net->read_pos + pkt_len)
1387013876
return packet_error;

0 commit comments

Comments
 (0)