wok-current view glibc/stuff/CVE-2024-33601_CVE-2024-33602_1.patch @ rev 25785

Mass rebuild after bump to glibc 2.31, add epson printer and scanner package
author Stanislas Leduc <shann@slitaz.org>
date Tue Jul 15 20:40:17 2025 +0000 (3 months ago)
parents
children
line source
1 From 4d27d4b9a188786fc6a56745506cec2acfc51f83 Mon Sep 17 00:00:00 2001
2 From: Florian Weimer <fweimer@redhat.com>
3 Date: Thu, 25 Apr 2024 15:01:07 +0200
4 Subject: [PATCH] CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two
5 buffers in addgetnetgrentX (bug 31680)
7 This avoids potential memory corruption when the underlying NSS
8 callback function does not use the buffer space to store all strings
9 (e.g., for constant strings).
11 Instead of custom buffer management, two scratch buffers are used.
12 This increases stack usage somewhat.
14 Scratch buffer allocation failure is handled by return -1
15 (an invalid timeout value) instead of terminating the process.
16 This fixes bug 31679.
18 Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
19 (cherry picked from commit c04a21e050d64a1193a6daab872bca2528bda44b)
20 ---
21 nscd/netgroupcache.c | 219 ++++++++++++++++++++++++-------------------
22 1 file changed, 121 insertions(+), 98 deletions(-)
24 diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
25 index aa9501a2c05..ee98ffd96ed 100644
26 --- a/nscd/netgroupcache.c
27 +++ b/nscd/netgroupcache.c
28 @@ -24,6 +24,7 @@
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/mman.h>
32 +#include <scratch_buffer.h>
34 #include "../inet/netgroup.h"
35 #include "nscd.h"
36 @@ -66,6 +67,16 @@ struct dataset
37 char strdata[0];
38 };
40 +/* Send a notfound response to FD. Always returns -1 to indicate an
41 + ephemeral error. */
42 +static time_t
43 +send_notfound (int fd)
44 +{
45 + if (fd != -1)
46 + TEMP_FAILURE_RETRY (send (fd, &notfound, sizeof (notfound), MSG_NOSIGNAL));
47 + return -1;
48 +}
49 +
50 /* Sends a notfound message and prepares a notfound dataset to write to the
51 cache. Returns true if there was enough memory to allocate the dataset and
52 returns the dataset in DATASETP, total bytes to write in TOTALP and the
53 @@ -84,8 +95,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
54 total = sizeof (notfound);
55 timeout = time (NULL) + db->negtimeout;
57 - if (fd != -1)
58 - TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
59 + send_notfound (fd);
61 dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
62 /* If we cannot permanently store the result, so be it. */
63 @@ -110,11 +120,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
64 return cacheable;
65 }
67 +struct addgetnetgrentX_scratch
68 +{
69 + /* This is the result that the caller should use. It can be NULL,
70 + point into buffer, or it can be in the cache. */
71 + struct dataset *dataset;
72 +
73 + struct scratch_buffer buffer;
74 +
75 + /* Used internally in addgetnetgrentX as a staging area. */
76 + struct scratch_buffer tmp;
77 +
78 + /* Number of bytes in buffer that are actually used. */
79 + size_t buffer_used;
80 +};
81 +
82 +static void
83 +addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch)
84 +{
85 + scratch->dataset = NULL;
86 + scratch_buffer_init (&scratch->buffer);
87 + scratch_buffer_init (&scratch->tmp);
88 +
89 + /* Reserve space for the header. */
90 + scratch->buffer_used = sizeof (struct dataset);
91 + static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space),
92 + "initial buffer space");
93 + memset (scratch->tmp.data, 0, sizeof (struct dataset));
94 +}
95 +
96 +static void
97 +addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch)
98 +{
99 + scratch_buffer_free (&scratch->buffer);
100 + scratch_buffer_free (&scratch->tmp);
101 +}
102 +
103 +/* Copy LENGTH bytes from S into SCRATCH. Returns NULL if SCRATCH
104 + could not be resized, otherwise a pointer to the copy. */
105 +static char *
106 +addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch,
107 + const char *s, size_t length)
108 +{
109 + while (true)
110 + {
111 + size_t remaining = scratch->buffer.length - scratch->buffer_used;
112 + if (remaining >= length)
113 + break;
114 + if (!scratch_buffer_grow_preserve (&scratch->buffer))
115 + return NULL;
116 + }
117 + char *copy = scratch->buffer.data + scratch->buffer_used;
118 + memcpy (copy, s, length);
119 + scratch->buffer_used += length;
120 + return copy;
121 +}
122 +
123 +/* Copy S into SCRATCH, including its null terminator. Returns false
124 + if SCRATCH could not be resized. */
125 +static bool
126 +addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s)
127 +{
128 + if (s == NULL)
129 + s = "";
130 + return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL;
131 +}
132 +
133 +/* Caller must initialize and free *SCRATCH. If the return value is
134 + negative, this function has sent a notfound response. */
135 static time_t
136 addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
137 const char *key, uid_t uid, struct hashentry *he,
138 - struct datahead *dh, struct dataset **resultp,
139 - void **tofreep)
140 + struct datahead *dh, struct addgetnetgrentX_scratch *scratch)
141 {
142 if (__glibc_unlikely (debug_level > 0))
143 {
144 @@ -133,14 +210,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
146 char *key_copy = NULL;
147 struct __netgrent data;
148 - size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
149 - size_t buffilled = sizeof (*dataset);
150 - char *buffer = NULL;
151 size_t nentries = 0;
152 size_t group_len = strlen (key) + 1;
153 struct name_list *first_needed
154 = alloca (sizeof (struct name_list) + group_len);
155 - *tofreep = NULL;
157 if (netgroup_database == NULL
158 && __nss_database_lookup2 ("netgroup", NULL, NULL, &netgroup_database))
159 @@ -152,8 +225,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
160 }
162 memset (&data, '\0', sizeof (data));
163 - buffer = xmalloc (buflen);
164 - *tofreep = buffer;
165 first_needed->next = first_needed;
166 memcpy (first_needed->name, key, group_len);
167 data.needed_groups = first_needed;
168 @@ -196,8 +267,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
169 while (1)
170 {
171 int e;
172 - status = getfct.f (&data, buffer + buffilled,
173 - buflen - buffilled - req->key_len, &e);
174 + status = getfct.f (&data, scratch->tmp.data,
175 + scratch->tmp.length, &e);
176 if (status == NSS_STATUS_SUCCESS)
177 {
178 if (data.type == triple_val)
179 @@ -205,68 +276,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
180 const char *nhost = data.val.triple.host;
181 const char *nuser = data.val.triple.user;
182 const char *ndomain = data.val.triple.domain;
183 -
184 - size_t hostlen = strlen (nhost ?: "") + 1;
185 - size_t userlen = strlen (nuser ?: "") + 1;
186 - size_t domainlen = strlen (ndomain ?: "") + 1;
187 -
188 - if (nhost == NULL || nuser == NULL || ndomain == NULL
189 - || nhost > nuser || nuser > ndomain)
190 - {
191 - const char *last = nhost;
192 - if (last == NULL
193 - || (nuser != NULL && nuser > last))
194 - last = nuser;
195 - if (last == NULL
196 - || (ndomain != NULL && ndomain > last))
197 - last = ndomain;
198 -
199 - size_t bufused
200 - = (last == NULL
201 - ? buffilled
202 - : last + strlen (last) + 1 - buffer);
203 -
204 - /* We have to make temporary copies. */
205 - size_t needed = hostlen + userlen + domainlen;
206 -
207 - if (buflen - req->key_len - bufused < needed)
208 - {
209 - buflen += MAX (buflen, 2 * needed);
210 - /* Save offset in the old buffer. We don't
211 - bother with the NULL check here since
212 - we'll do that later anyway. */
213 - size_t nhostdiff = nhost - buffer;
214 - size_t nuserdiff = nuser - buffer;
215 - size_t ndomaindiff = ndomain - buffer;
216 -
217 - char *newbuf = xrealloc (buffer, buflen);
218 - /* Fix up the triplet pointers into the new
219 - buffer. */
220 - nhost = (nhost ? newbuf + nhostdiff
221 - : NULL);
222 - nuser = (nuser ? newbuf + nuserdiff
223 - : NULL);
224 - ndomain = (ndomain ? newbuf + ndomaindiff
225 - : NULL);
226 - *tofreep = buffer = newbuf;
227 - }
228 -
229 - nhost = memcpy (buffer + bufused,
230 - nhost ?: "", hostlen);
231 - nuser = memcpy ((char *) nhost + hostlen,
232 - nuser ?: "", userlen);
233 - ndomain = memcpy ((char *) nuser + userlen,
234 - ndomain ?: "", domainlen);
235 - }
236 -
237 - char *wp = buffer + buffilled;
238 - wp = memmove (wp, nhost ?: "", hostlen);
239 - wp += hostlen;
240 - wp = memmove (wp, nuser ?: "", userlen);
241 - wp += userlen;
242 - wp = memmove (wp, ndomain ?: "", domainlen);
243 - wp += domainlen;
244 - buffilled = wp - buffer;
245 + if (!(addgetnetgrentX_append (scratch, nhost)
246 + && addgetnetgrentX_append (scratch, nuser)
247 + && addgetnetgrentX_append (scratch, ndomain)))
248 + return send_notfound (fd);
249 ++nentries;
250 }
251 else
252 @@ -318,8 +331,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
253 }
254 else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
255 {
256 - buflen *= 2;
257 - *tofreep = buffer = xrealloc (buffer, buflen);
258 + if (!scratch_buffer_grow (&scratch->tmp))
259 + return send_notfound (fd);
260 }
261 else if (status == NSS_STATUS_RETURN
262 || status == NSS_STATUS_NOTFOUND
263 @@ -352,10 +365,17 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
264 goto maybe_cache_add;
265 }
267 - total = buffilled;
268 + /* Capture the result size without the key appended. */
269 + total = scratch->buffer_used;
270 +
271 + /* Make a copy of the key. The scratch buffer must not move after
272 + this point. */
273 + key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len);
274 + if (key_copy == NULL)
275 + return send_notfound (fd);
277 /* Fill in the dataset. */
278 - dataset = (struct dataset *) buffer;
279 + dataset = scratch->buffer.data;
280 timeout = datahead_init_pos (&dataset->head, total + req->key_len,
281 total - offsetof (struct dataset, resp),
282 he == NULL ? 0 : dh->nreloads + 1,
283 @@ -364,11 +384,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
284 dataset->resp.version = NSCD_VERSION;
285 dataset->resp.found = 1;
286 dataset->resp.nresults = nentries;
287 - dataset->resp.result_len = buffilled - sizeof (*dataset);
288 -
289 - assert (buflen - buffilled >= req->key_len);
290 - key_copy = memcpy (buffer + buffilled, key, req->key_len);
291 - buffilled += req->key_len;
292 + dataset->resp.result_len = total - sizeof (*dataset);
294 /* Now we can determine whether on refill we have to create a new
295 record or not. */
296 @@ -399,7 +415,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
297 if (__glibc_likely (newp != NULL))
298 {
299 /* Adjust pointer into the memory block. */
300 - key_copy = (char *) newp + (key_copy - buffer);
301 + key_copy = (char *) newp + (key_copy - (char *) dataset);
303 dataset = memcpy (newp, dataset, total + req->key_len);
304 cacheable = true;
305 @@ -440,7 +456,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
306 }
308 out:
309 - *resultp = dataset;
310 + scratch->dataset = dataset;
312 return timeout;
313 }
314 @@ -461,6 +477,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
315 if (user != NULL)
316 key = (char *) rawmemchr (key, '\0') + 1;
317 const char *domain = *key++ ? key : NULL;
318 + struct addgetnetgrentX_scratch scratch;
319 +
320 + addgetnetgrentX_scratch_init (&scratch);
322 if (__glibc_unlikely (debug_level > 0))
323 {
324 @@ -476,12 +495,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
325 group, group_len,
326 db, uid);
327 time_t timeout;
328 - void *tofree;
329 if (result != NULL)
330 - {
331 - timeout = result->head.timeout;
332 - tofree = NULL;
333 - }
334 + timeout = result->head.timeout;
335 else
336 {
337 request_header req_get =
338 @@ -490,7 +505,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
339 .key_len = group_len
340 };
341 timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
342 - &result, &tofree);
343 + &scratch);
344 + result = scratch.dataset;
345 + if (timeout < 0)
346 + goto out;
347 }
349 struct indataset
350 @@ -604,7 +622,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
351 }
353 out:
354 - free (tofree);
355 + addgetnetgrentX_scratch_free (&scratch);
356 return timeout;
357 }
359 @@ -614,11 +632,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
360 const char *key, uid_t uid, struct hashentry *he,
361 struct datahead *dh)
362 {
363 - struct dataset *ignore;
364 - void *tofree;
365 - time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
366 - &ignore, &tofree);
367 - free (tofree);
368 + struct addgetnetgrentX_scratch scratch;
369 + addgetnetgrentX_scratch_init (&scratch);
370 + time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch);
371 + addgetnetgrentX_scratch_free (&scratch);
372 + if (timeout < 0)
373 + timeout = 0;
374 return timeout;
375 }
377 @@ -662,5 +681,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he,
378 .key_len = he->len
379 };
381 - return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
382 + int timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner,
383 + he, dh);
384 + if (timeout < 0)
385 + timeout = 0;
386 + return timeout;
387 }