Skip to content

Commit 3099bab

Browse files
author
Anushree Prakash B
committed
Bug#30885987 - ANOTHER BUFFER OVERFLOWS IN CLI_READ_ROWS
DESCRIPTION =========== There is a heap buffer over read and over write while reading rows if the packet contents are bad. ANALYSIS ======== There are some missing boundary checks in client-side functions which can cause read or write buffer overflows. FIX === Added checks in the required code path to avoid buffer overflows. RB: 25367
1 parent 8ed6479 commit 3099bab

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#######################################################
2+
# checks if mysql is debug compiled.
3+
# This "cannot" be done simply by using have_debug.inc
4+
######################################################
5+
6+
--disable_query_log
7+
--let $temp_out_help_file=$MYSQL_TMP_DIR/mysql_help.tmp
8+
--exec $MYSQL --help>$temp_out_help_file
9+
let log_tmp=$temp_out_help_file;
10+
--let $temp_inc=$MYSQL_TMP_DIR/temp.inc
11+
let inc_tmp=$temp_inc;
12+
13+
--perl
14+
use strict;
15+
my $tmp_file= $ENV{'log_tmp'} or die "log_tmp not set";
16+
open(FILE, "$tmp_file") or die("Unable to open $tmp_file: $!\n");
17+
my $count = () = grep(/Output debug log/g,<FILE>);
18+
close FILE;
19+
20+
my $temp_inc= $ENV{'inc_tmp'} or die "temp_inc not set";
21+
open(FILE_INC,">", "$temp_inc") or die("can't open file \"$temp_inc\": $!");
22+
print FILE_INC '--let $is_debug= '.$count;
23+
close FILE_INC;
24+
EOF
25+
--source $temp_inc
26+
27+
if (!$is_debug)
28+
{
29+
--skip mysql needs to be debug compiled
30+
}
31+
--remove_file $temp_out_help_file
32+
--remove_file $temp_inc
33+
--enable_query_log

sql-common/client.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,20 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
16951695
end_pos=pos+pkt_len;
16961696
for (field=0 ; field < fields ; field++)
16971697
{
1698+
if (pos >= end_pos) {
1699+
set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1700+
return -1;
1701+
}
16981702
len=(ulong) net_field_length_checked(&pos, (ulong)(end_pos - pos));
1703+
DBUG_EXECUTE_IF("simulate_bad_field_length_1", {
1704+
len= 1000000L;
1705+
fields= 2;
1706+
});
1707+
DBUG_EXECUTE_IF("simulate_bad_field_length_2", {
1708+
len= pkt_len - 1;
1709+
fields= 2;
1710+
});
1711+
16991712
if (pos > end_pos)
17001713
{
17011714
set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
@@ -1713,12 +1726,18 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
17131726
pos+=len;
17141727
*lengths++=len;
17151728
}
1729+
1730+
/*
1731+
It's safe to write to prev_pos here because we already check
1732+
for a valid pos in the beginning of this loop.
1733+
*/
17161734
if (prev_pos)
17171735
*prev_pos=0; /* Terminate prev field */
17181736
prev_pos=pos;
17191737
}
17201738
row[field]=(char*) prev_pos+1; /* End of last field */
1721-
*prev_pos=0; /* Terminate last field */
1739+
if (prev_pos < end_pos)
1740+
*prev_pos=0; /* Terminate last field */
17221741
return 0;
17231742
}
17241743

sql/net_serv.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -215,6 +215,17 @@ void net_clear(NET *net,
215215
{
216216
DBUG_ENTER("net_clear");
217217

218+
DBUG_EXECUTE_IF("simulate_bad_field_length_1", {
219+
net->pkt_nr= net->compress_pkt_nr= 0;
220+
net->write_pos= net->buff;
221+
DBUG_VOID_RETURN;
222+
});
223+
DBUG_EXECUTE_IF("simulate_bad_field_length_2", {
224+
net->pkt_nr= net->compress_pkt_nr= 0;
225+
net->write_pos= net->buff;
226+
DBUG_VOID_RETURN;
227+
});
228+
218229
#if !defined(EMBEDDED_LIBRARY)
219230
/* Ensure the socket buffer is empty, except for an EOF (at least 1). */
220231
DBUG_ASSERT(!check_buffer || (vio_pending(net->vio) <= 1));

0 commit comments

Comments
 (0)