mirror of
https://sourceware.org/git/glibc.git
synced 2026-10-28 10:25:13 +08:00
CVE-2026-89092: nscd: replace alloca with malloc in aicache, hstcache
This changes the alloca fallback to a malloc fallback in the addrinfo and host cache code. This fixes bug 34624. Co-authored-by: Florian Weimer <fweimer@redhat.com> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
1 parent
60b925c18f
commit
cbf59b8366
2 files changed
+52
-22
No files matched your search
+18
-9
@@ -102,7 +102,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
int32_t ttl = INT32_MAX;
|
||||
ssize_t total = 0;
|
||||
char *key_copy = NULL;
|
||||
bool alloca_used = false;
|
||||
/* If not NULL, dataset is a temporary dataset not inserted into the
|
||||
database, and needs to be free'd. */
|
||||
void *dataset_alloc = NULL;
|
||||
time_t timeout = MAX_TIMEOUT_VALUE;
|
||||
|
||||
while (!no_more)
|
||||
@@ -173,10 +175,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
/* We cannot permanently add the result in the moment. But
|
||||
we can provide the result as is. Store the data in some
|
||||
temporary memory. */
|
||||
dataset = (struct dataset *) alloca (total + req->key_len);
|
||||
dataset = (struct dataset *) malloc (total + req->key_len);
|
||||
if (dataset == NULL)
|
||||
goto out;
|
||||
|
||||
/* We cannot add this record to the permanent database. */
|
||||
alloca_used = true;
|
||||
dataset_alloc = dataset;
|
||||
}
|
||||
|
||||
/* Fill in the address and address families. */
|
||||
@@ -345,10 +349,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
/* We cannot permanently add the result in the moment. But
|
||||
we can provide the result as is. Store the data in some
|
||||
temporary memory. */
|
||||
dataset = (struct dataset *) alloca (total + req->key_len);
|
||||
dataset = (struct dataset *) malloc (total + req->key_len);
|
||||
if (dataset == NULL)
|
||||
goto out;
|
||||
|
||||
/* We cannot add this record to the permanent database. */
|
||||
alloca_used = true;
|
||||
dataset_alloc = dataset;
|
||||
}
|
||||
|
||||
/* Fill in the address and address families. */
|
||||
@@ -400,8 +406,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
resp)) == 0)
|
||||
{
|
||||
/* The data has not changed. We will just bump the
|
||||
timeout value. Note that the new record has been
|
||||
allocated on the stack and need not be freed. */
|
||||
timeout value. */
|
||||
dh->timeout = dataset->head.timeout;
|
||||
dh->ttl = dataset->head.ttl;
|
||||
++dh->nreloads;
|
||||
@@ -419,7 +424,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
key_copy = (char *) newp + (key_copy - (char *) dataset);
|
||||
|
||||
dataset = memcpy (newp, dataset, total + req->key_len);
|
||||
alloca_used = false;
|
||||
|
||||
free (dataset_alloc);
|
||||
dataset_alloc = NULL;
|
||||
}
|
||||
|
||||
/* Mark the old record as obsolete. */
|
||||
@@ -502,7 +509,7 @@ next_nip:
|
||||
out:
|
||||
__resolv_context_put (ctx);
|
||||
|
||||
if (dataset != NULL && !alloca_used)
|
||||
if (dataset != NULL && dataset_alloc == NULL)
|
||||
{
|
||||
/* If necessary, we also propagate the data to disk. */
|
||||
if (db->persistent)
|
||||
@@ -528,6 +535,8 @@ next_nip:
|
||||
scratch_buffer_free (&tmpbuf4);
|
||||
scratch_buffer_free (&canonbuf);
|
||||
|
||||
free (dataset_alloc);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
|
||||
+34
-13
@@ -15,7 +15,6 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <alloca.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
@@ -188,7 +187,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
/* Determine the I/O structure. */
|
||||
size_t h_name_len = strlen (hst->h_name) + 1;
|
||||
size_t h_aliases_cnt;
|
||||
uint32_t *h_aliases_len;
|
||||
uint32_t *h_aliases_len = NULL;
|
||||
size_t h_addr_list_cnt;
|
||||
char *addresses;
|
||||
char *aliases;
|
||||
@@ -202,7 +201,13 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
|
||||
++h_aliases_cnt;
|
||||
/* Determine the length of all aliases. */
|
||||
h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
|
||||
if (h_aliases_cnt > 0)
|
||||
{
|
||||
h_aliases_len = (uint32_t *) reallocarray (NULL, h_aliases_cnt,
|
||||
sizeof (uint32_t));
|
||||
if (h_aliases_len == NULL)
|
||||
return MAX_TIMEOUT_VALUE;
|
||||
}
|
||||
total = 0;
|
||||
for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
|
||||
{
|
||||
@@ -216,8 +221,11 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
++h_addr_list_cnt;
|
||||
|
||||
if (h_addr_list_cnt == 0)
|
||||
/* Invalid entry. */
|
||||
return MAX_TIMEOUT_VALUE;
|
||||
{
|
||||
/* Invalid entry. */
|
||||
free (h_aliases_len);
|
||||
return MAX_TIMEOUT_VALUE;
|
||||
}
|
||||
|
||||
total += (sizeof (struct dataset)
|
||||
+ h_name_len
|
||||
@@ -228,8 +236,10 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
change. Allocate memory on the cache since it is likely
|
||||
discarded anyway. If it turns out to be necessary to have a
|
||||
new record we can still allocate real memory. */
|
||||
bool alloca_used = false;
|
||||
dataset = NULL;
|
||||
/* If not NULL, dataset is a temporary dataset not inserted into
|
||||
the database, and needs to be free'd. */
|
||||
void *dataset_alloc = NULL;
|
||||
|
||||
/* If the record contains more than one IP address (used for
|
||||
load balancing etc) don't cache the entry. This is something
|
||||
@@ -245,10 +255,15 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
/* We cannot permanently add the result in the moment. But
|
||||
we can provide the result as is. Store the data in some
|
||||
temporary memory. */
|
||||
dataset = (struct dataset *) alloca (total + req->key_len);
|
||||
dataset = (struct dataset *) malloc (total + req->key_len);
|
||||
if (dataset == NULL)
|
||||
{
|
||||
free (h_aliases_len);
|
||||
return MAX_TIMEOUT_VALUE;
|
||||
}
|
||||
|
||||
/* We cannot add this record to the permanent database. */
|
||||
alloca_used = true;
|
||||
dataset_alloc = dataset;
|
||||
}
|
||||
|
||||
timeout = datahead_init_pos (&dataset->head, total + req->key_len,
|
||||
@@ -271,7 +286,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
cp = dataset->strdata;
|
||||
|
||||
cp = mempcpy (cp, hst->h_name, h_name_len);
|
||||
cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
|
||||
if (h_aliases_cnt > 0)
|
||||
cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
|
||||
|
||||
/* The normal addresses first. */
|
||||
addresses = cp;
|
||||
@@ -283,6 +299,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
|
||||
cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
|
||||
|
||||
free (h_aliases_len);
|
||||
|
||||
assert (cp
|
||||
== dataset->strdata + total - offsetof (struct dataset,
|
||||
strdata));
|
||||
@@ -308,8 +326,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
dh->allocsize - offsetof (struct dataset, resp)) == 0)
|
||||
{
|
||||
/* The data has not changed. We will just bump the
|
||||
timeout value. Note that the new record has been
|
||||
allocated on the stack and need not be freed. */
|
||||
timeout value. */
|
||||
assert (h_addr_list_cnt == 1);
|
||||
dh->ttl = dataset->head.ttl;
|
||||
dh->timeout = dataset->head.timeout;
|
||||
@@ -335,7 +352,9 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
key_copy = (char *) newp + (key_copy - (char *) dataset);
|
||||
|
||||
dataset = memcpy (newp, dataset, total + req->key_len);
|
||||
alloca_used = false;
|
||||
|
||||
free (dataset_alloc);
|
||||
dataset_alloc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +382,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
the current cache handling cannot handle and it is more than
|
||||
questionable whether it is worthwhile complicating the cache
|
||||
handling just for handling such a special case. */
|
||||
if (! alloca_used)
|
||||
if (dataset_alloc == NULL)
|
||||
{
|
||||
/* If necessary, we also propagate the data to disk. */
|
||||
if (db->persistent)
|
||||
@@ -394,6 +413,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||
|
||||
pthread_rwlock_unlock (&db->lock);
|
||||
}
|
||||
free (dataset_alloc);
|
||||
dataset_alloc = NULL;
|
||||
}
|
||||
|
||||
if (__builtin_expect (!all_written, 0) && debug_level > 0)
|
||||
|
||||
Reference in new issue
Block a user