]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
nscd: Fix use-after-free in addgetnetgrentX [BZ #23520]
authorFlorian Weimer <fweimer@redhat.com>
Tue, 28 Aug 2018 11:19:27 +0000 (13:19 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 8 Mar 2021 10:12:28 +0000 (10:12 +0000)
addinnetgrX may use the heap-allocated buffer, so free the buffer
in this function.

(cherry picked from commit 745664bd798ec8fd50438605948eea594179fba1)

ChangeLog
NEWS
nscd/netgroupcache.c

index 23b740dc2ee11c56f4523e0e47450313c201d456..2760eee9a6bdfe2bba99492fd38f8129785a7e83 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2018-08-28  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #23520]
+       nscd: Fix use-after-free in addgetnetgrentX and its callers.
+       * nscd/netgroupcache.c
+       (addgetnetgrentX): Add tofreep parameter.  Do not free
+       heap-allocated buffer.
+       (addinnetgrX): Free buffer allocated bt addgetnetgrentX.
+       (addgetnetgrentX_ignore): New function.
+       (addgetnetgrent): Call it.
+       (readdgetnetgrent): Likewise.
+
 2019-02-01  Florian Weimer  <fweimer@redhat.com>
 
        * support/support_test_compare_string.c
diff --git a/NEWS b/NEWS
index f591f150d36ee6b52cb45d50c79c1a838dcddf6f..dff138e8b2e1a42162372f866716fb591032ca97 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -163,6 +163,7 @@ The following bugs are resolved with this release:
   [23363] stdio-common/tst-printf.c has non-free license
   [23456] Wrong index_cpu_LZCNT
   [23459] COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors
+  [23520] nscd: nscd: Use-after-free in addgetnetgrentX and its callers
   [23538] pthread_cond_broadcast: Fix waiters-after-spinning case
   [23562] signal: Use correct type for si_band in siginfo_t
   [23579] libc: Errors misreported in preadv2
index 2f187b208c19cec983f401c03a32344733de254a..3adc5387d6cc87769320e8f2230ac879e20721cf 100644 (file)
@@ -113,7 +113,8 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
 static time_t
 addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
                 const char *key, uid_t uid, struct hashentry *he,
-                struct datahead *dh, struct dataset **resultp)
+                struct datahead *dh, struct dataset **resultp,
+                void **tofreep)
 {
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -139,6 +140,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
   size_t group_len = strlen (key) + 1;
   struct name_list *first_needed
     = alloca (sizeof (struct name_list) + group_len);
+  *tofreep = NULL;
 
   if (netgroup_database == NULL
       && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
@@ -151,6 +153,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 
   memset (&data, '\0', sizeof (data));
   buffer = xmalloc (buflen);
+  *tofreep = buffer;
   first_needed->next = first_needed;
   memcpy (first_needed->name, key, group_len);
   data.needed_groups = first_needed;
@@ -465,8 +468,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     }
 
  out:
-  free (buffer);
-
   *resultp = dataset;
 
   return timeout;
@@ -503,8 +504,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
                                                            group, group_len,
                                                            db, uid);
   time_t timeout;
+  void *tofree;
   if (result != NULL)
-    timeout = result->head.timeout;
+    {
+      timeout = result->head.timeout;
+      tofree = NULL;
+    }
   else
     {
       request_header req_get =
@@ -513,7 +518,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
          .key_len = group_len
        };
       timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
-                                &result);
+                                &result, &tofree);
     }
 
   struct indataset
@@ -586,7 +591,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
       ++dh->nreloads;
       if (cacheable)
         pthread_rwlock_unlock (&db->lock);
-      return timeout;
+      goto out;
     }
 
   if (he == NULL)
@@ -649,17 +654,30 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
        dh->usable = false;
     }
 
+ out:
+  free (tofree);
   return timeout;
 }
 
 
+static time_t
+addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
+                       const char *key, uid_t uid, struct hashentry *he,
+                       struct datahead *dh)
+{
+  struct dataset *ignore;
+  void *tofree;
+  time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
+                                   &ignore, &tofree);
+  free (tofree);
+  return timeout;
+}
+
 void
 addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
                void *key, uid_t uid)
 {
-  struct dataset *ignore;
-
-  addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
+  addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL);
 }
 
 
@@ -672,10 +690,8 @@ readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
       .type = GETNETGRENT,
       .key_len = he->len
     };
-  struct dataset *ignore;
-
-  return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
-                         &ignore);
+  return addgetnetgrentX_ignore
+    (db, -1, &req, db->data + he->key, he->owner, he, dh);
 }