Bug #46440 memcmp() for struct sockaddr_storage is invalid
Description:
On line 245 of sql/hostname.cc, memcmp is used to compare a struct sockaddr_storage* (in) to a struct sockaddr* (t_res->ai_addr). I believe this is invalid, because of the following code I added to debug this problem.
printf("Getaddrinfo result: %0*X\n", t_res->ai_addrlen, t_res->ai_addr);
printf("In: %0*X\n", addrLen, in);
printf("Getaddrinfo result: %0*X\n", 4, ((struct sockaddr_in*)t_res->ai_addr)->sin_addr);
printf("In: %0*X\n", 4, ((struct sockaddr_in*)in)->sin_addr);
printf("Getaddrinfo result: %p\n", &((struct sockaddr_in*)t_res->ai_addr)->sin_addr);
printf("In: %p\n", &((struct sockaddr_in*)in)->sin_addr);
This code prints (for example):
Getaddrinfo result: 0000000008062110
In: 0000000008047B84
Getaddrinfo result: FC5F5582
In: FC5F5582
Getaddrinfo result: 8062114
In: 8047b88
This shows that because t_res->ai_addr (a struct sockaddr*) has a pointer as part of its structure, using memcmp() to compare the contents of "t_res->ai_addr" and "in" is invalid.
The attached patch *should* fix the problem... but it doesn't.
How to repeat:
Build mysql-cluster-gpl-7.0.6 on Solaris (or install the precompiled binaries). Add a GRANT like:
GRANT ALL ON *.* to 'user'@'chasca.cs.umbc.edu';
Try to connect from the specified user and host. Get an error like this:
Access denied for user 'user'@'::ffff:130.85.95.252'
Suggested fix:
--- mysql-cluster-gpl-7.0.6/sql/hostname.cc Tue May 26 10:34:43 2009
+++ mysql-cluster-gpl-7.0.6-mod//sql/hostname.cc Tue Jul 28 17:22:14 2009
@@ -137,6 +148,18 @@
char * ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors)
{
char *name= NULL;
+ if (in->ss_family == AF_INET6)
+ {
+ if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)in)->sin6_addr))
+ {
+ struct sockaddr_in foo;
+ bzero(&foo, sizeof(struct sockaddr));
+ foo.sin_family = AF_INET;
+ foo.sin_port = ((struct sockaddr_in6*)in)->sin6_port;
+ memcpy(&foo.sin_addr.s_addr, &((struct sockaddr_in6*)in)->sin6_addr.s6_addr[12], 4);
+ in = (struct sockaddr_storage*)&foo;
+ }
+ }
struct addrinfo hints,*res_lst= NULL,*t_res;
int gxi_error;
@@ -149,7 +172,7 @@
/* Historical comparison for 127.0.0.1 */
gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
hostname_buff, NI_MAXHOST,
- NULL, 0, NI_NUMERICHOST);
+ NULL, 0, 0);
if (gxi_error)
{
DBUG_PRINT("error",("getnameinfo returned %d", gxi_error));
@@ -242,8 +265,16 @@
/* Check that 'getaddrinfo' returned the used ip */
for (t_res= res_lst; t_res; t_res=t_res->ai_next)
{
- if (!memcmp(&(t_res->ai_addr), in,
- sizeof(struct sockaddr_storage) ) )
+ if ((in->ss_family == t_res->ai_addr->sa_family) &&
+ (((in->ss_family == AF_INET) &&
+ (((struct sockaddr_in*)in)->sin_addr.s_addr ==
+ ((struct sockaddr_in*)t_res->ai_addr)->sin_addr.s_addr))
+ ||
+ ((in->ss_family == AF_INET6) &&
+ (!memcmp(
+ (void*)&((struct sockaddr_in6*)in)->sin6_addr,
+ (void*)&((struct sockaddr_in6*)t_res->ai_addr)->sin6_addr,
+ sizeof(struct in6_addr))))))
{
add_hostname(in,name);
freeaddrinfo(res_lst);
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.051 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: On line 245 of sql/hostname.cc, memcmp is used to compare a struct sockaddr_storage* (in) to a struct sockaddr* (t_res->ai_addr). I believe this is invalid, because of the following code I added to debug this problem. printf("Getaddrinfo result: %0*X\n", t_res->ai_addrlen, t_res->ai_addr); printf("In: %0*X\n", addrLen, in); printf("Getaddrinfo result: %0*X\n", 4, ((struct sockaddr_in*)t_res->ai_addr)->sin_addr); printf("In: %0*X\n", 4, ((struct sockaddr_in*)in)->sin_addr); printf("Getaddrinfo result: %p\n", &((struct sockaddr_in*)t_res->ai_addr)->sin_addr); printf("In: %p\n", &((struct sockaddr_in*)in)->sin_addr); This code prints (for example): Getaddrinfo result: 0000000008062110 In: 0000000008047B84 Getaddrinfo result: FC5F5582 In: FC5F5582 Getaddrinfo result: 8062114 In: 8047b88 This shows that because t_res->ai_addr (a struct sockaddr*) has a pointer as part of its structure, using memcmp() to compare the contents of "t_res->ai_addr" and "in" is invalid. The attached patch *should* fix the problem... but it doesn't. How to repeat: Build mysql-cluster-gpl-7.0.6 on Solaris (or install the precompiled binaries). Add a GRANT like: GRANT ALL ON *.* to 'user'@'chasca.cs.umbc.edu'; Try to connect from the specified user and host. Get an error like this: Access denied for user 'user'@'::ffff:130.85.95.252' Suggested fix: --- mysql-cluster-gpl-7.0.6/sql/hostname.cc Tue May 26 10:34:43 2009 +++ mysql-cluster-gpl-7.0.6-mod//sql/hostname.cc Tue Jul 28 17:22:14 2009 @@ -137,6 +148,18 @@ char * ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors) { char *name= NULL; + if (in->ss_family == AF_INET6) + { + if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)in)->sin6_addr)) + { + struct sockaddr_in foo; + bzero(&foo, sizeof(struct sockaddr)); + foo.sin_family = AF_INET; + foo.sin_port = ((struct sockaddr_in6*)in)->sin6_port; + memcpy(&foo.sin_addr.s_addr, &((struct sockaddr_in6*)in)->sin6_addr.s6_addr[12], 4); + in = (struct sockaddr_storage*)&foo; + } + } struct addrinfo hints,*res_lst= NULL,*t_res; int gxi_error; @@ -149,7 +172,7 @@ /* Historical comparison for 127.0.0.1 */ gxi_error= getnameinfo((struct sockaddr *)in, addrLen, hostname_buff, NI_MAXHOST, - NULL, 0, NI_NUMERICHOST); + NULL, 0, 0); if (gxi_error) { DBUG_PRINT("error",("getnameinfo returned %d", gxi_error)); @@ -242,8 +265,16 @@ /* Check that 'getaddrinfo' returned the used ip */ for (t_res= res_lst; t_res; t_res=t_res->ai_next) { - if (!memcmp(&(t_res->ai_addr), in, - sizeof(struct sockaddr_storage) ) ) + if ((in->ss_family == t_res->ai_addr->sa_family) && + (((in->ss_family == AF_INET) && + (((struct sockaddr_in*)in)->sin_addr.s_addr == + ((struct sockaddr_in*)t_res->ai_addr)->sin_addr.s_addr)) + || + ((in->ss_family == AF_INET6) && + (!memcmp( + (void*)&((struct sockaddr_in6*)in)->sin6_addr, + (void*)&((struct sockaddr_in6*)t_res->ai_addr)->sin6_addr, + sizeof(struct in6_addr)))))) { add_hostname(in,name); freeaddrinfo(res_lst);