Fix forced loop termination in nscd database lookup.
authorJakub Jelinek <jakub@redhat.com>
Mon, 18 May 2009 17:19:50 +0000 (10:19 -0700)
committerUlrich Drepper <drepper@redhat.com>
Mon, 18 May 2009 17:19:50 +0000 (10:19 -0700)
There are two issues with the forced loop exit in the nscd lookup:
1. the estimate of the entry size isn't pessimistic enough for all
   databases, resulting potentially is too early exits
2. the combination of 64-bit process and 32-bit nscd would lead to
   rejecting valid records in the database.

ChangeLog
nscd/nscd_helper.c

index 04c04ba..dfe26cf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-05-18  Jakub Jelinek  <jakub@redhat.com>
+           Ulrich Drepper  <drepper@redhat.com>
+
+       * nscd/nscd_helper.c (MINIMUM_HASHENTRY_SIZE): Define.
+       (__nscd_cache_search): Assume each entry in the
+       hash chain needs one hashentry and half of datahead.  Use
+       MINIMUM_HASHENTRY_SIZE instead of sizeof(hashentry).
+
 2009-05-16  Ulrich Drepper  <drepper@redhat.com>
 
        * posix/sys/wait.h: Fix typos.  Pretty printing.
index c09f008..fe63f9a 100644 (file)
@@ -468,6 +468,15 @@ __nscd_get_map_ref (request_type type, const char *name,
 }
 
 
+/* Using sizeof (hashentry) is not always correct to determine the size of
+   the data structure as found in the nscd cache.  The program could be
+   a 64-bit process and nscd could be a 32-bit process.  In this case
+   sizeof (hashentry) would overestimate the size.  The following is
+   the minimum size of such an entry, good enough for our tests here.  */
+#define MINIMUM_HASHENTRY_SIZE \
+  (offsetof (struct hashentry, dellist) + sizeof (int32_t))
+
+
 /* Don't return const struct datahead *, as eventhough the record
    is normally constant, it can change arbitrarily during nscd
    garbage collection.  */
@@ -481,10 +490,11 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
   ref_t trail = mapped->head->array[hash];
   trail = atomic_forced_read (trail);
   ref_t work = trail;
-  size_t loop_cnt = datasize / (offsetof (struct datahead, data) + datalen);
+  size_t loop_cnt = datasize / (MINIMUM_HASHENTRY_SIZE
+                               + offsetof (struct datahead, data) / 2);
   int tick = 0;
 
-  while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
+  while (work != ENDREF && work + MINIMUM_HASHENTRY_SIZE <= datasize)
     {
       struct hashentry *here = (struct hashentry *) (mapped->data + work);
       ref_t here_key, here_packet;
@@ -541,7 +551,7 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
            return NULL;
 #endif
 
-         if (trail + sizeof (struct hashentry) > datasize)
+         if (trail + MINIMUM_HASHENTRY_SIZE > datasize)
            return NULL;
 
          trail = atomic_forced_read (trailelem->next);