summaryrefslogtreecommitdiff
path: root/sys-apps/coreutils/files/coreutils-9.8-basenc-base58.patch
blob: d8ccb11a81fa1d5cdb708c4468fea5081c102c7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
https://cgit.git.savannah.gnu.org/cgit/coreutils.git/commit/?id=2ef53e5b0477f9d9361a11a471d704a96b1c99b8
(Dropped the test to avoid autoreconf.)

From 2ef53e5b0477f9d9361a11a471d704a96b1c99b8 Mon Sep 17 00:00:00 2001
From: Pádraig Brady <P@draigBrady.com>
Date: Tue, 23 Sep 2025 15:38:51 +0100
Subject: basenc: --base58: fix buffer overflow with input > 15MB

base58_length() operated naively on an int
which resulted in an overflow to a negative number
for any input > 2^31-1/138, i.e. 15,561,475 bytes.

* src/basenc.c (base_length): Change input and output
parameter types from int to idx_t since this needs to
cater for the full input size in the base58 case.
(base58_length): Likewise.  Also reorder the calculation
to be less exact, but doing the division first
to minimize the chance of overflow (which now on 64 bit
would only happen for inputs > around 6 Exa bytes).
* tests/basenc/basenc-large.sh: Add a new test,
that triggers with valgrind or ASAN.
* tests/local.mk: Reference the new test.
* NEWS: Mention the bug fix.
---
 src/basenc.c                 | 43 +++++++++++++++++++++++++------------------
 4 files changed, 58 insertions(+), 18 deletions(-)
 create mode 100755 tests/basenc/basenc-large.sh

diff --git a/src/basenc.c b/src/basenc.c
index 1fb7a16f5..ae55f8e32 100644
--- a/src/basenc.c
+++ b/src/basenc.c
@@ -253,7 +253,7 @@ static_assert (DEC_BLOCKSIZE % 12 == 0); /* Complete encoded blocks are used. */
 static_assert (DEC_BLOCKSIZE % 40 == 0); /* complete encoded blocks for base32*/
 static_assert (DEC_BLOCKSIZE % 12 == 0); /* complete encoded blocks for base64*/
 
-static int (*base_length) (int i);
+static idx_t (*base_length) (idx_t len);
 static int (*required_padding) (int i);
 static bool (*isubase) (unsigned char ch);
 static void (*base_encode) (char const *restrict in, idx_t inlen,
@@ -427,8 +427,8 @@ decode_ctx_finalize (struct base_decode_context *ctx,
 
 #if BASE_TYPE == 42
 
-static int
-base64_length_wrapper (int len)
+static idx_t
+base64_length_wrapper (idx_t len)
 {
   return BASE64_LENGTH (len);
 }
@@ -526,8 +526,8 @@ base64url_decode_ctx_wrapper (struct base_decode_context *ctx,
 
 
 
-static int
-base32_length_wrapper (int len)
+static idx_t
+base32_length_wrapper (idx_t len)
 {
   return BASE32_LENGTH (len);
 }
@@ -740,8 +740,8 @@ isubase16 (unsigned char ch)
   return ch < sizeof base16_to_int && 0 <= base16_to_int[ch];
 }
 
-static int
-base16_length (int len)
+static idx_t
+base16_length (idx_t len)
 {
   return len * 2;
 }
@@ -820,13 +820,14 @@ base16_decode_ctx (struct base_decode_context *ctx,
 
 
 
-
-static int
-z85_length (int len)
+ATTRIBUTE_PURE
+static idx_t
+z85_length (idx_t len)
 {
   /* Z85 does not allow padding, so no need to round to highest integer.  */
-  int outlen = (len * 5) / 4;
-  return outlen;
+  idx_t z85_len = (len * 5) / 4;
+  affirm (0 <= z85_len);
+  return z85_len;
 }
 
 static bool
@@ -1015,8 +1016,8 @@ isubase2 (unsigned char ch)
   return ch == '0' || ch == '1';
 }
 
-static int
-base2_length (int len)
+static idx_t
+base2_length (idx_t len)
 {
   return len * 8;
 }
@@ -1206,12 +1207,17 @@ isubase58 (unsigned char ch)
 }
 
 
-static int
-base58_length (int len)
+ATTRIBUTE_PURE
+static idx_t
+base58_length (idx_t len)
 {
   /* Base58 output length is approximately log(256)/log(58),
-     so ensure we've enough place for that + NUL.  */
-  return (len * 138) / 100 + 1;
+     which is approximately len * 138 / 100,
+     which is at most ((len + 100 - 1) / 100) * 138
+     +1 to ensure we've enough place for NUL  */
+  idx_t base58_len = ((len + 99) / 100) * 138 + 1;
+  affirm (0 < base58_len);
+  return base58_len;
 }
 
 
@@ -1268,6 +1274,7 @@ base58_encode (char const* data, size_t data_len,
   if (data_len - zeros)
     {
       mpz_import (num, data_len - zeros, 1, 1, 0, 0, data + zeros);
+      affirm (mpz_sizeinbase (num, 58) + 1 <= *outlen);
       for (p = mpz_get_str (p, 58, num); *p; p++)
         *p = gmp_to_base58[to_uchar (*p)];
     }
-- 
cgit v1.2.3