summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Slater <joe.slater@windriver.com>2021-09-07 12:00:02 -0700
committerArmin Kuster <akuster808@gmail.com>2021-09-07 12:53:53 -0700
commitcea26b8482b83eda18370406f8d59cf63436b5ba (patch)
tree9e431bd3399e44da7a07f1abddab8b31f058be54
parent32f1d758a14bba35d67a75778ae747f1ff5c5482 (diff)
downloadmeta-openembedded-cea26b8482b83eda18370406f8d59cf63436b5ba.tar.gz
redis: fix CVE-2021-32761
Backport from version 6.2.5. Signed-off-by: Joe Slater <joe.slater@windriver.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch257
-rw-r--r--meta-oe/recipes-extended/redis/redis_6.2.2.bb1
2 files changed, 258 insertions, 0 deletions
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch
new file mode 100644
index 0000000000..14992b789a
--- /dev/null
+++ b/meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch
@@ -0,0 +1,257 @@
1From 835d15b5360e277e6f95529c4d8685946a977ddd Mon Sep 17 00:00:00 2001
2From: Huang Zhw <huang_zhw@126.com>
3Date: Wed, 21 Jul 2021 21:25:19 +0800
4Subject: [PATCH 1/1] On 32 bit platform, the bit position of
5 GETBIT/SETBIT/BITFIELD/BITCOUNT,BITPOS may overflow (see CVE-2021-32761)
6 (#9191)
7
8GETBIT, SETBIT may access wrong address because of wrap.
9BITCOUNT and BITPOS may return wrapped results.
10BITFIELD may access the wrong address but also allocate insufficient memory and segfault (see CVE-2021-32761).
11
12This commit uses `uint64_t` or `long long` instead of `size_t`.
13related https://github.com/redis/redis/pull/8096
14
15At 32bit platform:
16> setbit bit 4294967295 1
17(integer) 0
18> config set proto-max-bulk-len 536870913
19OK
20> append bit "\xFF"
21(integer) 536870913
22> getbit bit 4294967296
23(integer) 0
24
25When the bit index is larger than 4294967295, size_t can't hold bit index. In the past, `proto-max-bulk-len` is limit to 536870912, so there is no problem.
26
27After this commit, bit position is stored in `uint64_t` or `long long`. So when `proto-max-bulk-len > 536870912`, 32bit platforms can still be correct.
28
29For 64bit platform, this problem still exists. The major reason is bit pos 8 times of byte pos. When proto-max-bulk-len is very larger, bit pos may overflow.
30But at 64bit platform, we don't have so long string. So this bug may never happen.
31
32Additionally this commit add a test cost `512MB` memory which is tag as `large-memory`. Make freebsd ci and valgrind ci ignore this test.
33
34(cherry picked from commit 71d452876ebf8456afaadd6b3c27988abadd1148)d
35---
36
37CVE: CVE-2021-32761
38
39Upstream-Status: Backport [835d15b5360e277e6f95529c4d8685946a977ddd]
40 https://github.com/redis/redis.git
41
42Signed-off-by: Joe Slater <joe.slater@windriver.com>
43
44---
45 .github/workflows/daily.yml | 6 +++---
46 src/bitops.c | 32 ++++++++++++++++----------------
47 src/server.h | 2 +-
48 tests/unit/bitops.tcl | 28 ++++++++++++++++++++++++++++
49 4 files changed, 48 insertions(+), 20 deletions(-)
50
51diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml
52index 9e4630e29..432971a9d 100644
53--- a/.github/workflows/daily.yml
54+++ b/.github/workflows/daily.yml
55@@ -151,7 +151,7 @@ jobs:
56 run: |
57 sudo apt-get update
58 sudo apt-get install tcl8.6 valgrind -y
59- ./runtest --valgrind --verbose --clients 1 --dump-logs
60+ ./runtest --valgrind --verbose --clients 1 --tags -large-memory --dump-logs
61 - name: module api test
62 run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
63 - name: unittest
64@@ -171,7 +171,7 @@ jobs:
65 run: |
66 sudo apt-get update
67 sudo apt-get install tcl8.6 valgrind -y
68- ./runtest --valgrind --verbose --clients 1 --dump-logs
69+ ./runtest --valgrind --verbose --clients 1 --tags -large-memory --dump-logs
70 - name: module api test
71 run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
72
73@@ -260,7 +260,7 @@ jobs:
74 prepare: pkg install -y bash gmake lang/tcl86
75 run: >
76 gmake &&
77- ./runtest --accurate --verbose --no-latency --dump-logs &&
78+ ./runtest --accurate --verbose --no-latency --tags -large-memory --dump-logs &&
79 MAKE=gmake ./runtest-moduleapi --verbose &&
80 ./runtest-sentinel &&
81 ./runtest-cluster
82diff --git a/src/bitops.c b/src/bitops.c
83index afd79ad88..f1c563a41 100644
84--- a/src/bitops.c
85+++ b/src/bitops.c
86@@ -37,8 +37,8 @@
87 /* Count number of bits set in the binary array pointed by 's' and long
88 * 'count' bytes. The implementation of this function is required to
89 * work with an input string length up to 512 MB or more (server.proto_max_bulk_len) */
90-size_t redisPopcount(void *s, long count) {
91- size_t bits = 0;
92+long long redisPopcount(void *s, long count) {
93+ long long bits = 0;
94 unsigned char *p = s;
95 uint32_t *p4;
96 static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
97@@ -98,11 +98,11 @@ size_t redisPopcount(void *s, long count) {
98 * no zero bit is found, it returns count*8 assuming the string is zero
99 * padded on the right. However if 'bit' is 1 it is possible that there is
100 * not a single set bit in the bitmap. In this special case -1 is returned. */
101-long redisBitpos(void *s, unsigned long count, int bit) {
102+long long redisBitpos(void *s, unsigned long count, int bit) {
103 unsigned long *l;
104 unsigned char *c;
105 unsigned long skipval, word = 0, one;
106- long pos = 0; /* Position of bit, to return to the caller. */
107+ long long pos = 0; /* Position of bit, to return to the caller. */
108 unsigned long j;
109 int found;
110
111@@ -410,7 +410,7 @@ void printBits(unsigned char *p, unsigned long count) {
112 * If the 'hash' argument is true, and 'bits is positive, then the command
113 * will also parse bit offsets prefixed by "#". In such a case the offset
114 * is multiplied by 'bits'. This is useful for the BITFIELD command. */
115-int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int bits) {
116+int getBitOffsetFromArgument(client *c, robj *o, uint64_t *offset, int hash, int bits) {
117 long long loffset;
118 char *err = "bit offset is not an integer or out of range";
119 char *p = o->ptr;
120@@ -435,7 +435,7 @@ int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int b
121 return C_ERR;
122 }
123
124- *offset = (size_t)loffset;
125+ *offset = loffset;
126 return C_OK;
127 }
128
129@@ -477,7 +477,7 @@ int getBitfieldTypeFromArgument(client *c, robj *o, int *sign, int *bits) {
130 * so that the 'maxbit' bit can be addressed. The object is finally
131 * returned. Otherwise if the key holds a wrong type NULL is returned and
132 * an error is sent to the client. */
133-robj *lookupStringForBitCommand(client *c, size_t maxbit) {
134+robj *lookupStringForBitCommand(client *c, uint64_t maxbit) {
135 size_t byte = maxbit >> 3;
136 robj *o = lookupKeyWrite(c->db,c->argv[1]);
137 if (checkType(c,o,OBJ_STRING)) return NULL;
138@@ -527,7 +527,7 @@ unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) {
139 void setbitCommand(client *c) {
140 robj *o;
141 char *err = "bit is not an integer or out of range";
142- size_t bitoffset;
143+ uint64_t bitoffset;
144 ssize_t byte, bit;
145 int byteval, bitval;
146 long on;
147@@ -566,7 +566,7 @@ void setbitCommand(client *c) {
148 void getbitCommand(client *c) {
149 robj *o;
150 char llbuf[32];
151- size_t bitoffset;
152+ uint64_t bitoffset;
153 size_t byte, bit;
154 size_t bitval = 0;
155
156@@ -888,7 +888,7 @@ void bitposCommand(client *c) {
157 addReplyLongLong(c, -1);
158 } else {
159 long bytes = end-start+1;
160- long pos = redisBitpos(p+start,bytes,bit);
161+ long long pos = redisBitpos(p+start,bytes,bit);
162
163 /* If we are looking for clear bits, and the user specified an exact
164 * range with start-end, we can't consider the right of the range as
165@@ -897,11 +897,11 @@ void bitposCommand(client *c) {
166 * So if redisBitpos() returns the first bit outside the range,
167 * we return -1 to the caller, to mean, in the specified range there
168 * is not a single "0" bit. */
169- if (end_given && bit == 0 && pos == bytes*8) {
170+ if (end_given && bit == 0 && pos == (long long)bytes<<3) {
171 addReplyLongLong(c,-1);
172 return;
173 }
174- if (pos != -1) pos += start*8; /* Adjust for the bytes we skipped. */
175+ if (pos != -1) pos += (long long)start<<3; /* Adjust for the bytes we skipped. */
176 addReplyLongLong(c,pos);
177 }
178 }
179@@ -933,12 +933,12 @@ struct bitfieldOp {
180 * GET subcommand is allowed, other subcommands will return an error. */
181 void bitfieldGeneric(client *c, int flags) {
182 robj *o;
183- size_t bitoffset;
184+ uint64_t bitoffset;
185 int j, numops = 0, changes = 0;
186 struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */
187 int owtype = BFOVERFLOW_WRAP; /* Overflow type. */
188 int readonly = 1;
189- size_t highest_write_offset = 0;
190+ uint64_t highest_write_offset = 0;
191
192 for (j = 2; j < c->argc; j++) {
193 int remargs = c->argc-j-1; /* Remaining args other than current. */
194@@ -1128,9 +1128,9 @@ void bitfieldGeneric(client *c, int flags) {
195 * object boundaries. */
196 memset(buf,0,9);
197 int i;
198- size_t byte = thisop->offset >> 3;
199+ uint64_t byte = thisop->offset >> 3;
200 for (i = 0; i < 9; i++) {
201- if (src == NULL || i+byte >= (size_t)strlen) break;
202+ if (src == NULL || i+byte >= (uint64_t)strlen) break;
203 buf[i] = src[i+byte];
204 }
205
206diff --git a/src/server.h b/src/server.h
207index 67541fe60..caf9df31c 100644
208--- a/src/server.h
209+++ b/src/server.h
210@@ -1795,7 +1795,7 @@ void getRandomHexChars(char *p, size_t len);
211 void getRandomBytes(unsigned char *p, size_t len);
212 uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
213 void exitFromChild(int retcode);
214-size_t redisPopcount(void *s, long count);
215+long long redisPopcount(void *s, long count);
216 int redisSetProcTitle(char *title);
217 int validateProcTitleTemplate(const char *template);
218 int redisCommunicateSystemd(const char *sd_notify_msg);
219diff --git a/tests/unit/bitops.tcl b/tests/unit/bitops.tcl
220index 926f38295..534832974 100644
221--- a/tests/unit/bitops.tcl
222+++ b/tests/unit/bitops.tcl
223@@ -349,3 +349,31 @@ start_server {tags {"bitops"}} {
224 }
225 }
226 }
227+
228+start_server {tags {"bitops large-memory"}} {
229+ test "BIT pos larger than UINT_MAX" {
230+ set bytes [expr (1 << 29) + 1]
231+ set bitpos [expr (1 << 32)]
232+ set oldval [lindex [r config get proto-max-bulk-len] 1]
233+ r config set proto-max-bulk-len $bytes
234+ r setbit mykey $bitpos 1
235+ assert_equal $bytes [r strlen mykey]
236+ assert_equal 1 [r getbit mykey $bitpos]
237+ assert_equal [list 128 128 -1] [r bitfield mykey get u8 $bitpos set u8 $bitpos 255 get i8 $bitpos]
238+ assert_equal $bitpos [r bitpos mykey 1]
239+ assert_equal $bitpos [r bitpos mykey 1 [expr $bytes - 1]]
240+ if {$::accurate} {
241+ # set all bits to 1
242+ set mega [expr (1 << 23)]
243+ set part [string repeat "\xFF" $mega]
244+ for {set i 0} {$i < 64} {incr i} {
245+ r setrange mykey [expr $i * $mega] $part
246+ }
247+ r setrange mykey [expr $bytes - 1] "\xFF"
248+ assert_equal [expr $bitpos + 8] [r bitcount mykey]
249+ assert_equal -1 [r bitpos mykey 0 0 [expr $bytes - 1]]
250+ }
251+ r config set proto-max-bulk-len $oldval
252+ r del mykey
253+ } {1}
254+}
255--
2562.24.1
257
diff --git a/meta-oe/recipes-extended/redis/redis_6.2.2.bb b/meta-oe/recipes-extended/redis/redis_6.2.2.bb
index a9e6eaffaa..ad675e9e04 100644
--- a/meta-oe/recipes-extended/redis/redis_6.2.2.bb
+++ b/meta-oe/recipes-extended/redis/redis_6.2.2.bb
@@ -19,6 +19,7 @@ SRC_URI = "http://download.redis.io/releases/${BP}.tar.gz \
19 file://fix-CVE-2021-29477.patch \ 19 file://fix-CVE-2021-29477.patch \
20 file://fix-CVE-2021-29478.patch \ 20 file://fix-CVE-2021-29478.patch \
21 file://fix-CVE-2021-32625.patch \ 21 file://fix-CVE-2021-32625.patch \
22 file://CVE-2021-32761.patch \
22 " 23 "
23SRC_URI[sha256sum] = "7a260bb74860f1b88c3d5942bf8ba60ca59f121c6dce42d3017bed6add0b9535" 24SRC_URI[sha256sum] = "7a260bb74860f1b88c3d5942bf8ba60ca59f121c6dce42d3017bed6add0b9535"
24 25