Merge remote-tracking branch 'origin/topic/vladg/gh-843'

Added a comment to clarify comparison of EOF packet length to 13.

* origin/topic/vladg/gh-843:
  Update baselines
  Made additional MySQL fixes.
  Add support to MySQL for deprecation of EOF packets.
  Whitespace cleanup & fixes
  Fix EOF detection in the MySQL protocol analyzer.
This commit is contained in:
Jon Siwek 2020-03-11 11:21:20 -07:00
commit 26af1f55af
5 changed files with 188 additions and 94 deletions

38
CHANGES
View file

@ -1,4 +1,42 @@
3.2.0-dev.221 | 2020-03-11 11:21:20 -0700
* Made additional MySQL fixes. (Vlad Grigorescu)
1) There are a couple more places where the new protocol uses and OK
packet instead of the deprecated EOF.
2) With > 255 results, we could end up in an situation where the uint8
sequence number would wrap, and we'd naively think it'd be a new
handshake.
Now, we track the previous sequence number, and assume overflow if it
was 255 previously and 0 now.
We also reset the previous sequence number to 0 in various packets
that we'd expect at the end of other commands.
* Add support to MySQL for deprecation of EOF packets. (Vlad Grigorescu)
From the docs: "As of MySQL 5.7.5, OK packes are also used to indicate
EOF, and EOF packets are deprecated."
The client sets a capability flag (CLIENT_DEPRECATE_EOF) to indicate
that it expects an OK instead of an EOF after the resultset rows.
* MySQL analyzer whitespace cleanup (Vlad Grigorescu)
* Fix EOF detection in the MySQL protocol analyzer. (Vlad Grigorescu)
The MySQL documentation
(https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_eof_packet.html)
warns us that "You must check whether the packet length is less than 9 to
make sure that it is a EOF_Packet packet."
While we were doing this in two places, we were comparing the total
packet length, which includes the 4-byte header. Changed to compare to
13 instead.
3.2.0-dev.214 | 2020-03-09 13:35:26 -0700
* Stop running GitHub Actions in forked repos (Jon Siwek, Corelight)

View file

@ -1 +1 @@
3.2.0-dev.214
3.2.0-dev.221

View file

@ -151,6 +151,11 @@ enum Expected {
EXPECT_AUTH_SWITCH,
};
enum Client_Capabilities {
# Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
CLIENT_DEPRECATE_EOF = 0x01000000,
};
type NUL_String = RE/[^\0]*\0/;
# MySQL PDU
@ -172,9 +177,12 @@ type Header = record {
len : uint32 = to_int()(le_len) + 4;
} &length=4;
type Server_Message(seq_id: uint8, pkt_len: uint32) = case seq_id of {
0 -> initial_handshake: Initial_Handshake_Packet;
default -> command_response : Command_Response(pkt_len);
type Server_Message(seq_id: uint8, pkt_len: uint32) = case is_initial of {
true -> initial_handshake: Initial_Handshake_Packet;
false -> command_response : Command_Response(pkt_len);
} &let {
is_initial : bool = (seq_id == 0) && ($context.connection.get_previous_seq_id() != 255);
update_seq_id : bool = $context.connection.set_previous_seq_id(seq_id);
};
type Client_Message(state: int) = case state of {
@ -230,6 +238,8 @@ type Handshake_Response_Packet_v10 = record {
pad : padding[23];
username : NUL_String;
password : bytestring &restofdata;
} &let {
deprecate_eof: bool = $context.connection.set_deprecate_eof(cap_flags & CLIENT_DEPRECATE_EOF);
};
type Handshake_Response_Packet_v9 = record {
@ -263,8 +273,8 @@ type Command_Response(pkt_len: uint32) = case $context.connection.get_expectatio
EXPECT_REST_OF_PACKET -> rest : bytestring &restofdata;
EXPECT_STATUS -> status : Command_Response_Status;
EXPECT_AUTH_SWITCH -> auth_switch : AuthSwitchRequest;
EXPECT_EOF -> eof : EOF1;
default -> unknow : empty;
EXPECT_EOF -> eof : EOFIfLegacy;
default -> unknown : empty;
};
type Command_Response_Status = record {
@ -304,19 +314,28 @@ type ColumnDefinition = record {
update_expectation: bool = $context.connection.set_next_expected($context.connection.get_remaining_cols() > 0 ? EXPECT_COLUMN_DEFINITION : EXPECT_EOF);
};
type EOFOrOK = case $context.connection.get_deprecate_eof() of {
false -> eof: EOF_Packet;
true -> ok: OK_Packet;
};
type ColumnDefinitionOrEOF(pkt_len: uint32) = record {
marker : uint8;
def_or_eof: case is_eof of {
true -> eof: EOF_Packet;
true -> eof: EOFOrOK;
false -> def: ColumnDefinition41(marker);
} &requires(is_eof);
} &let {
is_eof: bool = (marker == 0xfe && pkt_len <= 9);
# MySQL spec says "You must check whether the packet length is less than 9
# to make sure that it is a EOF_Packet packet" so the value of 13 here
# comes from that 9, plus a 4-byte header.
is_eof: bool = (marker == 0xfe && pkt_len < 13);
};
type EOF1 = record {
eof : EOF_Packet;
type EOFIfLegacy = case $context.connection.get_deprecate_eof() of {
false -> eof: EOF_Packet;
true -> none: empty;
} &let {
update_result_seen: bool = $context.connection.set_results_seen(0);
update_expectation: bool = $context.connection.set_next_expected(EXPECT_RESULTSET);
@ -325,11 +344,14 @@ type EOF1 = record {
type Resultset(pkt_len: uint32) = record {
marker : uint8;
row_or_eof: case is_eof of {
true -> eof: EOF_Packet;
true -> eof: EOFOrOK;
false -> row: ResultsetRow(marker);
} &requires(is_eof);
} &let {
is_eof: bool = (marker == 0xfe && pkt_len <= 9);
# MySQL spec says "You must check whether the packet length is less than 9
# to make sure that it is a EOF_Packet packet" so the value of 13 here
# comes from that 9, plus a 4-byte header.
is_eof : bool = (marker == 0xfe && pkt_len < 13);
update_result_seen: bool = $context.connection.inc_results_seen();
update_expectation: bool = $context.connection.set_next_expected(is_eof ? NO_EXPECTATION : EXPECT_RESULTSET);
};
@ -398,20 +420,24 @@ type EOF_Packet = record {
refine connection MySQL_Conn += {
%member{
uint8 version_;
uint8 previous_seq_id_;
int state_;
Expected expected_;
uint32 col_count_;
uint32 remaining_cols_;
uint32 results_seen_;
bool deprecate_eof_;
%}
%init{
version_ = 0;
previous_seq_id_ = 0;
state_ = CONNECTION_PHASE;
expected_ = EXPECT_STATUS;
col_count_ = 0;
remaining_cols_ = 0;
results_seen_ = 0;
deprecate_eof_ = false;
%}
function get_version(): uint8
@ -425,6 +451,17 @@ refine connection MySQL_Conn += {
return true;
%}
function get_previous_seq_id(): uint8
%{
return previous_seq_id_;
%}
function set_previous_seq_id(s: uint8): bool
%{
previous_seq_id_ = s;
return true;
%}
function get_state(): int
%{
return state_;
@ -436,6 +473,17 @@ refine connection MySQL_Conn += {
return true;
%}
function get_deprecate_eof(): bool
%{
return deprecate_eof_;
%}
function set_deprecate_eof(d: bool): bool
%{
deprecate_eof_ = d;
return true;
%}
function get_expectation(): Expected
%{
return expected_;

View file

@ -3,7 +3,7 @@
#empty_field (empty)
#unset_field -
#path mysql
#open 2018-05-17-04-01-33
#open 2020-03-07-04-49-02
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p cmd arg success rows response
#types time string addr port addr port string string bool count string
1216281025.136728 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 login tfoerste T 0 -
@ -12,7 +12,7 @@
1216281030.835395 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 init_db test T 0 -
1216281030.835742 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query show databases T 0 -
1216281030.836349 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query show tables T 0 -
1216281030.836757 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 field_list agent - - -
1216281030.836757 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 field_list agent T 0 -
1216281048.287657 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query create table foo (id BIGINT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, animal VARCHAR(64) NOT NULL, name VARCHAR(64) NULL DEFAULT NULL) ENGINE = MYISAM T 0 -
1216281057.746222 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query insert into foo (animal, name) values ("dog", "Goofy") T 1 -
1216281061.713980 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query insert into foo (animal, name) values ("cat", "Garfield") T 1 -
@ -24,4 +24,4 @@
1216281116.209268 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query delete from foo T 1 -
1216281122.880561 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 query drop table foo T 0 -
1216281124.418765 CHhAvVGS1DHFjwGM9 192.168.0.254 56162 192.168.0.254 3306 quit (empty) - - -
#close 2018-05-17-04-01-33
#close 2020-03-07-04-49-02

View file

@ -2,19 +2,24 @@ mysql ok, 0
mysql request, 3, select @@version_comment limit 1
mysql ok, 0
mysql result row, [Gentoo Linux mysql-5.0.54]
mysql ok, 0
mysql request, 3, SELECT DATABASE()
mysql ok, 0
mysql result row, []
mysql ok, 0
mysql request, 2, test
mysql ok, 0
mysql request, 3, show databases
mysql ok, 0
mysql result row, [information_schema]
mysql result row, [test]
mysql ok, 0
mysql request, 3, show tables
mysql ok, 0
mysql result row, [agent]
mysql ok, 0
mysql request, 4, agent\x00
mysql ok, 0
mysql request, 3, create table foo (id BIGINT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, animal VARCHAR(64) NOT NULL, name VARCHAR(64) NULL DEFAULT NULL) ENGINE = MYISAM
mysql ok, 0
mysql request, 3, insert into foo (animal, name) values ("dog", "Goofy")
@ -25,6 +30,7 @@ mysql request, 3, select * from foo
mysql ok, 0
mysql result row, [1, dog, Goofy]
mysql result row, [2, cat, Garfield]
mysql ok, 0
mysql request, 3, delete from foo where name like '%oo%'
mysql ok, 1
mysql request, 3, delete from foo where id = 1
@ -32,9 +38,11 @@ mysql ok, 0
mysql request, 3, select count(*) from foo
mysql ok, 0
mysql result row, [1]
mysql ok, 0
mysql request, 3, select * from foo
mysql ok, 0
mysql result row, [2, cat, Garfield]
mysql ok, 0
mysql request, 3, delete from foo
mysql ok, 1
mysql request, 3, drop table foo