--- Begin Message ---
- To: Debian Bug Tracking System <submit@bugs.debian.org>
- Subject: nss-updatedb: increases buffer size for retries too freely
- From: Stephen Gran <sgran@debian.org>
- Date: Mon, 3 Sep 2007 23:44:44 +0000
- Message-id: <20070903234444.GA18913@alioth.debian.org>
Package: nss-updatedb
Version: 7-1.1
Severity: normal
Doing a fair amount of debugging this weekend with nss-pgsql, I
discovered that nss_updatedb was returning information in situations
where the c library didn't. It turns out that this is because the try
again code in updatedb.c does not also evaluate errno to check for
ERANGE, and the c library code does. This is the (apparently) the only
time you are supposed to increase the buffer size, as I read the
behavior - otherwise you are supposed to just retry once and move on.
This isn't a hugely important thing, as you can imagine (being too
liberal with memory allocation won't kill most modern hardware), but it
would be good to have the various implementations match in their
behavior. Also, this bug masked a fairly difficult bug to track down
with nss-pgsql's errno handling (it was getting overwritten before being
returned to the caller) and since nss_updatedb never checks errno, it
would work for nss_updatedb, but not for the c library routines. Very
confusing, and I'd like to save the next poor soul some time :)
Unfortunately, this does involve some rather tedious code to save how
many times you've been around the loop for this particular check, so I
don't have a patch to hand for you, but effectively, it's:
int ent;
tryagain:
do {
status = vtable->getent((void *)&result, buffer, buflen, &errnop);
if (status != NSS_STATUS_SUCCESS) {
break;
}
status = callback(handle, (void *)&result, private);
} while (status == NSS_STATUS_SUCCESS);
if (status == NSS_STATUS_TRYAGAIN) {
if (*errnop == ERANGE) {
buflen *= 2;
buffer = realloc(buffer, buflen);
if (buffer == NULL) {
vtable->endent();
return NSS_STATUS_TRYAGAIN;
}
status = NSS_STATUS_SUCCESS; /* enter the loop again */
goto tryagain;
} else {
// need to figure out how to do this check neatly
// it needs to be uid for passwd structs, but
// gid for group structs.
if (ent == result->uid) {
return NSS_STATUS_TRYAGAIN;
}
ent = result->uid;
status = NSS_STATUS_SUCCESS; /* enter the loop again */
goto tryagain;
}
}
Obviously, you can't just check for uid in the result struct, you'll need
to determine what kind of struct it is and look up the right bit and that
sort of thing (unless you come up with something better than my first
idea). Hence no real patch, sorry.
Thanks,
-- System Information:
Debian Release: 4.0
APT prefers stable
APT policy: (500, 'stable')
Architecture: amd64 (x86_64)
Shell: /bin/sh linked to /bin/bash
Kernel: Linux 2.6.18-4-xen-amd64
Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8) (ignored: LC_ALL set to en_US.utf8)
Versions of packages nss-updatedb depends on:
ii libc6 2.3.6.ds1-13etch3 GNU C Library: Shared libraries
ii libdb4.3 4.3.29-8 Berkeley v4.3 Database Libraries [
Versions of packages nss-updatedb recommends:
ii libnss-db 2.2.3pre1-2 NSS module for using Berkeley Data
-- no debconf information
--- End Message ---