50f89d
commit 745664bd798ec8fd50438605948eea594179fba1
50f89d
Author: Florian Weimer <fweimer@redhat.com>
50f89d
Date:   Tue Aug 28 13:19:27 2018 +0200
50f89d
50f89d
    nscd: Fix use-after-free in addgetnetgrentX [BZ #23520]
50f89d
    
50f89d
    addinnetgrX may use the heap-allocated buffer, so free the buffer
50f89d
    in this function.
50f89d
50f89d
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
50f89d
index 2b35389cc816c3c8..87059fb28042f0a5 100644
50f89d
--- a/nscd/netgroupcache.c
50f89d
+++ b/nscd/netgroupcache.c
50f89d
@@ -113,7 +113,8 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
50f89d
 static time_t
50f89d
 addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
50f89d
 		 const char *key, uid_t uid, struct hashentry *he,
50f89d
-		 struct datahead *dh, struct dataset **resultp)
50f89d
+		 struct datahead *dh, struct dataset **resultp,
50f89d
+		 void **tofreep)
50f89d
 {
50f89d
   if (__glibc_unlikely (debug_level > 0))
50f89d
     {
50f89d
@@ -139,6 +140,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
50f89d
   size_t group_len = strlen (key) + 1;
50f89d
   struct name_list *first_needed
50f89d
     = alloca (sizeof (struct name_list) + group_len);
50f89d
+  *tofreep = NULL;
50f89d
 
50f89d
   if (netgroup_database == NULL
50f89d
       && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
50f89d
@@ -151,6 +153,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
50f89d
 
50f89d
   memset (&data, '\0', sizeof (data));
50f89d
   buffer = xmalloc (buflen);
50f89d
+  *tofreep = buffer;
50f89d
   first_needed->next = first_needed;
50f89d
   memcpy (first_needed->name, key, group_len);
50f89d
   data.needed_groups = first_needed;
50f89d
@@ -439,8 +442,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
50f89d
     }
50f89d
 
50f89d
  out:
50f89d
-  free (buffer);
50f89d
-
50f89d
   *resultp = dataset;
50f89d
 
50f89d
   return timeout;
50f89d
@@ -477,8 +478,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
50f89d
 							    group, group_len,
50f89d
 							    db, uid);
50f89d
   time_t timeout;
50f89d
+  void *tofree;
50f89d
   if (result != NULL)
50f89d
-    timeout = result->head.timeout;
50f89d
+    {
50f89d
+      timeout = result->head.timeout;
50f89d
+      tofree = NULL;
50f89d
+    }
50f89d
   else
50f89d
     {
50f89d
       request_header req_get =
50f89d
@@ -487,7 +492,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
50f89d
 	  .key_len = group_len
50f89d
 	};
50f89d
       timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
50f89d
-				 &result);
50f89d
+				 &result, &tofree);
50f89d
     }
50f89d
 
50f89d
   struct indataset
50f89d
@@ -560,7 +565,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
50f89d
       ++dh->nreloads;
50f89d
       if (cacheable)
50f89d
         pthread_rwlock_unlock (&db->lock);
50f89d
-      return timeout;
50f89d
+      goto out;
50f89d
     }
50f89d
 
50f89d
   if (he == NULL)
50f89d
@@ -596,17 +601,30 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
50f89d
 	dh->usable = false;
50f89d
     }
50f89d
 
50f89d
+ out:
50f89d
+  free (tofree);
50f89d
   return timeout;
50f89d
 }
50f89d
 
50f89d
 
50f89d
+static time_t
50f89d
+addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
50f89d
+			const char *key, uid_t uid, struct hashentry *he,
50f89d
+			struct datahead *dh)
50f89d
+{
50f89d
+  struct dataset *ignore;
50f89d
+  void *tofree;
50f89d
+  time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
50f89d
+				    &ignore, &tofree);
50f89d
+  free (tofree);
50f89d
+  return timeout;
50f89d
+}
50f89d
+
50f89d
 void
50f89d
 addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
50f89d
 		void *key, uid_t uid)
50f89d
 {
50f89d
-  struct dataset *ignore;
50f89d
-
50f89d
-  addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
50f89d
+  addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL);
50f89d
 }
50f89d
 
50f89d
 
50f89d
@@ -619,10 +637,8 @@ readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
50f89d
       .type = GETNETGRENT,
50f89d
       .key_len = he->len
50f89d
     };
50f89d
-  struct dataset *ignore;
50f89d
-
50f89d
-  return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
50f89d
-			  &ignore);
50f89d
+  return addgetnetgrentX_ignore
50f89d
+    (db, -1, &req, db->data + he->key, he->owner, he, dh);
50f89d
 }
50f89d
 
50f89d