Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typeCast: false causes out of bounds reads to packet when result set contains NULL values and binary protocol is used. #2602

Closed
Parsonswy opened this issue Apr 18, 2024 · 0 comments · Fixed by #2601

Comments

@Parsonswy
Copy link
Contributor

I noticed this when debugging a separate issue relating to out of bounds reads in the binary parser.

Presently the binary parser does not check the NULL mask when the MySQL connection is configured with typeCast: false and will always attempt to readLengthCodedBuffer which causes the results to be nonsensical or the whole connection to panic. In my testing if there were less than three NULL values in the result row it just caused mangling, but after the fourth the connection state was corrupted.

I've created a PR that checks nullBitmaskByte before attempting to readLengthCodedBuffer() to go along with this issue. When the cell is null the parser will push NULL to the results. I considered doing an empty buffer, but thought that might be ambiguous since length 0 strings and empty blob fields would also be empty buffers, I think. I don't use typeCast: false in a meaningful capacity though so I am not attached to either approach.

Test Table

Create Table: CREATE TABLE `binparse` (
  `id` int NOT NULL AUTO_INCREMENT,
  `n1` varchar(32) DEFAULT NULL,
  `n2` varchar(32) DEFAULT NULL,
  `n3` varchar(32) DEFAULT NULL,
  `n4` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
+----+------+------+------+------+
| id | n1   | n2   | n3   | n4   |
+----+------+------+------+------+
|  1 | NULL | NULL | NULL | NULL |
|  2 | NULL | NULL | NULL | NULL |
|  3 | NULL | NULL | NULL | NULL |
+----+------+------+------+------+

Three Nulls

const connection = await mysql.createConnection({
	debug: true,
	typeCast: false
        ...
});
connection.execute(
	'SELECT n1,n2,n3 FROM binparse',
	[],
	(error, result, fields) => {
		console.log(result);
	}
);
0 20154 ==> Execute#row(9,EOF,9)
[
  [Object: null prototype] {
    n1: <Buffer 00 00>,
    n2: <Buffer 00 1c 02 00 00 08 00>,
    n3: <Buffer 05 00 00 09 fe 00 00 22 00>                                                                                                                                                                                                                                    },
  [Object: null prototype] {                                                                                                                                                                                                                                                     n1: <Buffer 00 00>,
    n2: <Buffer 00 1c 05 00 00 09 fe 00>,
    n3: <Buffer >
  },
  [Object: null prototype] {
    n1: <Buffer 00 00 09 fe 00>,
    n2: <Buffer >,
    n3: <Buffer 00>
  }
]

Four Nulls

const connection = await mysql.createConnection({
	debug: true,
	typeCast: false
        ...
});
connection.execute(
	'SELECT n1,n2,n3,n4 FROM binparse',
	[],
	(error, result, fields) => {
		console.log(result);
	}
);
Error: Should not reach here: undefined
    at Packet.readLengthCodedNumberExt (/home/wyatt/Repos/2873-13-vw-cup-lxp-api/node_modules/mysql2/lib/packets/packet.js:232:11)
    at Packet.readLengthCodedNumber (/home/wyatt/Repos/2873-13-vw-cup-lxp-api/node_modules/mysql2/lib/packets/packet.js:193:17)                                                                                                                                                  at Packet.readLengthCodedBuffer (/home/wyatt/Repos/2873-13-vw-cup-lxp-api/node_modules/mysql2/lib/packets/packet.js:398:22)
    ...
0 20130 ==> (no command)#(no command)(9,maybeOK,6)
node:events:491                                                                                                                                                                                                                                                                    throw er; // Unhandled 'error' event
      ^
...
Error: Unexpected packet while no commands in the queue
    at Connection.protocolError (/home/wyatt/Repos/2873-13-vw-cup-lxp-api/node_modules/mysql2/lib/connection.js:409:17)
    at Connection.handlePacket (/home/wyatt/Repos/2873-13-vw-cup-lxp-api/node_modules/mysql2/lib/connection.js:454:14)
    ...
  fatal: true,
  code: 'PROTOCOL_UNEXPECTED_PACKET'
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 a pull request may close this issue.

1 participant