[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#208428: Solution for this bug [PATCH]



Hello,
=-==-=

This bug is caused by a forgotten ERANGE value in the errno variable.

More precisely, if internal_getgrnam_r() in nis/nss_compat/compat-grp.c
finds a line in the /etc/group that doesn't fit into current buffer it sets
the errno to ERANGE in order to tell the wrapper functions that the buffer
is too small to hold the entire line (see the compat-grp.c at the line 396).
This value is checked in the nss/getXXbyYY.c file at the line 124, and
subsequently, the buffer size is increased and the internal_getgrnam_r() is
called again. This cycle might repeat itself several times until the buffer
is long enough to hold the entire line.

However, once the errno has been set to ERANGE, the internal_getgrnam_r()
won't change it to any other value, nor it will reset it. No matter whether
the group lookup will be succesful or not, the errno will stay initialized
to ERANGE, and the test in the nss/getXXbyYY.c will loop forever, increasing
the buffer size along. As a result of this neverending loop, the memory is
quickly exhausted.

In glibc 2.2.x the errno was thoroughly set to ENOENT whenever some NSS
function returned NSS_STATUS_NOTFOUND. However, according to ChangeLog.13,
these lines were removed from various files (see the "2002-08-25" date) in
the glibc 2.3.x. Unfortunately, exactly these changes created this bug.

This bug is obviously not specific to getgrnam(), but rather it can appear
in every NSS lookup function. It is triggered by processing an entry that is
initially longer than 1023 bytes.

I have corrected this behavior in nis/nss_compat/*.c. I have changed the
errno to ENOENT in these files at the places where these both conditions
were met:

1.) The function was about to return the NSS_STATUS_NOTFOUND value
2.) The errno value was obviously not changed by any other function during
    the process

However, there are many more files that need similar changes. I have not
tampered with them yet. The complete listing can be obtained from the
ChangeLog.13 file.

Still, I am just a newbie in glibc code and it could happen that I have set
the errno inappropriately at some places. Therefore I suggest a thorough
review of my changes, and I myself treat this solution rather as a
workaround until it is acknowledged by someone more familiar with the glibc
code. On the other hand, it works for me just fine.

The attached dpatch file can be used immediately in the building process of
Debian libc6 packages, provided its name is mentioned in
debian/patches/0list file _after_ the 10_cvs line.

Hopefully this will be useful to you.

Regards,
Peter
#!/bin/sh -e
## 91_errno-enoent-nss-compat.dpatch
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.

if [ $# -ne 1 ]; then
    echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
    exit 1
fi

[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
patch_opts="${patch_opts:--f --no-backup-if-mismatch}"

case "$1" in
       -patch) patch $patch_opts -p1 < $0;;
       -unpatch) patch $patch_opts -p1 -R < $0;;
        *)
                echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
                exit 1;;
esac

exit 0

@DPATCH@
diff -urNad /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-grp.c glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-grp.c
--- /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-grp.c	2003-10-07 00:44:40.000000000 +0200
+++ glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-grp.c	2003-10-07 01:25:28.000000000 +0200
@@ -257,7 +257,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
@@ -388,7 +391,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
@@ -431,7 +437,10 @@
       if (result->gr_name[0] == '-' && result->gr_name[1] != '\0')
 	{
 	  if (strcmp (&result->gr_name[1], name) == 0)
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 	  else
 	    continue;
 	}
@@ -515,7 +524,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
diff -urNad /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-initgroups.c glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-initgroups.c
--- /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-initgroups.c	2003-10-07 00:44:40.000000000 +0200
+++ glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-initgroups.c	2003-10-07 00:54:55.000000000 +0200
@@ -322,7 +322,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
diff -urNad /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-pwd.c glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-pwd.c
--- /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-pwd.c	2003-10-07 00:44:40.000000000 +0200
+++ glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-pwd.c	2003-10-07 01:23:59.000000000 +0200
@@ -503,7 +503,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
@@ -699,8 +702,10 @@
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
 	    {
+	      *errnop = ENOENT;
 	      return NSS_STATUS_NOTFOUND;
 	    }
+	    
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
 	      fsetpos (ent->stream, &pos);
@@ -743,7 +748,10 @@
 	  && result->pw_name[2] != '\0')
 	{
 	  if (innetgr (&result->pw_name[2], NULL, name, NULL))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 	  continue;
 	}
 
@@ -771,7 +779,10 @@
 	  && result->pw_name[1] != '@')
 	{
 	  if (strcmp (&result->pw_name[1], name) == 0)
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 	  else
 	    continue;
 	}
@@ -901,7 +912,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
diff -urNad /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-spwd.c glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-spwd.c
--- /root/libc/prac/glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-spwd.c	2003-10-07 00:44:41.000000000 +0200
+++ glibc-2.3.2/glibc-2.3.2/nis/nss_compat/compat-spwd.c	2003-10-07 01:24:48.000000000 +0200
@@ -455,7 +455,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
@@ -647,7 +650,10 @@
 	  buffer[buflen - 1] = '\xff';
 	  p = fgets_unlocked (buffer, buflen, ent->stream);
 	  if (p == NULL && feof_unlocked (ent->stream))
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 
 	  if (p == NULL || buffer[buflen - 1] != '\xff')
 	    {
@@ -693,7 +699,10 @@
 	  && result->sp_namp[2] != '\0')
 	{
 	  if (innetgr (&result->sp_namp[2], NULL, name, NULL))
-            return NSS_STATUS_NOTFOUND;
+	    {
+	       *errnop = ENOENT;
+              return NSS_STATUS_NOTFOUND;
+            }
 	  continue;
 	}
 
@@ -721,7 +730,10 @@
 	  && result->sp_namp[1] != '@')
 	{
 	  if (strcmp (&result->sp_namp[1], name) == 0)
-	    return NSS_STATUS_NOTFOUND;
+	    {
+	      *errnop = ENOENT;
+	      return NSS_STATUS_NOTFOUND;
+	    }
 	  else
 	    continue;
 	}

Reply to: