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