git: 3501eec9dd39 - main - libc: Guard mergesort() allocation size arithmetic

From: Robert Clausecker <fuz_at_FreeBSD.org>
Date: Sun, 07 Jun 2026 21:00:55 UTC
The branch main has been updated by fuz:

URL: https://cgit.FreeBSD.org/src/commit/?id=3501eec9dd39b527a46e82de53480968d283b90e

commit 3501eec9dd39b527a46e82de53480968d283b90e
Author:     Faraz Vahedi <kfv@kfv.io>
AuthorDate: 2026-05-28 13:50:45 +0000
Commit:     Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2026-06-07 20:59:18 +0000

    libc: Guard mergesort() allocation size arithmetic
    
    Signed-off-by:  Faraz Vahedi <kfv@kfv.io>
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2243
    Reviewed by:    fuz
    MFC after:      1 week
---
 lib/libc/stdlib/merge.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
index e70938088589..e07a3947e741 100644
--- a/lib/libc/stdlib/merge.c
+++ b/lib/libc/stdlib/merge.c
@@ -49,6 +49,7 @@
 #include <sys/param.h>
 
 #include <errno.h>
+#include <stdckdint.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -109,7 +110,7 @@ mergesort_b(void *base, size_t nmemb, size_t size, cmp_t cmp)
 mergesort(void *base, size_t nmemb, size_t size, cmp_t cmp)
 #endif
 {
-	size_t i;
+	size_t i, nbytes, asize;
 	int sense;
 	int big, iflag;
 	u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
@@ -123,16 +124,21 @@ mergesort(void *base, size_t nmemb, size_t size, cmp_t cmp)
 	if (nmemb == 0)
 		return (0);
 
+	if (ckd_mul(&nbytes, nmemb, size) || ckd_add(&asize, nbytes, PSIZE)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
 	iflag = 0;
 	if (__is_aligned(size, ISIZE) && __is_aligned(base, ISIZE))
 		iflag = 1;
 
-	if ((list2 = malloc(nmemb * size + PSIZE)) == NULL)
+	if ((list2 = malloc(asize)) == NULL)
 		return (-1);
 
 	list1 = base;
 	setup(list1, list2, nmemb, size, cmp);
-	last = list2 + nmemb * size;
+	last = list2 + nbytes;
 	i = big = 0;
 	while (*EVAL(list2) != last) {
 	    l2 = list1;
@@ -227,10 +233,10 @@ COPY:	    			b = t;
 	    tp2 = list1;	/* swap list1, list2 */
 	    list1 = list2;
 	    list2 = tp2;
-	    last = list2 + nmemb*size;
+	    last = list2 + nbytes;
 	}
 	if (base == list2) {
-		memmove(list2, list1, nmemb*size);
+		memmove(list2, list1, nbytes);
 		list2 = list1;
 	}
 	free(list2);