Compare commits

..

No commits in common. "056d76b9e4d9684fc97020fd31e389134ec9be6e" and "3bb17c61342a85b5da4e7f661366bce8329ba767" have entirely different histories.

14 changed files with 2 additions and 1471 deletions

View File

@ -1,41 +0,0 @@
From 87801a8fd06db1d654eea3e4f7626ff476a9bdaa Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2024 15:00:45 +0200
Subject: [PATCH] CVE-2024-33599: nscd: Stack-based buffer overflow in netgroup
cache (bug 31677)
Using alloca matches what other caches do. The request length is
bounded by MAXKEYLEN.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflict:NA
Reference:https://sourceware.org/git/?p=glibc.git;a=patch;h=87801a8fd06db1d654eea3e4f7626ff476a9bdaa
---
nscd/netgroupcache.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index 2f71bf29..f13a11b4 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -503,12 +503,13 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
= (struct indataset *) mempool_alloc (db,
sizeof (*dataset) + req->key_len,
1);
- struct indataset dataset_mem;
bool cacheable = true;
if (__glibc_unlikely (dataset == NULL))
{
cacheable = false;
- dataset = &dataset_mem;
+ /* The alloca is safe because nscd_run_worker verfies that
+ key_len is not larger than MAXKEYLEN. */
+ dataset = alloca (sizeof (*dataset) + req->key_len);
}
datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
--
2.33.0

View File

@ -1,63 +0,0 @@
From b048a482f088e53144d26a61c390bed0210f49f2 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2024 15:01:07 +0200
Subject: [PATCH] CVE-2024-33600: nscd: Avoid null pointer crashes after
notfound response (bug 31678)
The addgetnetgrentX call in addinnetgrX may have failed to produce
a result, so the result variable in addinnetgrX can be NULL.
Use db->negtimeout as the fallback value if there is no result data;
the timeout is also overwritten below.
Also avoid sending a second not-found response. (The client
disconnects after receiving the first response, so the data stream did
not go out of sync even without this fix.) It is still beneficial to
add the negative response to the mapping, so that the client can get
it from there in the future, instead of going through the socket.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflict:NA
Reference:https://sourceware.org/git/?p=glibc.git;a=patch;h=b048a482f088e53144d26a61c390bed0210f49f2
---
nscd/netgroupcache.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index 08668e96..5ed16f87 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -512,14 +512,15 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
sizeof (innetgroup_response_header),
- he == NULL ? 0 : dh->nreloads + 1, result->head.ttl);
+ he == NULL ? 0 : dh->nreloads + 1,
+ result == NULL ? db->negtimeout : result->head.ttl);
/* Set the notfound status and timeout based on the result from
getnetgrent. */
- dataset->head.notfound = result->head.notfound;
+ dataset->head.notfound = result == NULL || result->head.notfound;
dataset->head.timeout = timeout;
dataset->resp.version = NSCD_VERSION;
- dataset->resp.found = result->resp.found;
+ dataset->resp.found = result != NULL && result->resp.found;
/* Until we find a matching entry the result is 0. */
dataset->resp.result = 0;
@@ -567,7 +568,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
goto out;
}
- if (he == NULL)
+ /* addgetnetgrentX may have already sent a notfound response. Do
+ not send another one. */
+ if (he == NULL && dataset->resp.found)
{
/* We write the dataset before inserting it to the database
since while inserting this thread might block and so would
--
2.33.0

View File

@ -1,62 +0,0 @@
From 7835b00dbce53c3c87bbbb1754a95fb5e58187aa Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2024 15:01:07 +0200
Subject: [PATCH] CVE-2024-33600: nscd: Do not send missing not-found response
in addgetnetgrentX (bug 31678)
If we failed to add a not-found response to the cache, the dataset
point can be null, resulting in a null pointer dereference.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflict:NA
Reference:https://sourceware.org/git/?p=glibc.git;a=patch;h=7835b00dbce53c3c87bbbb1754a95fb5e58187aa
---
nscd/netgroupcache.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index f13a11b4..08668e96 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -148,7 +148,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
/* No such service. */
cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
&key_copy);
- goto writeout;
+ goto maybe_cache_add;
}
memset (&data, '\0', sizeof (data));
@@ -349,7 +349,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
{
cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
&key_copy);
- goto writeout;
+ goto maybe_cache_add;
}
total = buffilled;
@@ -411,14 +411,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
if (he == NULL && fd != -1)
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily let the receiver wait. */
- writeout:
+ /* We write the dataset before inserting it to the database since
+ while inserting this thread might block and so would
+ unnecessarily let the receiver wait. */
writeall (fd, &dataset->resp, dataset->head.recsize);
- }
+ maybe_cache_add:
if (cacheable)
{
/* If necessary, we also propagate the data to disk. */
--
2.33.0

View File

@ -1,393 +0,0 @@
From c04a21e050d64a1193a6daab872bca2528bda44b Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2024 15:01:07 +0200
Subject: [PATCH] CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two
buffers in addgetnetgrentX (bug 31680)
This avoids potential memory corruption when the underlying NSS
callback function does not use the buffer space to store all strings
(e.g., for constant strings).
Instead of custom buffer management, two scratch buffers are used.
This increases stack usage somewhat.
Scratch buffer allocation failure is handled by return -1
(an invalid timeout value) instead of terminating the process.
This fixes bug 31679.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflict:NA
Reference:https://sourceware.org/git/?p=glibc.git;a=patch;h=c04a21e050d64a1193a6daab872bca2528bda44b
---
nscd/netgroupcache.c | 219 ++++++++++++++++++++++++-------------------
1 file changed, 121 insertions(+), 98 deletions(-)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index 5ed16f87..92c9cb36 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <scratch_buffer.h>
#include "../inet/netgroup.h"
#include "nscd.h"
@@ -66,6 +67,16 @@ struct dataset
char strdata[0];
};
+/* Send a notfound response to FD. Always returns -1 to indicate an
+ ephemeral error. */
+static time_t
+send_notfound (int fd)
+{
+ if (fd != -1)
+ TEMP_FAILURE_RETRY (send (fd, &notfound, sizeof (notfound), MSG_NOSIGNAL));
+ return -1;
+}
+
/* Sends a notfound message and prepares a notfound dataset to write to the
cache. Returns true if there was enough memory to allocate the dataset and
returns the dataset in DATASETP, total bytes to write in TOTALP and the
@@ -84,8 +95,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
total = sizeof (notfound);
timeout = time (NULL) + db->negtimeout;
- if (fd != -1)
- TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
+ send_notfound (fd);
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
/* If we cannot permanently store the result, so be it. */
@@ -110,11 +120,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
return cacheable;
}
+struct addgetnetgrentX_scratch
+{
+ /* This is the result that the caller should use. It can be NULL,
+ point into buffer, or it can be in the cache. */
+ struct dataset *dataset;
+
+ struct scratch_buffer buffer;
+
+ /* Used internally in addgetnetgrentX as a staging area. */
+ struct scratch_buffer tmp;
+
+ /* Number of bytes in buffer that are actually used. */
+ size_t buffer_used;
+};
+
+static void
+addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch)
+{
+ scratch->dataset = NULL;
+ scratch_buffer_init (&scratch->buffer);
+ scratch_buffer_init (&scratch->tmp);
+
+ /* Reserve space for the header. */
+ scratch->buffer_used = sizeof (struct dataset);
+ static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space),
+ "initial buffer space");
+ memset (scratch->tmp.data, 0, sizeof (struct dataset));
+}
+
+static void
+addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch)
+{
+ scratch_buffer_free (&scratch->buffer);
+ scratch_buffer_free (&scratch->tmp);
+}
+
+/* Copy LENGTH bytes from S into SCRATCH. Returns NULL if SCRATCH
+ could not be resized, otherwise a pointer to the copy. */
+static char *
+addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch,
+ const char *s, size_t length)
+{
+ while (true)
+ {
+ size_t remaining = scratch->buffer.length - scratch->buffer_used;
+ if (remaining >= length)
+ break;
+ if (!scratch_buffer_grow_preserve (&scratch->buffer))
+ return NULL;
+ }
+ char *copy = scratch->buffer.data + scratch->buffer_used;
+ memcpy (copy, s, length);
+ scratch->buffer_used += length;
+ return copy;
+}
+
+/* Copy S into SCRATCH, including its null terminator. Returns false
+ if SCRATCH could not be resized. */
+static bool
+addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s)
+{
+ if (s == NULL)
+ s = "";
+ return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL;
+}
+
+/* Caller must initialize and free *SCRATCH. If the return value is
+ negative, this function has sent a notfound response. */
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,
- void **tofreep)
+ struct datahead *dh, struct addgetnetgrentX_scratch *scratch)
{
if (__glibc_unlikely (debug_level > 0))
{
@@ -133,14 +210,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
char *key_copy = NULL;
struct __netgrent data;
- size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
- size_t buffilled = sizeof (*dataset);
- char *buffer = NULL;
size_t nentries = 0;
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_get (nss_database_netgroup, &netgroup_database))
@@ -152,8 +225,6 @@ 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;
@@ -196,8 +267,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
while (1)
{
int e;
- status = getfct.f (&data, buffer + buffilled,
- buflen - buffilled - req->key_len, &e);
+ status = getfct.f (&data, scratch->tmp.data,
+ scratch->tmp.length, &e);
if (status == NSS_STATUS_SUCCESS)
{
if (data.type == triple_val)
@@ -205,68 +276,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
const char *nhost = data.val.triple.host;
const char *nuser = data.val.triple.user;
const char *ndomain = data.val.triple.domain;
-
- size_t hostlen = strlen (nhost ?: "") + 1;
- size_t userlen = strlen (nuser ?: "") + 1;
- size_t domainlen = strlen (ndomain ?: "") + 1;
-
- if (nhost == NULL || nuser == NULL || ndomain == NULL
- || nhost > nuser || nuser > ndomain)
- {
- const char *last = nhost;
- if (last == NULL
- || (nuser != NULL && nuser > last))
- last = nuser;
- if (last == NULL
- || (ndomain != NULL && ndomain > last))
- last = ndomain;
-
- size_t bufused
- = (last == NULL
- ? buffilled
- : last + strlen (last) + 1 - buffer);
-
- /* We have to make temporary copies. */
- size_t needed = hostlen + userlen + domainlen;
-
- if (buflen - req->key_len - bufused < needed)
- {
- buflen += MAX (buflen, 2 * needed);
- /* Save offset in the old buffer. We don't
- bother with the NULL check here since
- we'll do that later anyway. */
- size_t nhostdiff = nhost - buffer;
- size_t nuserdiff = nuser - buffer;
- size_t ndomaindiff = ndomain - buffer;
-
- char *newbuf = xrealloc (buffer, buflen);
- /* Fix up the triplet pointers into the new
- buffer. */
- nhost = (nhost ? newbuf + nhostdiff
- : NULL);
- nuser = (nuser ? newbuf + nuserdiff
- : NULL);
- ndomain = (ndomain ? newbuf + ndomaindiff
- : NULL);
- *tofreep = buffer = newbuf;
- }
-
- nhost = memcpy (buffer + bufused,
- nhost ?: "", hostlen);
- nuser = memcpy ((char *) nhost + hostlen,
- nuser ?: "", userlen);
- ndomain = memcpy ((char *) nuser + userlen,
- ndomain ?: "", domainlen);
- }
-
- char *wp = buffer + buffilled;
- wp = memmove (wp, nhost ?: "", hostlen);
- wp += hostlen;
- wp = memmove (wp, nuser ?: "", userlen);
- wp += userlen;
- wp = memmove (wp, ndomain ?: "", domainlen);
- wp += domainlen;
- buffilled = wp - buffer;
+ if (!(addgetnetgrentX_append (scratch, nhost)
+ && addgetnetgrentX_append (scratch, nuser)
+ && addgetnetgrentX_append (scratch, ndomain)))
+ return send_notfound (fd);
++nentries;
}
else
@@ -318,8 +331,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
{
- buflen *= 2;
- *tofreep = buffer = xrealloc (buffer, buflen);
+ if (!scratch_buffer_grow (&scratch->tmp))
+ return send_notfound (fd);
}
else if (status == NSS_STATUS_RETURN
|| status == NSS_STATUS_NOTFOUND
@@ -352,10 +365,17 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
goto maybe_cache_add;
}
- total = buffilled;
+ /* Capture the result size without the key appended. */
+ total = scratch->buffer_used;
+
+ /* Make a copy of the key. The scratch buffer must not move after
+ this point. */
+ key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len);
+ if (key_copy == NULL)
+ return send_notfound (fd);
/* Fill in the dataset. */
- dataset = (struct dataset *) buffer;
+ dataset = scratch->buffer.data;
timeout = datahead_init_pos (&dataset->head, total + req->key_len,
total - offsetof (struct dataset, resp),
he == NULL ? 0 : dh->nreloads + 1,
@@ -364,11 +384,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
dataset->resp.nresults = nentries;
- dataset->resp.result_len = buffilled - sizeof (*dataset);
-
- assert (buflen - buffilled >= req->key_len);
- key_copy = memcpy (buffer + buffilled, key, req->key_len);
- buffilled += req->key_len;
+ dataset->resp.result_len = total - sizeof (*dataset);
/* Now we can determine whether on refill we have to create a new
record or not. */
@@ -399,7 +415,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
if (__glibc_likely (newp != NULL))
{
/* Adjust pointer into the memory block. */
- key_copy = (char *) newp + (key_copy - buffer);
+ key_copy = (char *) newp + (key_copy - (char *) dataset);
dataset = memcpy (newp, dataset, total + req->key_len);
cacheable = true;
@@ -440,7 +456,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
out:
- *resultp = dataset;
+ scratch->dataset = dataset;
return timeout;
}
@@ -461,6 +477,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
if (user != NULL)
key = (char *) rawmemchr (key, '\0') + 1;
const char *domain = *key++ ? key : NULL;
+ struct addgetnetgrentX_scratch scratch;
+
+ addgetnetgrentX_scratch_init (&scratch);
if (__glibc_unlikely (debug_level > 0))
{
@@ -476,12 +495,8 @@ 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;
- tofree = NULL;
- }
+ timeout = result->head.timeout;
else
{
request_header req_get =
@@ -490,7 +505,10 @@ 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, &tofree);
+ &scratch);
+ result = scratch.dataset;
+ if (timeout < 0)
+ goto out;
}
struct indataset
@@ -604,7 +622,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
}
out:
- free (tofree);
+ addgetnetgrentX_scratch_free (&scratch);
return timeout;
}
@@ -614,11 +632,12 @@ 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);
+ struct addgetnetgrentX_scratch scratch;
+ addgetnetgrentX_scratch_init (&scratch);
+ time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch);
+ addgetnetgrentX_scratch_free (&scratch);
+ if (timeout < 0)
+ timeout = 0;
return timeout;
}
@@ -662,5 +681,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he,
.key_len = he->len
};
- return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
+ int timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner,
+ he, dh);
+ if (timeout < 0)
+ timeout = 0;
+ return timeout;
}
--
2.33.0

View File

@ -1,93 +0,0 @@
From c00b984fcd53f679ca2dafcd1aee2c89836e6e73 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Tue, 29 Aug 2023 08:28:31 +0200
Subject: [PATCH] nscd: Skip unusable entries in first pass in prune_cache (bug
30800)
Previously, if an entry was marked unusable for any reason, but had
not timed out yet, the assert would trigger.
One way to get into such state is if a data change is detected during
re-validation of an entry. This causes the entry to be marked as not
usable. If exits nscd soon after that, then the clock jumps
backwards, and nscd restarted, the cache re-validation run after
startup triggers the removed assert.
The change is more complicated than just the removal of the assert
because entries marked as not usable should be garbage-collected in
the second pass. To make this happen, it is necessary to update some
book-keeping data.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflict:NA
Reference:https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=c00b984fcd53f679ca2dafcd1aee2c89836e6e73
---
nscd/cache.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/nscd/cache.c b/nscd/cache.c
index 78b22697..ac5902ae 100644
--- a/nscd/cache.c
+++ b/nscd/cache.c
@@ -371,8 +371,11 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
serv2str[runp->type], str, dh->timeout);
}
- /* Check whether the entry timed out. */
- if (dh->timeout < now)
+ /* Check whether the entry timed out. Timed out entries
+ will be revalidated. For unusable records, it is still
+ necessary to record that the bucket needs to be scanned
+ again below. */
+ if (dh->timeout < now || !dh->usable)
{
/* This hash bucket could contain entries which need to
be looked at. */
@@ -384,7 +387,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
/* We only have to look at the data of the first entries
since the count information is kept in the data part
which is shared. */
- if (runp->first)
+ if (runp->first && dh->usable)
{
/* At this point there are two choices: we reload the
@@ -400,9 +403,6 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
{
/* Remove the value. */
dh->usable = false;
-
- /* We definitely have some garbage entries now. */
- any = true;
}
else
{
@@ -414,18 +414,15 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
time_t timeout = readdfcts[runp->type] (table, runp, dh);
next_timeout = MIN (next_timeout, timeout);
-
- /* If the entry has been replaced, we might need
- cleanup. */
- any |= !dh->usable;
}
}
+
+ /* If the entry has been replaced, we might need cleanup. */
+ any |= !dh->usable;
}
else
- {
- assert (dh->usable);
- next_timeout = MIN (next_timeout, dh->timeout);
- }
+ /* Entry has not timed out and is usable. */
+ next_timeout = MIN (next_timeout, dh->timeout);
run = runp->next;
}
--
2.33.0

View File

@ -1,49 +0,0 @@
From 2d472b48610f6a298d28035b683ab13e9afac4cb Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Mon, 24 Jul 2023 15:12:26 +0200
Subject: [PATCH] nscd: Use errval, not errno to guide cache update (bug 30662)
The errno variable is potentially clobbered by the preceding
send call. It is not related to the to-be-cached information.
The parallel code in hstcache.c and servicescache.c already uses
errval.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflict:NA
Reference:https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=2d472b48610f6a298d28035b683ab13e9afac4cb
---
nscd/grpcache.c | 2 +-
nscd/pwdcache.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index 457ca4d8..d18bcabe 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -117,7 +117,7 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
/* If we have a transient error or cannot permanently store
the result, so be it. */
- if (errno == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
+ if (errval == EAGAIN || __glibc_unlikely (db->negtimeout == 0))
{
/* Mark the old entry as obsolete. */
if (dh != NULL)
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index dfafb526..409c5acd 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -123,7 +123,7 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
/* If we have a transient error or cannot permanently store
the result, so be it. */
- if (errno == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
+ if (errval == EAGAIN || __glibc_unlikely (db->negtimeout == 0))
{
/* Mark the old entry as obsolete. */
if (dh != NULL)
--
2.33.0

View File

@ -1,209 +0,0 @@
From 980450f12685326729d63ff72e93a996113bf073 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed, 29 Nov 2023 11:31:37 +0000
Subject: [PATCH] elf: Add TLS modid reuse test for bug 29039
This is a minimal regression test for bug 29039 which only affects
targets with TLSDESC and a reproducer requires that
1) Have modid gaps (closed modules) with old generation.
2) Update a DTV to a newer generation (needs a newer dlopen).
3) But do not update the closed gap entry in that DTV.
4) Reuse the modid gap for a new module (another dlopen).
5) Use dynamic TLSDESC in that new module with old generation (bug).
6) Access TLS via this TLSDESC and the now outdated DTV.
However step (3) in practice rarely happens: during DTV update the
entries for closed modids are initialized to "unallocated" and then
dynamic TLSDESC calls __tls_get_addr independently of its generation.
The only exception to this is DTV setup at thread creation (gaps are
initialized to NULL instead of unallocated) or DTV resize where the
gap entries are outside the previous DTV array (again NULL instead
of unallocated, and this requires loading > DTV_SURPLUS modules).
So the bug can only cause NULL (+ offset) dereference, not use after
free. And the easiest way to get (3) is via thread creation.
Note that step (5) requires that the newly loaded module has larger
TLS than the remaining optional static TLS. And for (6) there cannot
be other TLS access or dlopen in the thread that updates the DTV.
Tested on aarch64-linux-gnu.
Reference:https://sourceware.org/git/?p=glibc.git;a=commit;h=980450f12685326729d63ff72e93a996113bf073
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
---
elf/Makefile | 15 +++++++
elf/tst-tlsgap-mod0.c | 2 +
elf/tst-tlsgap-mod1.c | 2 +
elf/tst-tlsgap-mod2.c | 2 +
elf/tst-tlsgap.c | 92 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 113 insertions(+)
create mode 100644 elf/tst-tlsgap-mod0.c
create mode 100644 elf/tst-tlsgap-mod1.c
create mode 100644 elf/tst-tlsgap-mod2.c
create mode 100644 elf/tst-tlsgap.c
diff --git a/elf/Makefile b/elf/Makefile
index ed13f34d..b5de4dd4 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -425,6 +425,7 @@ tests += \
tst-tls5 \
tst-tlsalign \
tst-tlsalign-extern \
+ tst-tlsgap \
tst-tls-dlinfo \
tst-tls-ie \
tst-tls-ie-dlmopen \
@@ -704,6 +705,9 @@ modules-names = \
tst-tls20mod-bad \
tst-tls21mod \
tst-tlsalign-lib \
+ tst-tlsgap-mod0 \
+ tst-tlsgap-mod1 \
+ tst-tlsgap-mod2 \
tst-tls-ie-mod0 \
tst-tls-ie-mod1 \
tst-tls-ie-mod2 \
@@ -2498,3 +2502,14 @@ $(objpfx)tst-non-directory-path.out: tst-non-directory-path.sh \
'$(test-wrapper-env)' '$(run_program_env)' \
'$(rpath-link)' $(objpfx) > $@; \
$(evaluate-test)
+
+$(objpfx)tst-tlsgap: $(shared-thread-library)
+$(objpfx)tst-tlsgap.out: \
+ $(objpfx)tst-tlsgap-mod0.so \
+ $(objpfx)tst-tlsgap-mod1.so \
+ $(objpfx)tst-tlsgap-mod2.so
+ifeq (yes,$(have-mtls-dialect-gnu2))
+CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2
+CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2
+CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2
+endif
diff --git a/elf/tst-tlsgap-mod0.c b/elf/tst-tlsgap-mod0.c
new file mode 100644
index 00000000..1478b0be
--- /dev/null
+++ b/elf/tst-tlsgap-mod0.c
@@ -0,0 +1,2 @@
+int __thread tls0;
+int *f0(void) { return &tls0; }
diff --git a/elf/tst-tlsgap-mod1.c b/elf/tst-tlsgap-mod1.c
new file mode 100644
index 00000000..b10fc370
--- /dev/null
+++ b/elf/tst-tlsgap-mod1.c
@@ -0,0 +1,2 @@
+int __thread tls1[100]; /* Size > glibc.rtld.optional_static_tls / 2. */
+int *f1(void) { return tls1; }
diff --git a/elf/tst-tlsgap-mod2.c b/elf/tst-tlsgap-mod2.c
new file mode 100644
index 00000000..166c27d7
--- /dev/null
+++ b/elf/tst-tlsgap-mod2.c
@@ -0,0 +1,2 @@
+int __thread tls2;
+int *f2(void) { return &tls2; }
diff --git a/elf/tst-tlsgap.c b/elf/tst-tlsgap.c
new file mode 100644
index 00000000..49328850
--- /dev/null
+++ b/elf/tst-tlsgap.c
@@ -0,0 +1,92 @@
+/* TLS modid gap reuse regression test for bug 29039.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+#include <support/check.h>
+
+static void *mod[3];
+#define MOD(i) "tst-tlsgap-mod" #i ".so"
+static const char *modname[3] = { MOD(0), MOD(1), MOD(2) };
+#undef MOD
+
+static void
+open_mod (int i)
+{
+ mod[i] = xdlopen (modname[i], RTLD_LAZY);
+ printf ("open %s\n", modname[i]);
+}
+
+static void
+close_mod (int i)
+{
+ xdlclose (mod[i]);
+ mod[i] = NULL;
+ printf ("close %s\n", modname[i]);
+}
+
+static void
+access_mod (int i, const char *sym)
+{
+ int *(*f) (void) = xdlsym (mod[i], sym);
+ int *p = f ();
+ printf ("access %s: %s() = %p\n", modname[i], sym, p);
+ TEST_VERIFY_EXIT (p != NULL);
+ ++*p;
+}
+
+static void *
+start (void *arg)
+{
+ /* The DTV generation is at the last dlopen of mod0 and the
+ entry for mod1 is NULL. */
+
+ open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS. */
+
+ /* DTV is unchanged: dlopen only updates the DTV to the latest
+ generation if static TLS is allocated for a loaded module.
+
+ With bug 29039, the TLSDESC relocation in mod1 uses the old
+ dlclose generation of mod1 instead of the new dlopen one so
+ DTV is not updated on TLS access. */
+
+ access_mod (1, "f1");
+
+ return arg;
+}
+
+static int
+do_test (void)
+{
+ open_mod (0);
+ open_mod (1);
+ open_mod (2);
+ close_mod (0);
+ close_mod (1); /* Create modid gap at mod1. */
+ open_mod (0); /* Reuse modid of mod0, bump generation count. */
+
+ /* Create a thread where DTV of mod1 is NULL. */
+ pthread_t t = xpthread_create (NULL, start, NULL);
+ xpthread_join (t);
+ return 0;
+}
+
+#include <support/test-driver.c>
--
2.33.0

View File

@ -1,35 +0,0 @@
From 1cce91d8aed5c3eca2b6f47767c82d9ed3e9e33f Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 8 Apr 2024 09:06:09 -0700
Subject: [PATCH] elf: Check objname before calling fatal_error
_dl_signal_error may be called with objname == NULL. _dl_exception_create
checks objname == NULL. But fatal_error doesn't. Check objname before
calling fatal_error. This fixes BZ #31596.
Reference:https://sourceware.org/git/?p=glibc.git;a=commit;h=1cce91d8aed5c3eca2b6f47767c82d9ed3e9e33f
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
---
elf/dl-error-skeleton.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
index b699936c..26dfab55 100644
--- a/elf/dl-error-skeleton.c
+++ b/elf/dl-error-skeleton.c
@@ -121,7 +121,11 @@ _dl_signal_error (int errcode, const char *objname, const char *occation,
__longjmp (lcatch->env[0].__jmpbuf, 1);
}
else
+ {
+ if (objname == NULL)
+ objname = "";
fatal_error (errcode, objname, occation, errstring);
+ }
}
libc_hidden_def (_dl_signal_error)
--
2.33.0

View File

@ -1,54 +0,0 @@
From 3921c5b40f293c57cb326f58713c924b0662ef59 Mon Sep 17 00:00:00 2001
From: Hector Martin <marcan@marcan.st>
Date: Tue, 28 Nov 2023 15:23:07 +0900
Subject: [PATCH] elf: Fix TLS modid reuse generation assignment (BZ 29039)
_dl_assign_tls_modid() assigns a slotinfo entry for a new module, but
does *not* do anything to the generation counter. The first time this
happens, the generation is zero and map_generation() returns the current
generation to be used during relocation processing. However, if
a slotinfo entry is later reused, it will already have a generation
assigned. If this generation has fallen behind the current global max
generation, then this causes an obsolete generation to be assigned
during relocation processing, as map_generation() returns this
generation if nonzero. _dl_add_to_slotinfo() eventually resets the
generation, but by then it is too late. This causes DTV updates to be
skipped, leading to NULL or broken TLS slot pointers and segfaults.
Fix this by resetting the generation to zero in _dl_assign_tls_modid(),
so it behaves the same as the first time a slot is assigned.
_dl_add_to_slotinfo() will still assign the correct static generation
later during module load, but relocation processing will no longer use
an obsolete generation.
Note that slotinfo entry (aka modid) reuse typically happens after a
dlclose and only TLS access via dynamic tlsdesc is affected. Because
tlsdesc is optimized to use the optional part of static TLS, dynamic
tlsdesc can be avoided by increasing the glibc.rtld.optional_static_tls
tunable to a large enough value, or by LD_PRELOAD-ing the affected
modules.
Fixes bug 29039.
Reference:https://sourceware.org/git/?p=glibc.git;a=commit;h=3921c5b40f293c57cb326f58713c924b0662ef59
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
---
elf/dl-tls.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 0070c8bb..42868eef 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -160,6 +160,7 @@ _dl_assign_tls_modid (struct link_map *l)
{
/* Mark the entry as used, so any dependency see it. */
atomic_store_relaxed (&runp->slotinfo[result - disp].map, l);
+ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0);
break;
}
--
2.33.0

View File

@ -1,137 +0,0 @@
From 434eca873f14f618d6c2279b54fb809fb56f2c50 Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon, 6 Nov 2023 17:25:40 -0300
Subject: [PATCH] elf: Fix _dl_debug_vdprintf to work before self-relocation
The strlen might trigger and invalid GOT entry if it used before
the process is self-relocated (for instance on dl-tunables if any
error occurs).
For i386, _dl_writev with PIE requires to use the old 'int $0x80'
syscall mode because the calling the TLS register (gs) is not yet
initialized.
Reference:https://sourceware.org/git/?p=glibc.git;a=commit;h=434eca873f14f618d6c2279b54fb809fb56f2c50
Checked on x86_64-linux-gnu.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
elf/dl-misc.c | 15 +++++++++++++--
stdio-common/Makefile | 5 +++++
stdio-common/_itoa.c | 5 +++++
sysdeps/unix/sysv/linux/i386/dl-writev.h | 24 ++++++++++++++++++++++++
4 files changed, 47 insertions(+), 2 deletions(-)
create mode 100644 sysdeps/unix/sysv/linux/i386/dl-writev.h
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index bba2e714..5b637c7e 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -16,6 +16,10 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <string.h>
+#if BUILD_PIE_DEFAULT
+# pragma GCC visibility push(hidden)
+#endif
#include <assert.h>
#include <fcntl.h>
#include <ldsodefs.h>
@@ -23,7 +27,6 @@
#include <link.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/mman.h>
@@ -71,6 +74,14 @@ _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
return result;
}
+/* The function might be called before the process is self-relocated. */
+static size_t
+_dl_debug_strlen (const char *s)
+{
+ const char *p = s;
+ for (; *s != '\0'; s++);
+ return s - p;
+}
/* Bare-bones printf implementation. This function only knows about
the formats and flags needed and can handle only up to 64 stripes in
@@ -235,7 +246,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
case 's':
/* Get the string argument. */
iov[niov].iov_base = va_arg (arg, char *);
- iov[niov].iov_len = strlen (iov[niov].iov_base);
+ iov[niov].iov_len = _dl_debug_strlen (iov[niov].iov_base);
if (prec != -1)
iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
++niov;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 803f16da..f9763c27 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -181,6 +181,11 @@ CFLAGS-isoc99_scanf.c += -fexceptions
CFLAGS-errlist.c += $(fno-unit-at-a-time)
CFLAGS-siglist.c += $(fno-unit-at-a-time)
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-_itoa.o = $(no-stack-protector)
+CFLAGS-_itoa.op = $(no-stack-protector)
+
# scanf14a.c and scanf16a.c test a deprecated extension which is no
# longer visible under most conformance levels; see the source files
# for more detail.
diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c
index c37d1c35..20c2e384 100644
--- a/stdio-common/_itoa.c
+++ b/stdio-common/_itoa.c
@@ -18,6 +18,11 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+/* Mark symbols hidden in static PIE for early self relocation to work.
+ Note: string.h may have ifuncs which cannot be hidden on i686. */
+#if BUILD_PIE_DEFAULT
+# pragma GCC visibility push(hidden)
+#endif
#include <gmp-mparam.h>
#include <gmp.h>
#include <limits.h>
diff --git a/sysdeps/unix/sysv/linux/i386/dl-writev.h b/sysdeps/unix/sysv/linux/i386/dl-writev.h
new file mode 100644
index 00000000..624d0e46
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/dl-writev.h
@@ -0,0 +1,24 @@
+/* Message-writing for the dynamic linker. Linux/i386 version.
+ Copyright (C) 2013-2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#if BUILD_PIE_DEFAULT
+/* Can't use "call *%gs:SYSINFO_OFFSET" during startup in static PIE. */
+# define I386_USE_SYSENTER 0
+#endif
+
+#include <sysdeps/unix/sysv/linux/dl-writev.h>
--
2.33.0

View File

@ -1,135 +0,0 @@
From 718fdd87b1b98ef88e883a37d9c18867256fa5a4 Mon Sep 17 00:00:00 2001
From: Rongwei Wang <rongwei.wang@linux.alibaba.com>
Date: Fri, 10 Dec 2021 20:39:10 +0800
Subject: [PATCH] elf: Properly align PT_LOAD segments [BZ #28676]
When PT_LOAD segment alignment > the page size, allocate enough space to
ensure that the segment can be properly aligned. This change helps code
segments use huge pages become simple and available.
This fixes [BZ #28676].
Signed-off-by: Xu Yu <xuyu@linux.alibaba.com>
Signed-off-by: Rongwei Wang <rongwei.wang@linux.alibaba.com>
---
elf/dl-load.c | 2 ++
elf/dl-load.h | 3 ++-
elf/dl-map-segments.h | 50 +++++++++++++++++++++++++++++++++++++++----
3 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/elf/dl-load.c b/elf/dl-load.c
index bf8957e73c..721593135e 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1,5 +1,6 @@
/* Map in a shared object's segments from the file.
Copyright (C) 1995-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -1150,6 +1151,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
c->dataend = ph->p_vaddr + ph->p_filesz;
c->allocend = ph->p_vaddr + ph->p_memsz;
+ c->mapalign = ph->p_align;
c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
/* Determine whether there is a gap between the last segment
diff --git a/elf/dl-load.h b/elf/dl-load.h
index e329d49a81..e6dabcb336 100644
--- a/elf/dl-load.h
+++ b/elf/dl-load.h
@@ -1,5 +1,6 @@
/* Map in a shared object's segments from the file.
Copyright (C) 1995-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -74,7 +75,7 @@ ELF_PREFERRED_ADDRESS_DATA;
Its details have been expanded out and converted. */
struct loadcmd
{
- ElfW(Addr) mapstart, mapend, dataend, allocend;
+ ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign;
ElfW(Off) mapoff;
int prot; /* PROT_* bits. */
};
diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h
index f9fb110ee3..70a4c40695 100644
--- a/elf/dl-map-segments.h
+++ b/elf/dl-map-segments.h
@@ -1,5 +1,6 @@
/* Map in a shared object's segments. Generic version.
Copyright (C) 1995-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -18,6 +19,50 @@
#include <dl-load.h>
+/* Map a segment and align it properly. */
+
+static __always_inline ElfW(Addr)
+_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
+ const size_t maplength, int fd)
+{
+ if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize)))
+ return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot,
+ MAP_COPY|MAP_FILE, fd, c->mapoff);
+
+ /* If the segment alignment > the page size, allocate enough space to
+ ensure that the segment can be properly aligned. */
+ ElfW(Addr) maplen = (maplength >= c->mapalign
+ ? (maplength + c->mapalign)
+ : (2 * c->mapalign));
+ ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen,
+ PROT_NONE,
+ MAP_ANONYMOUS|MAP_PRIVATE,
+ -1, 0);
+ if (__glibc_unlikely ((void *) map_start == MAP_FAILED))
+ return map_start;
+
+ ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign);
+ map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned,
+ maplength, c->prot,
+ MAP_COPY|MAP_FILE|MAP_FIXED,
+ fd, c->mapoff);
+ if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED))
+ __munmap ((void *) map_start, maplen);
+ else
+ {
+ /* Unmap the unused regions. */
+ ElfW(Addr) delta = map_start_aligned - map_start;
+ if (delta)
+ __munmap ((void *) map_start, delta);
+ ElfW(Addr) map_end = map_start_aligned + maplength;
+ delta = map_start + maplen - map_end;
+ if (delta)
+ __munmap ((void *) map_end, delta);
+ }
+
+ return map_start_aligned;
+}
+
/* This implementation assumes (as does the corresponding implementation
of _dl_unmap_segments, in dl-unmap-segments.h) that shared objects
are always laid out with all segments contiguous (or with gaps
@@ -53,10 +98,7 @@ _dl_map_segments (struct link_map *l, int fd,
- MAP_BASE_ADDR (l));
/* Remember which part of the address space this object uses. */
- l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
- c->prot,
- MAP_COPY|MAP_FILE,
- fd, c->mapoff);
+ l->l_map_start = _dl_map_segment (c, mappref, maplength, fd);
if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
--
2.43.0

View File

@ -1,76 +0,0 @@
From 2aa0974d2573441bffd596b07bff8698b1f2f18c Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 20 Oct 2023 14:29:50 +0200
Subject: [PATCH 1/1] elf: ldconfig should skip temporary files created by
package managers
This avoids crashes due to partially written files, after a package
update is interrupted.
Reference:https://sourceware.org/git/?p=glibc.git;a=commit;h=2aa0974d2573441bffd596b07bff8698b1f2f18c
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
---
elf/ldconfig.c | 39 +++++++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 6190e0ea..73b5ef27 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -746,6 +746,31 @@ struct dlib_entry
struct dlib_entry *next;
};
+/* Skip some temporary DSO files. These files may be partially written
+ and lead to ldconfig crashes when examined. */
+static bool
+skip_dso_based_on_name (const char *name, size_t len)
+{
+ /* Skip temporary files created by the prelink program. Files with
+ names like these are never really DSOs we want to look at. */
+ if (len >= sizeof (".#prelink#") - 1)
+ {
+ if (strcmp (name + len - sizeof (".#prelink#") + 1,
+ ".#prelink#") == 0)
+ return true;
+ if (len >= sizeof (".#prelink#.XXXXXX") - 1
+ && memcmp (name + len - sizeof (".#prelink#.XXXXXX")
+ + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
+ return true;
+ }
+ /* Skip temporary files created by RPM. */
+ if (memchr (name, len, ';') != NULL)
+ return true;
+ /* Skip temporary files created by dpkg. */
+ if (len > 4 && memcmp (name + len - 4, ".tmp", 4) == 0)
+ return true;
+ return false;
+}
static void
search_dir (const struct dir_entry *entry)
@@ -822,18 +847,8 @@ search_dir (const struct dir_entry *entry)
continue;
size_t len = strlen (direntry->d_name);
- /* Skip temporary files created by the prelink program. Files with
- names like these are never really DSOs we want to look at. */
- if (len >= sizeof (".#prelink#") - 1)
- {
- if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1,
- ".#prelink#") == 0)
- continue;
- if (len >= sizeof (".#prelink#.XXXXXX") - 1
- && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX")
- + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
- continue;
- }
+ if (skip_dso_based_on_name (direntry->d_name, len))
+ continue;
len += strlen (entry->path) + 2;
if (len > file_name_len)
{
--
2.33.0

View File

@ -1,68 +0,0 @@
From cfb5a97a93ea656e3b2263e42142a4032986d9ba Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Mon, 23 Oct 2023 12:53:16 +0200
Subject: [PATCH] ldconfig: Fixes for skipping temporary files.
Arguments to a memchr call were swapped, causing incorrect skipping
of files.
Files related to dpkg have different names: they actually end in
.dpkg-new and .dpkg-tmp, not .tmp as I mistakenly assumed.
Fixes commit 2aa0974d2573441bffd59 ("elf: ldconfig should skip
temporary files created by package managers").
Reference:https://sourceware.org/git/?p=glibc.git;a=commit;h=cfb5a97a93ea656e3b2263e42142a4032986d9ba
---
elf/ldconfig.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 73b5ef27..5812a951 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -746,6 +746,17 @@ struct dlib_entry
struct dlib_entry *next;
};
+/* Return true if the N bytes at NAME end with with the characters in
+ the string SUFFIX. (NAME[N + 1] does not have to be a null byte.)
+ Expected to be called with a string literal for SUFFIX. */
+static inline bool
+endswithn (const char *name, size_t n, const char *suffix)
+{
+ return (n >= strlen (suffix)
+ && memcmp (name + n - strlen (suffix), suffix,
+ strlen (suffix)) == 0);
+}
+
/* Skip some temporary DSO files. These files may be partially written
and lead to ldconfig crashes when examined. */
static bool
@@ -755,8 +766,7 @@ skip_dso_based_on_name (const char *name, size_t len)
names like these are never really DSOs we want to look at. */
if (len >= sizeof (".#prelink#") - 1)
{
- if (strcmp (name + len - sizeof (".#prelink#") + 1,
- ".#prelink#") == 0)
+ if (endswithn (name, len, ".#prelink#"))
return true;
if (len >= sizeof (".#prelink#.XXXXXX") - 1
&& memcmp (name + len - sizeof (".#prelink#.XXXXXX")
@@ -764,10 +774,11 @@ skip_dso_based_on_name (const char *name, size_t len)
return true;
}
/* Skip temporary files created by RPM. */
- if (memchr (name, len, ';') != NULL)
+ if (memchr (name, ';', len) != NULL)
return true;
/* Skip temporary files created by dpkg. */
- if (len > 4 && memcmp (name + len - 4, ".tmp", 4) == 0)
+ if (endswithn (name, len, ".dpkg-new")
+ || endswithn (name, len, ".dpkg-tmp"))
return true;
return false;
}
--
2.33.0

View File

@ -27,15 +27,10 @@
# - Run smoke tests with valgrind to verify dynamic loader.
# - Default: Always run valgrind tests if there is architecture support.
##############################################################################
%bcond_without testsuite
%bcond_with benchtests
%bcond_with bootstrap
%ifarch ppc64le
%bcond_with testsuite
%bcond_with werror
%else
%bcond_without testsuite
%bcond_without werror
%endif
%bcond_without docs
%ifarch x86_64 aarch64
%bcond_without compat_2_17
@ -71,7 +66,7 @@
##############################################################################
Name: glibc
Version: 2.34
Release: 152
Release: 147
Summary: The GNU libc libraries
License: %{all_license}
URL: http://www.gnu.org/software/glibc/
@ -291,19 +286,6 @@ Patch199: elf-Add-a-way-to-check-if-tunable-is-set-BZ-27069.patch
Patch200: malloc-Improve-MAP_HUGETLB-with-glibc.malloc.hugetlb.patch
Patch201: iconv-ISO-2022-CN-EXT-fix-out-of-bound-writes-when-w.patch
Patch202: backport-resolv_conf-release-lock-on-allocation-failure-bug-30527.patch
Patch203: backport-CVE-2024-33599-nscd-Stack-based-buffer-overflow-in-netgroup-cache.patch
Patch204: backport-CVE-2024-33600-nscd-Do-not-send-missing-not-found-response.patch
Patch205: backport-CVE-2024-33600-nscd-Avoid-null-pointer-crash-after-not-found-response.patch
Patch206: backport-CVE-2024-33601-CVE-2024-33602-nscd-Use-two-buffer-in-addgetnetgrentX.patch
Patch207: backport-Use-errval-not-errno-to-guide-cache-update.patch
Patch208: backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch
Patch209: backport-elf-Add-TLS-modid-reuse-test-for-bug-29039.patch
Patch210: backport-elf-Fix-TLS-modid-reuse-generation-assignment-BZ-290.patch
Patch211: backport-elf-Check-objname-before-calling-fatal_error.patch
Patch212: backport-elf-Fix-_dl_debug_vdprintf-to-work-before-self-reloc.patch
Patch213: backport-elf-ldconfig-should-skip-temporary-files-created-by-.patch
Patch214: backport-ldconfig-Fixes-for-skipping-temporary-files.patch
Patch215: backport-elf-Properly-align-PT_LOAD-segments-BZ-28676.patch
Patch9000: turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch
Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch
@ -1519,42 +1501,6 @@ fi
%endif
%changelog
* Tue Jun 25 2024 chenhaixiang <chenhaixiang3@huawei.com> - 2.34-152
- Type:bugfix
- ID:
- SUG:NA
- DESC:elf: Properly align PT_LOAD segments
* Mon Jun 17 2024 hefq343 <fengqing.he@shingroup.cn> - 2.34-151
- Type:bugfix
- ID:
- SUG:NA
- DESC:fix compile error for ppc64le
* Fri May 10 2024 shixuantong <shixuantong1@huawei.com> - 2.34-150
- Type:bugfix
- ID:
- SUG:NA
- DESC:elf: Add TLS modid reuse test for bug 29039
elf: Fix TLS modid reuse generation assignment
elf: Check objname before calling fatal_error
elf: Fix _dl_debug_vdprintf to work before self-relocation
elf: ldconfig should skip temporary files created by package managers
ldconfig: Fixes for skipping temporary files.
* Mon May 06 2024 chengyechun <chengyechun1@huaiwe.com> - 2.34-149
- Type:bugfix
- ID:
- SUG:NA
- DESC:nscd: Use errval, not errno to guide cache update
nsce :Skip unusable entries in first pass in prune_cache
* Mon Apr 29 2024 chengyechun <chengyechun1@huawei.com> - 2.34-148
- Type:CVE
- ID:CVE-2024-33599 CVE-2024-33600 CVE-2024-33601 CVE-2024-33602
- SUG:NA
- DESC:fix CVE-2024-33599 CVE-2024-33600 CVE-2024-33601 CVE-2024-33602
* Wed Apr 24 2024 Lixing <lixing@loongson.cn> - 2.34-147
- Add missing LoongArch relocation type in elf.h