git: 2ae615c4f1d0 - stable/13 - diff: Fix integer overflows in Stone algorithm
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 10 Feb 2026 15:28:14 UTC
The branch stable/13 has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=2ae615c4f1d0c29984caac73d72091be8c41358f
commit 2ae615c4f1d0c29984caac73d72091be8c41358f
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-10 14:24:30 +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
(cherry picked from commit 5fc739eb5949620da911db2f87ca8faedc549d3a)
---
usr.bin/diff/diffreg.c | 32 +++++++++++++++++++++-----------
usr.bin/diff/tests/diff_test.sh | 30 ++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 11 deletions(-)
diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c
index fb01fa24a281..ea7732bb6d99 100644
--- a/usr.bin/diff/diffreg.c
+++ b/usr.bin/diff/diffreg.c
@@ -78,6 +78,7 @@
#include <paths.h>
#include <regex.h>
#include <stdbool.h>
+#include <stdckdint.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -1064,7 +1065,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;
@@ -1125,8 +1126,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.
@@ -1490,10 +1492,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)) {
@@ -1593,10 +1599,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 027febf69f64..8b8846925ee8 100755
--- a/usr.bin/diff/tests/diff_test.sh
+++ b/usr.bin/diff/tests/diff_test.sh
@@ -20,6 +20,8 @@ atf_test_case report_identical
atf_test_case non_regular_file
atf_test_case binary
atf_test_case dirloop
+atf_test_case bigc
+atf_test_case bigu
simple_body()
{
@@ -300,6 +302,32 @@ 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
+}
+
+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_init_test_cases()
{
atf_add_test_case simple
@@ -323,4 +351,6 @@ atf_init_test_cases()
atf_add_test_case non_regular_file
atf_add_test_case binary
atf_add_test_case dirloop
+ atf_add_test_case bigc
+ atf_add_test_case bigu
}