Bug #4017 mysql_real_connect buffer overflow
Submitted: 4 Jun 2004 19:15 Modified: 17 Jun 2004 15:42
Reporter: Lukasz Wojtow Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:4.0.18 OS:Any (All)
Assigned to: Guilhem Bichot CPU Architecture:Any

[4 Jun 2004 19:15] Lukasz Wojtow
Description:
I'm not quite sure if it's a bug, so forgive me if it's not. In mysql_real_connect() is the following code:
    hp = my_gethostbyname_r(host,&tmp_hostent,buff2.buff,sizeof(buff2),
			      &tmp_errno);
    [ ... ]
    memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);

As far as i looked my_gethostbyname_r() doesn't check if hp->h_length is more than size of sock_addr.sin_addr. Malicious user can make mysql connection to a host which dns is under his own control. This way hp->h_addr could be much larger than sin_addr and buffer overflow occurs. As it is only possible in condition when the user is able to make connection to any server, this bug's severity is not very big, but can be used to break PHP's safe mode (and possibly others)

How to repeat:
Try to connect to host: anyname.anydomain.com where dns responsible for resolving this name sends too big answer. By some chance returned address will be copied to small sock_addr.sin_addr.

Suggested fix:
Checking for length should work.
[16 Jun 2004 21:54] Matthew Lord
Hi,

I was unable to produce an overrun when using a very long IP ADDR, do you have a repeatable case for 
this one?

Thank You!
[17 Jun 2004 0:20] Lukasz Wojtow
Everything depends on library you use. In glibc there is a limitation for an IP address to have only 4 bytes (obviously), but generally speaking the length of the address comes with a response for dns query (i know it sounds funny but read rfc1035 if you don't believe). This bug can occur on libraries where gethostbyname function takes length from dns's response and puts it to h_length. see sources for ping and squid (just do grep for 'gethostbyname' and look a few lines lower) to see how it should be done. doing thing like memcpy(&sa.sin_addr,he->h_addr,he->h_length) is like strncpy(buffer,user_input,strlen(user_input)). It is an overflow, just not exploitable on Linux (glibc) and OpenBSD (i don't know about others).
Lukasz Wojtow
[17 Jun 2004 0:26] Matthew Lord
I couldn't reproduce it, but it is theoretically possible to overflow the buffer and it would not hurt in any 
case to put a check for the size.
[17 Jun 2004 15:42] Guilhem Bichot
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.

If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information 
about accessing the source trees is available at
    http://www.mysql.com/doc/en/Installing_source_tree.html

Additional info:

Thank you a lot for noticing this problem and providing a very thorough explanation!
I have just fixed it like this
      memcpy(&sock_addr.sin_addr,hp->h_addr,
             min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length));
And I have checked all code and there is no occurence of that problem elsewhere.

ChangeSet@1.1424.3.1, 2004-06-17 15:40:13+02:00, guilhem@mysql.com in 3.23