[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
libldap: too little space allocated for IPv6 address *patch* (ITS#2018)
Full_Name: Thorild Selén
Version: 2.0.23 and HEAD
OS: Linux 2.4.19 (Debian)
URL:
Submission from: (NULL) (130.238.19.17)
(In brief: IPv6 address allocation problem; patch at end)
I was using strace to examine a program that kept hanging, and saw:
> connect(10, {sin_family=AF_INET6, sin6_port=htons(389),
> inet_pton(AF_INET6, "3ffe:200:66:8000::11", &sin6_addr),
> sin6_flowinfo=0 , sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation
> now in progress)
> select(1024, NULL, [10], NULL, {16, 0}) = 1 (out [10], left {16, 0})
(We connect to the LDAP server. All is well so far. From the data that follows,
this looks like libnss_ldap checking which groups exist on the system.)
And then:
> getpeername(10, {sin_family=AF_INET6, sin6_port=htons(389),
> inet_pton(AF_INET6, "3ffe:200:66:8000:1cd3:ffbf:ac7c:5940",
> &sin6_addr), sin6_flowinfo=0, sin6_scope_id=137790328}, [28]) = 0
> fcntl64(10, F_GETFL) = 0x802 (flags O_RDWR|O_NONBLOCK)
> fcntl64(10, F_SETFL, O_RDWR) = 0
> getpeername(10, {sin_family=AF_INET6, sin6_port=htons(389),
> inet_pton(AF_INET6, "3ffe:200:66:8000:2cd4:ffbf:af7a:5840",
> &sin6_addr), sin6_flowinfo=0, sin6_scope_id=139343664}, [28]) = 0
The second parts of these addresses are mangled; something isn't allocating
enough space to store an IPv6 address. That made me look in the libldap
source for a bug of this kind, and saw that in libraries/libldap/os-ip.c,
in ldap_host_connected_to, an auto struct sockaddr is used to store an
address; possibly an IPv6 address, which won't fit; a struct
sockaddr_storage should be used instead (see RFC 2553). This bug is present
in this version as well as in the present working version (HEAD).
Below is a patch for HEAD.
/Thorild
Patch copyright 2002 Thorild Selén, all rights reserved.
Contains code copyright 1999-2001 the OpenLDAP Foundation,
Redwood City, California, USA.
This is free software; you can redistribute and use it
under the same terms as OpenLDAP itself.
=========================================================
diff -Naur ldap/libraries/libldap/os-ip.c ldap-new/libraries/libldap/os-ip.c
--- ldap/libraries/libldap/os-ip.c Sun Jul 28 03:30:39 2002
+++ ldap-new/libraries/libldap/os-ip.c Fri Aug 9 17:50:51 2002
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.79 2002/07/28 03:30:39
kurt Exp $ */
+/* $OpenLDAP: /libraries/libldap/os-ip.c,v 1.72.2.4 2002/07/28 19:10:46 kurt
Exp $ */
/*
* Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
@@ -482,7 +482,13 @@
{
struct hostent *hp;
socklen_t len;
- struct sockaddr sa;
+#ifdef LDAP_PF_INET6
+ struct sockaddr_storage sa_storage;
+#else
+ struct sockaddr sa_storage;
+#endif
+ struct sockaddr *sa = (struct sockaddr *) &sa_storage;
+
char *addr;
char *host;
@@ -492,11 +498,11 @@
char *ha_buf=NULL;
ber_socket_t sd;
- (void)memset( (char *)&sa, '\0', sizeof( struct sockaddr ));
- len = sizeof( sa );
+ (void)memset( (char *)&sa_storage, '\0', sizeof( sa_storage ));
+ len = sizeof( sa_storage );
ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
- if ( getpeername( sd, &sa, &len ) == -1 ) {
+ if ( getpeername( sd, sa, &len ) == -1 ) {
return( NULL );
}
@@ -506,19 +512,19 @@
* hostname is used as the kerberos instance.
*/
- switch (sa.sa_family) {
+ switch (sa->sa_family) {
#ifdef LDAP_PF_LOCAL
case AF_LOCAL:
return LDAP_STRDUP( ldap_int_hostname );
#endif
#ifdef LDAP_PF_INET6
case AF_INET6:
- addr = (char *) &((struct sockaddr_in6 *)&sa)->sin6_addr;
+ addr = (char *) &((struct sockaddr_in6 *)sa)->sin6_addr;
len = sizeof( struct in6_addr );
break;
#endif
case AF_INET:
- addr = (char *) &((struct sockaddr_in *)&sa)->sin_addr;
+ addr = (char *) &((struct sockaddr_in *)sa)->sin_addr;
len = sizeof( struct in_addr );
{
@@ -526,7 +532,7 @@
localhost.sin_addr.s_addr = htonl( INADDR_ANY );
if( memcmp ( &localhost.sin_addr,
- &((struct sockaddr_in *)&sa)->sin_addr,
+ &((struct sockaddr_in *)sa)->sin_addr,
sizeof(localhost.sin_addr) ) == 0 )
{
return LDAP_STRDUP( ldap_int_hostname );
@@ -536,7 +542,7 @@
localhost.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
if( memcmp ( &localhost.sin_addr,
- &((struct sockaddr_in *)&sa)->sin_addr,
+ &((struct sockaddr_in *)sa)->sin_addr,
sizeof(localhost.sin_addr) ) == 0 )
{
return LDAP_STRDUP( ldap_int_hostname );
@@ -552,7 +558,7 @@
host = NULL;
if ((ldap_pvt_gethostbyaddr_a( addr, len,
- sa.sa_family, &he_buf, &ha_buf,
+ sa->sa_family, &he_buf, &ha_buf,
&hp,&local_h_errno ) == 0 ) &&
(hp != NULL) && ( hp->h_name != NULL ) )
{