Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 05 Feb 2026 14:45:46 +0000
From:      Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 5fc739eb5949 - main - diff: Fix integer overflows in Stone algorithm
Message-ID:  <6984ad1a.3be1d.60ebf0ea@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=5fc739eb5949620da911db2f87ca8faedc549d3a

commit 5fc739eb5949620da911db2f87ca8faedc549d3a
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-02-05 14:39:43 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-02-05 14:39:43 +0000

    diff: Fix integer overflows in Stone algorithm
    
    Fix integer overflows that may occur when the context window is very
    large and add tests to exercise those conditions.
    
    PR:             267032
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    thj, kevans
    Differential Revision:  https://reviews.freebsd.org/D55110
---
 usr.bin/diff/diffreg.c          | 32 +++++++++++++++++++++-----------
 usr.bin/diff/tests/diff_test.sh | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 11 deletions(-)

diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c
index ffa5568bf442..91ae5ee6591a 100644
--- a/usr.bin/diff/diffreg.c
+++ b/usr.bin/diff/diffreg.c
@@ -77,6 +77,7 @@
 #include <paths.h>
 #include <regex.h>
 #include <stdbool.h>
+#include <stdckdint.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -1056,7 +1057,7 @@ change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d,
 {
 	static size_t max_context = 64;
 	long curpos;
-	int i, nc;
+	int dist, i, nc;
 	const char *walk;
 	bool skip_blanks, ignore;
 
@@ -1120,8 +1121,9 @@ proceed:
 			 */
 			print_header(file1, file2);
 			anychange = 1;
-		} else if (a > context_vec_ptr->b + (2 * diff_context) + 1 &&
-		    c > context_vec_ptr->d + (2 * diff_context) + 1) {
+		} else if (!ckd_add(&dist, diff_context, diff_context) &&
+		    a - context_vec_ptr->b - 1 > dist &&
+		    c - context_vec_ptr->d - 1 > dist) {
 			/*
 			 * If this change is more than 'diff_context' lines from the
 			 * previous change, dump the record and reset it.
@@ -1506,10 +1508,14 @@ dump_context_vec(FILE *f1, FILE *f2, int flags)
 		return;
 
 	b = d = 0;		/* gcc */
-	lowa = MAX(1, cvp->a - diff_context);
-	upb = MIN((int)len[0], context_vec_ptr->b + diff_context);
-	lowc = MAX(1, cvp->c - diff_context);
-	upd = MIN((int)len[1], context_vec_ptr->d + diff_context);
+	if (ckd_sub(&lowa, cvp->a, diff_context) || lowa < 1)
+		lowa = 1;
+	if (ckd_add(&upb, context_vec_ptr->b, diff_context) || upb > (int)len[0])
+		upb = (int)len[0];
+	if (ckd_sub(&lowc, cvp->c, diff_context) || lowc < 1)
+		lowc = 1;
+	if (ckd_add(&upd, context_vec_ptr->d, diff_context) || upd > (int)len[1])
+		upd = (int)len[1];
 
 	printf("***************");
 	if (flags & (D_PROTOTYPE | D_MATCHLAST)) {
@@ -1609,10 +1615,14 @@ dump_unified_vec(FILE *f1, FILE *f2, int flags)
 		return;
 
 	b = d = 0;		/* gcc */
-	lowa = MAX(1, cvp->a - diff_context);
-	upb = MIN((int)len[0], context_vec_ptr->b + diff_context);
-	lowc = MAX(1, cvp->c - diff_context);
-	upd = MIN((int)len[1], context_vec_ptr->d + diff_context);
+	if (ckd_sub(&lowa, cvp->a, diff_context) || lowa < 1)
+		lowa = 1;
+	if (ckd_add(&upb, context_vec_ptr->b, diff_context) || upb > (int)len[0])
+		upb = (int)len[0];
+	if (ckd_sub(&lowc, cvp->c, diff_context) || lowc < 1)
+		lowc = 1;
+	if (ckd_add(&upd, context_vec_ptr->d, diff_context) || upd > (int)len[1])
+		upd = (int)len[1];
 
 	printf("@@ -");
 	uni_range(lowa, upb);
diff --git a/usr.bin/diff/tests/diff_test.sh b/usr.bin/diff/tests/diff_test.sh
index 691b649813a1..89348d3a8b16 100755
--- a/usr.bin/diff/tests/diff_test.sh
+++ b/usr.bin/diff/tests/diff_test.sh
@@ -24,6 +24,7 @@ atf_test_case functionname
 atf_test_case noderef
 atf_test_case ignorecase
 atf_test_case dirloop
+atf_test_case verylong
 
 simple_body()
 {
@@ -380,6 +381,36 @@ dirloop_body()
 	    diff -r a b
 }
 
+bigc_head()
+{
+	atf_set "descr" "Context diff with very large context"
+}
+bigc_body()
+{
+	echo $'x\na\ny' >a
+	echo $'x\nb\ny' >b
+	atf_check -s exit:2 -e ignore diff -C$(((1<<31)-1)) a b
+	atf_check -s exit:1 -o match:'--- 1,3 ---' \
+	    diff -C$(((1<<31)-2)) a b
+	atf_check -s exit:1 -o match:'--- 1,3 ---' \
+	    diff -Astone -C$(((1<<31)-2)) a b
+}
+
+bigu_head()
+{
+	atf_set "descr" "Unified diff with very large context"
+}
+bigu_body()
+{
+	echo $'x\na\ny' >a
+	echo $'x\nb\ny' >b
+	atf_check -s exit:2 -e ignore diff -U$(((1<<31)-1)) a b
+	atf_check -s exit:1 -o match:'^@@ -1,3 \+1,3 @@$' \
+	    diff -U$(((1<<31)-2)) a b
+	atf_check -s exit:1 -o match:'^@@ -1,3 \+1,3 @@$' \
+	    diff -Astone -U$(((1<<31)-2)) a b
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case simple
@@ -407,4 +438,6 @@ atf_init_test_cases()
 	atf_add_test_case noderef
 	atf_add_test_case ignorecase
 	atf_add_test_case dirloop
+	atf_add_test_case bigc
+	atf_add_test_case bigu
 }


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6984ad1a.3be1d.60ebf0ea>