From e4784703ee44d0a0a497a1a411dea20987d501ad Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 12 Feb 2018 15:19:43 +0530 Subject: [PATCH] Bug#25471090: MYSQL USE AFTER FREE Description:- Mysql client crashes when trying to connect to a fake server which is sending incorrect packets. Analysis:- Mysql client crashes when it tries to read server version details. Fix:- A check is added in "red_one_row()". --- include/mysql_com.h | 3 ++- sql-common/client.c | 16 +++++++++------- sql-common/pack.c | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 5cd40915743..52e8a367e3d 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -561,6 +561,7 @@ void my_thread_end(void); #ifdef _global_h ulong STDCALL net_field_length(uchar **packet); +ulong STDCALL net_field_length_checked(uchar **packet, ulong max_length); my_ulonglong net_field_length_ll(uchar **packet); uchar *net_store_length(uchar *pkg, ulonglong length); #endif diff --git a/sql-common/client.c b/sql-common/client.c index 759d95117cb..9972ca741f2 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1723,18 +1723,20 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) end_pos=pos+pkt_len; for (field=0 ; field < fields ; field++) { - if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) + len=(ulong) net_field_length_checked(&pos, (ulong)(end_pos - pos)); + if (pos > end_pos) + { + set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); + return -1; + } + + if (len == NULL_LENGTH) { /* null field */ row[field] = 0; *lengths++=0; } else { - if (len > (ulong) (end_pos - pos)) - { - set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); - return -1; - } row[field] = (char*) pos; pos+=len; *lengths++=len; diff --git a/sql-common/pack.c b/sql-common/pack.c index 02e91b5c3e3..57ff55689a2 100644 --- a/sql-common/pack.c +++ b/sql-common/pack.c @@ -1,5 +1,4 @@ -/* Copyright (c) 2000-2003, 2007 MySQL AB - Use is subject to license terms +/* Copyright (c) 2000, 2018 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,6 +45,40 @@ ulong STDCALL net_field_length(uchar **packet) return (ulong) uint4korr(pos+1); } +/* The same as above but with max length check */ +ulong STDCALL net_field_length_checked(uchar **packet, ulong max_length) +{ + ulong len; + uchar *pos= (uchar *)*packet; + + if (*pos < 251) + { + (*packet)++; + len= (ulong) *pos; + return (len > max_length) ? max_length : len; + } + if (*pos == 251) + { + (*packet)++; + return NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + len= (ulong) uint2korr(pos+1); + return (len > max_length) ? max_length : len; + } + if (*pos == 253) + { + (*packet)+=4; + len= (ulong) uint3korr(pos+1); + return (len > max_length) ? max_length : len; + } + (*packet)+=9; /* Must be 254 when here */ + len= (ulong) uint4korr(pos+1); + return (len > max_length) ? max_length : len; +} + /* The same as above but returns longlong */ my_ulonglong net_field_length_ll(uchar **packet) {