about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2009-05-15 21:17:08 -0700
committerPetr Baudis <pasky@suse.cz>2009-05-22 04:54:50 +0200
commitb9e0df9847f3460c67e27e631af8662e7906ed6b (patch)
tree2b7f681156ce2671b60a1afb60bdbcb11bd43440
parentf27dc66bb946b74df6817768758b1de49d4be887 (diff)
downloadglibc-b9e0df9847f3460c67e27e631af8662e7906ed6b.tar.gz
glibc-b9e0df9847f3460c67e27e631af8662e7906ed6b.tar.xz
glibc-b9e0df9847f3460c67e27e631af8662e7906ed6b.zip
Robustify libc-side nscd database reader.
The nscd database mapped in processes can change at any time.  We
have to be more vigilant when it comes to using that memory.  Test
the data entries are valid in their entire size, don't read data
again from memory once we verified it, and make sure the trailing
pointer is not going off the deep end.
(cherry picked from commit cfe1fc1013d0e7e4863c974fa0e78891cc0a2ed2)
-rw-r--r--ChangeLog25
-rw-r--r--nscd/nscd-client.h5
-rw-r--r--nscd/nscd_getai.c5
-rw-r--r--nscd/nscd_getgr_r.c5
-rw-r--r--nscd/nscd_gethst_r.c6
-rw-r--r--nscd/nscd_getpw_r.c5
-rw-r--r--nscd/nscd_getserv_r.c5
-rw-r--r--nscd/nscd_helper.c27
-rw-r--r--nscd/nscd_initgroups.c5
9 files changed, 60 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index b584ec669d..a672e153bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,16 +1,29 @@
-2009-05-12  Jakub Jelinek  <jakub@redhat.com>
-
-	* include/atomic.h: Formatting.
-	(catomic_compare_and_exchange_val_acq): Don't define if already
-	defined by bits/atomic.h.
-
 2009-05-14  Jakub Jelinek  <jakub@redhat.com>
 
+	* nscd/nscd_helper.c: Include stddef.h.
+	(__nscd_cache_search): Add datalen argument.  Use atomic_forced_read
+	in a couple of places.  Return NULL if trail is not less than
+	datasize, don't consider dataheads with length smaller than
+	offsetof (struct datahead, data) + datalen.
+	* nscd/nscd_client.h (__nscd_cache_search): Adjust prototype.
+	* nscd/nscd_gethst_r.c (nscd_gethst_r): Adjust callers.
+	* nscd/nscd_getpw_r.c (nscd_getpw_r): Likewise.
+	* nscd/nscd_getgr_r.c (nscd_getgr_r): Likewise.
+	* nscd/nscd_getai.c (__nscd_getai): Likewise.
+	* nscd/nscd_initgroups.c (__nscd_getgrouplist): Likewise.
+	* nscd/nscd_getserv_r.c (nscd_getserv_r): Likewise.
+
 	* nscd/selinux.c (nscd_avc_destroy): Removed.
 	* nscd/selinux.h (nscd_avc_destroy): Likewise.
 	* nscd/nscd.c (termination_handler): Don't call
 	nscd_avc_destroy.
 
+2009-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+	* include/atomic.h: Formatting.
+	(catomic_compare_and_exchange_val_acq): Don't define if already
+	defined by bits/atomic.h.
+
 2009-05-10  Ulrich Drepper  <drepper@redhat.com>
 
 	* version.h (VERSION): Bump to 2.10.1.
diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
index 3c9688fd30..f66a658d2a 100644
--- a/nscd/nscd-client.h
+++ b/nscd/nscd-client.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005, 2006, 2007
+/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -329,7 +329,8 @@ static inline int __nscd_drop_map_ref (struct mapped_database *map,
 extern struct datahead *__nscd_cache_search (request_type type,
 					     const char *key,
 					     size_t keylen,
-					     const struct mapped_database *mapped);
+					     const struct mapped_database *mapped,
+					     size_t datalen);
 
 /* Wrappers around read, readv and write that only read/write less than LEN
    bytes on error or EOF.  */
diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c
index 674a5e7514..d1c5cd14e9 100644
--- a/nscd/nscd_getai.c
+++ b/nscd/nscd_getai.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+/* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
 
@@ -75,7 +76,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
   if (mapped != NO_MAPPING)
     {
       struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
-						    mapped);
+						    mapped, sizeof ai_resp);
       if (found != NULL)
 	{
 	  respdata = (char *) (&found->data[0].aidata + 1);
diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
index b84b06b3ce..c2d204c3c8 100644
--- a/nscd/nscd_getgr_r.c
+++ b/nscd/nscd_getgr_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2000, 2002-2005, 2006, 2007
+/* Copyright (C) 1998-2000, 2002-2005, 2006, 2007, 2009
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
@@ -107,7 +107,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
 
   if (mapped != NO_MAPPING)
     {
-      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
+						    sizeof gr_resp);
       if (found != NULL)
 	{
 	  len = (const uint32_t *) (&found->data[0].grdata + 1);
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
index aea8288594..70631fa961 100644
--- a/nscd/nscd_gethst_r.c
+++ b/nscd/nscd_gethst_r.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1998-2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -137,7 +138,8 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
   if (mapped != NO_MAPPING)
     {
       /* No const qualifier, as it can change during garbage collection.  */
-      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
+						    sizeof hst_resp);
       if (found != NULL)
 	{
 	  h_name = (char *) (&found->data[0].hstdata + 1);
diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
index 21f792bb4e..8a4449d186 100644
--- a/nscd/nscd_getpw_r.c
+++ b/nscd/nscd_getpw_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999, 2003, 2004, 2005, 2007
+/* Copyright (C) 1998, 1999, 2003, 2004, 2005, 2007, 2009
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
@@ -104,7 +104,8 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
 
   if (mapped != NO_MAPPING)
     {
-      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
+						    sizeof pw_resp);
       if (found != NULL)
 	{
 	  pw_name = (const char *) (&found->data[0].pwdata + 1);
diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
index b1ad7e2e43..dce4165482 100644
--- a/nscd/nscd_getserv_r.c
+++ b/nscd/nscd_getserv_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2007, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
 
@@ -104,7 +104,8 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
 
   if (mapped != NO_MAPPING)
     {
-      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+      struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
+						    sizeof serv_resp);
 
       if (found != NULL)
 	{
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index cd3fa24196..db247962b9 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
+#include <stddef.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
@@ -472,18 +473,20 @@ __nscd_get_map_ref (request_type type, const char *name,
    garbage collection.  */
 struct datahead *
 __nscd_cache_search (request_type type, const char *key, size_t keylen,
-		     const struct mapped_database *mapped)
+		     const struct mapped_database *mapped, size_t datalen)
 {
   unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
   size_t datasize = mapped->datasize;
 
   ref_t trail = mapped->head->array[hash];
+  trail = atomic_forced_read (trail);
   ref_t work = trail;
   int tick = 0;
 
   while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
     {
       struct hashentry *here = (struct hashentry *) (mapped->data + work);
+      ref_t here_key, here_packet;
 
 #ifndef _STRING_ARCH_unaligned
       /* Although during garbage collection when moving struct hashentry
@@ -498,13 +501,14 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
 
       if (type == here->type
 	  && keylen == here->len
-	  && here->key + keylen <= datasize
-	  && memcmp (key, mapped->data + here->key, keylen) == 0
-	  && here->packet + sizeof (struct datahead) <= datasize)
+	  && (here_key = atomic_forced_read (here->key)) + keylen <= datasize
+	  && memcmp (key, mapped->data + here_key, keylen) == 0
+	  && ((here_packet = atomic_forced_read (here->packet))
+	      + sizeof (struct datahead) <= datasize))
 	{
 	  /* We found the entry.  Increment the appropriate counter.  */
 	  struct datahead *dh
-	    = (struct datahead *) (mapped->data + here->packet);
+	    = (struct datahead *) (mapped->data + here_packet);
 
 #ifndef _STRING_ARCH_unaligned
 	  if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
@@ -513,11 +517,14 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
 
 	  /* See whether we must ignore the entry or whether something
 	     is wrong because garbage collection is in progress.  */
-	  if (dh->usable && here->packet + dh->allocsize <= datasize)
+	  if (dh->usable
+	      && here_packet + dh->allocsize <= datasize
+	      && (here_packet + offsetof (struct datahead, data) + datalen
+		  <= datasize))
 	    return dh;
 	}
 
-      work = here->next;
+      work = atomic_forced_read (here->next);
       /* Prevent endless loops.  This should never happen but perhaps
 	 the database got corrupted, accidentally or deliberately.  */
       if (work == trail)
@@ -532,7 +539,11 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
 	  if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1))
 	    return NULL;
 #endif
-	  trail = trailelem->next;
+
+	  if (trail + sizeof (struct hashentry) > datasize)
+	    return NULL;
+
+	  trail = atomic_forced_read (trailelem->next);
 	}
       tick = 1 - tick;
     }
diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c
index 866455a96c..5ff60c080c 100644
--- a/nscd/nscd_initgroups.c
+++ b/nscd/nscd_initgroups.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
 
@@ -55,7 +55,8 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
   if (mapped != NO_MAPPING)
     {
       struct datahead *found = __nscd_cache_search (INITGROUPS, user,
-						    userlen, mapped);
+						    userlen, mapped,
+						    sizeof initgr_resp);
       if (found != NULL)
 	{
 	  respdata = (char *) (&found->data[0].initgrdata + 1);