As discussed in the respective bug logs, I'm working on a 2:3.2.5-4 release with the atatched patches and the following changelog:
samba (2:3.2.5-4) unstable; urgency=low * Fix segfault whan accessign some NAS devices running old versions of Samba Closes: #500129 * Fix process crush when using gethostbyname_r in several threads Closes: #509101, #510450 -- Christian Perrier <bubu...@debian.org> Thu, 08 Jan 2009 05:59:17 +0100 (yeah, I spotted the typo..:-)) I intend to make them available somewhere, ask the bug submitters to test them (CC'ing the corresponding bugs in Launchpad as maybe some Ubuntu users could test the packages as well). If everything is OK, I'll propose updating the packages.....hopefully on time before the hard freeze. Release team, in case all this process takes too much time and we miss the hard hard freeze by some days (this depends on D-I RC2, more or less), would you be OK to consider unblocking that samba version anyway (after all, we're taking care to test things properly before blindly uploading something for lenny....)?
Goal: Fix segfault whan accessign some NAS devices running old versions of Samba Fixes: #500129 Status wrt upstream: Fixed in 3.2.6 Author: Kai Blin <k...@samba.org> and Volker Lendecke <v...@samba.org> Note: This bug was a regression in Samba 3.2 and may affect etch->lenny upgrades, introducing regressions. See also Launchpad bug #264943 (Ubuntu Hardy->Intrepid regression) Index: samba-3.2.5/source/lib/system.c =================================================================== --- samba-3.2.5.orig/source/lib/system.c +++ samba-3.2.5/source/lib/system.c @@ -142,6 +142,20 @@ } /******************************************************************* +A writev wrapper that will deal with EINTR. +********************************************************************/ + +ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t ret; + + do { + ret = writev(fd, iov, iovcnt); + } while (ret == -1 && errno == EINTR); + return ret; +} + +/******************************************************************* A pread wrapper that will deal with EINTR and 64-bit file offsets. ********************************************************************/ Index: samba-3.2.5/source/lib/util_sock.c =================================================================== --- samba-3.2.5.orig/source/lib/util_sock.c +++ samba-3.2.5/source/lib/util_sock.c @@ -1037,40 +1037,109 @@ } /**************************************************************************** - Write data to a fd. + Write all data from an iov array ****************************************************************************/ -ssize_t write_data(int fd, const char *buffer, size_t N) +ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) { - size_t total=0; - ssize_t ret; - char addr[INET6_ADDRSTRLEN]; + int i; + size_t to_send; + ssize_t thistime; + size_t sent; + struct iovec *iov_copy, *iov; + + to_send = 0; + for (i=0; i<iovcnt; i++) { + to_send += orig_iov[i].iov_len; + } + + thistime = sys_writev(fd, orig_iov, iovcnt); + if ((thistime <= 0) || (thistime == to_send)) { + return thistime; + } + sent = thistime; - while (total < N) { - ret = sys_write(fd,buffer + total,N - total); + /* + * We could not send everything in one call. Make a copy of iov that + * we can mess with. We keep a copy of the array start in iov_copy for + * the TALLOC_FREE, because we're going to modify iov later on, + * discarding elements. + */ - if (ret == -1) { - if (fd == get_client_fd()) { - /* Try and give an error message saying - * what client failed. */ - DEBUG(0,("write_data: write failure in " - "writing to client %s. Error %s\n", - get_peer_addr(fd,addr,sizeof(addr)), - strerror(errno) )); - } else { - DEBUG(0,("write_data: write failure. " - "Error = %s\n", strerror(errno) )); + iov_copy = (struct iovec *)TALLOC_MEMDUP( + talloc_tos(), orig_iov, sizeof(struct iovec) * iovcnt); + + if (iov_copy == NULL) { + errno = ENOMEM; + return -1; + } + iov = iov_copy; + + while (sent < to_send) { + /* + * We have to discard "thistime" bytes from the beginning + * iov array, "thistime" contains the number of bytes sent + * via writev last. + */ + while (thistime > 0) { + if (thistime < iov[0].iov_len) { + char *new_base = + (char *)iov[0].iov_base + thistime; + iov[0].iov_base = new_base; + iov[0].iov_len -= thistime; + break; } - return -1; + thistime -= iov[0].iov_len; + iov += 1; + iovcnt -= 1; } - if (ret == 0) { - return total; + thistime = sys_writev(fd, iov, iovcnt); + if (thistime <= 0) { + break; } + sent += thistime; + } + + TALLOC_FREE(iov_copy); + return sent; +} - total += ret; +/**************************************************************************** + Write data to a fd. +****************************************************************************/ + +/**************************************************************************** + Write data to a fd. +****************************************************************************/ + +ssize_t write_data(int fd, const char *buffer, size_t N) +{ + ssize_t ret; + struct iovec iov; + + iov.iov_base = CONST_DISCARD(char *, buffer); + iov.iov_len = N; + + ret = write_data_iov(fd, &iov, 1); + if (ret >= 0) { + return ret; + } + + if (fd == get_client_fd()) { + char addr[INET6_ADDRSTRLEN]; + /* + * Try and give an error message saying what client failed. + */ + DEBUG(0, ("write_data: write failure in writing to client %s. " + "Error %s\n", get_peer_addr(fd,addr,sizeof(addr)), + strerror(errno))); + } else { + DEBUG(0,("write_data: write failure. Error = %s\n", + strerror(errno) )); } - return (ssize_t)total; + + return -1; } /**************************************************************************** Index: samba-3.2.5/source/libsmb/clientgen.c =================================================================== --- samba-3.2.5.orig/source/libsmb/clientgen.c +++ samba-3.2.5/source/libsmb/clientgen.c @@ -315,7 +315,7 @@ /* First length to send is the offset to the data. */ size_t len = SVAL(cli->outbuf,smb_vwv11) + 4; size_t nwritten=0; - ssize_t ret; + struct iovec iov[2]; /* fd == -1 causes segfaults -- Tom (t...@ninja.nl) */ if (cli->fd == -1) { @@ -327,33 +327,19 @@ return false; } - while (nwritten < len) { - ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten); - if (ret <= 0) { - close(cli->fd); - cli->fd = -1; - cli->smb_rw_error = SMB_WRITE_ERROR; - DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", - (int)len,(int)ret, strerror(errno) )); - return false; - } - nwritten += ret; - } + iov[0].iov_base = cli->outbuf; + iov[0].iov_len = len; + iov[1].iov_base = CONST_DISCARD(char *, p); + iov[1].iov_len = extradata; - /* Now write the extra data. */ - nwritten=0; - while (nwritten < extradata) { - ret = write_socket(cli->fd,p+nwritten,extradata - nwritten); - if (ret <= 0) { - close(cli->fd); - cli->fd = -1; - cli->smb_rw_error = SMB_WRITE_ERROR; - DEBUG(0,("Error writing %d extradata " - "bytes to client. %d (%s)\n", - (int)extradata,(int)ret, strerror(errno) )); - return false; - } - nwritten += ret; + nwritten = write_data_iov(cli->fd, iov, 2); + if (nwritten < (len + extradata)) { + close(cli->fd); + cli->fd = -1; + cli->smb_rw_error = SMB_WRITE_ERROR; + DEBUG(0,("Error writing %d bytes to client. (%s)\n", + (int)(len+extradata), strerror(errno))); + return false; } /* Increment the mid so we can tell between responses. */ Index: samba-3.2.5/source/libsmb/clilist.c =================================================================== --- samba-3.2.5.orig/source/libsmb/clilist.c +++ samba-3.2.5/source/libsmb/clilist.c @@ -79,16 +79,17 @@ p += 27; p += clistr_align_in(cli, p, 0); - /* We can safely use +1 here (which is required by OS/2) - * instead of +2 as the STR_TERMINATE flag below is + /* We can safely use len here (which is required by OS/2) + * and the NAS-BASIC server instead of +2 or +1 as the + * STR_TERMINATE flag below is * actually used as the length calculation. - * The len+2 is merely an upper bound. + * The len is merely an upper bound. * Due to the explicit 2 byte null termination * in cli_receive_trans/cli_receive_nt_trans * we know this is safe. JRA + kukks */ - if (p + len + 1 > pdata_end) { + if (p + len > pdata_end) { return pdata_end - base; }
Goal: Fix process crush when using gethostbyname_r in several threads Fixes: #509101, #510450 Status wrt upstream: Fixed in 3.2.6 Author: Jeremy Allison <j...@samba.org> Note: This bug induces web browser crashes (see #510450) and is a regression for many desktop users in etch->lenny upgrades Index: samba-3.2.5/source/nsswitch/wins.c =================================================================== --- samba-3.2.5.orig/source/nsswitch/wins.c +++ samba-3.2.5/source/nsswitch/wins.c @@ -25,6 +25,14 @@ #include <ns_daemon.h> #endif +#if HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#if HAVE_PTHREAD +static pthread_mutex_t wins_nss_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + #ifndef INADDRSZ #define INADDRSZ 4 #endif @@ -321,11 +329,16 @@ _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he, char *buffer, size_t buflen, int *h_errnop) { + NSS_STATUS nss_status = NSS_STATUS_SUCCESS; struct in_addr *ip_list; int i, count; fstring name; size_t namelen; +#if HAVE_PTHREAD + pthread_mutex_lock(&wins_nss_mutex); +#endif + memset(he, '\0', sizeof(*he)); fstrcpy(name, hostname); @@ -333,8 +346,10 @@ ip_list = lookup_byname_backend(name, &count); - if (!ip_list) - return NSS_STATUS_NOTFOUND; + if (!ip_list) { + nss_status = NSS_STATUS_NOTFOUND; + goto out; + } /* Copy h_name */ @@ -342,7 +357,8 @@ if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) { free(ip_list); - return NSS_STATUS_TRYAGAIN; + nss_status = NSS_STATUS_TRYAGAIN; + goto out; } memcpy(he->h_name, name, namelen); @@ -354,20 +370,23 @@ if (get_static(&buffer, &buflen, i) == NULL) { free(ip_list); - return NSS_STATUS_TRYAGAIN; + nss_status = NSS_STATUS_TRYAGAIN; + goto out; } if ((he->h_addr_list = (char **)get_static( &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL) { free(ip_list); - return NSS_STATUS_TRYAGAIN; + nss_status = NSS_STATUS_TRYAGAIN; + goto out; } for (i = 0; i < count; i++) { if ((he->h_addr_list[i] = get_static(&buffer, &buflen, INADDRSZ)) == NULL) { free(ip_list); - return NSS_STATUS_TRYAGAIN; + nss_status = NSS_STATUS_TRYAGAIN; + goto out; } memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ); } @@ -386,16 +405,27 @@ if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0) i = sizeof(char*) - i; - if (get_static(&buffer, &buflen, i) == NULL) - return NSS_STATUS_TRYAGAIN; + if (get_static(&buffer, &buflen, i) == NULL) { + nss_status = NSS_STATUS_TRYAGAIN; + goto out; + } if ((he->h_aliases = (char **)get_static( - &buffer, &buflen, sizeof(char *))) == NULL) - return NSS_STATUS_TRYAGAIN; + &buffer, &buflen, sizeof(char *))) == NULL) { + nss_status = NSS_STATUS_TRYAGAIN; + goto out; + } he->h_aliases[0] = NULL; - return NSS_STATUS_SUCCESS; + nss_status = NSS_STATUS_SUCCESS; + + out: + +#if HAVE_PTHREAD + pthread_mutex_unlock(&wins_nss_mutex); +#endif + return nss_status; } @@ -403,12 +433,15 @@ _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer, size_t buflen, int *h_errnop) { + NSS_STATUS nss_status; + if(af!=AF_INET) { *h_errnop = NO_DATA; - return NSS_STATUS_UNAVAIL; + nss_status = NSS_STATUS_UNAVAIL; + } else { + nss_status = _nss_wins_gethostbyname_r( + name, he, buffer, buflen, h_errnop); } - - return _nss_wins_gethostbyname_r( - name, he, buffer, buflen, h_errnop); + return nss_status; } #endif
signature.asc
Description: Digital signature