summary refs log tree commit diff
path: root/nscd/nscd_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'nscd/nscd_helper.c')
-rw-r--r--nscd/nscd_helper.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index 7c45981586..71ea53e19d 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1998-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2002,2003,2004,2005,2006,2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -21,6 +22,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
+#include <string.h>
 #include <time.h>
 #include <unistd.h>
 #include <sys/mman.h>
@@ -186,6 +188,7 @@ get_mapping (request_type type, const char *key,
     request_header req;
     char key[keylen];
   } reqdata;
+  size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
 
   int sock = open_socket ();
   if (sock < 0)
@@ -200,9 +203,9 @@ get_mapping (request_type type, const char *key,
 #  define MSG_NOSIGNAL 0
 # endif
   if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock, &reqdata,
-						    sizeof (reqdata),
+						    real_sizeof_reqdata,
 						    MSG_NOSIGNAL))
-			!= sizeof (reqdata), 0))
+			!= real_sizeof_reqdata, 0))
     /* We cannot even write the request.  */
     goto out_close2;
 
@@ -240,11 +243,12 @@ get_mapping (request_type type, const char *key,
 			!= keylen, 0))
     goto out_close2;
 
-  mapfd = *(int *) CMSG_DATA (cmsg);
+  if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
+			|| (CMSG_FIRSTHDR (&msg)->cmsg_len
+			    != CMSG_LEN (sizeof (int))), 0))
+    goto out_close2;
 
-  if (__builtin_expect (CMSG_FIRSTHDR (&msg)->cmsg_len
-			!= CMSG_LEN (sizeof (int)), 0))
-    goto out_close;
+  mapfd = *(int *) CMSG_DATA (cmsg);
 
   struct stat64 st;
   if (__builtin_expect (strcmp (resdata, key) != 0, 0)
@@ -362,7 +366,10 @@ __nscd_get_map_ref (request_type type, const char *name,
 }
 
 
-const struct datahead *
+/* Don't return const struct datahead *, as eventhough the record
+   is normally constant, it can change arbitrarily during nscd
+   garbage collection.  */
+struct datahead *
 __nscd_cache_search (request_type type, const char *key, size_t keylen,
 		     const struct mapped_database *mapped)
 {
@@ -374,16 +381,32 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
     {
       struct hashentry *here = (struct hashentry *) (mapped->data + work);
 
+#ifndef _STRING_ARCH_unaligned
+      /* Although during garbage collection when moving struct hashentry
+	 records around we first copy from old to new location and then
+	 adjust pointer from previous hashentry to it, there is no barrier
+	 between those memory writes.  It is very unlikely to hit it,
+	 so check alignment only if a misaligned load can crash the
+	 application.  */
+      if ((uintptr_t) here & (__alignof__ (*here) - 1))
+	return NULL;
+#endif
+
       if (type == here->type
 	  && keylen == here->len
-	  && here->key + here->len <= datasize
+	  && here->key + keylen <= datasize
 	  && memcmp (key, mapped->data + here->key, keylen) == 0
 	  && here->packet + sizeof (struct datahead) <= datasize)
 	{
 	  /* We found the entry.  Increment the appropriate counter.  */
-	  const struct datahead *dh
+	  struct datahead *dh
 	    = (struct datahead *) (mapped->data + here->packet);
 
+#ifndef _STRING_ARCH_unaligned
+	  if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
+	    return NULL;
+#endif
+
 	  /* 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)