@@ -137,20 +137,27 @@ mongoc_compressor_name_to_id (const char *compressor)
137
137
return -1 ;
138
138
}
139
139
140
+ // To support unchecked casts from `unsigned long` to `size_t`.
141
+ BSON_STATIC_ASSERT2 (size_t_gte_ulong , SIZE_MAX >= ULONG_MAX );
142
+
140
143
bool
141
144
mongoc_uncompress (int32_t compressor_id ,
142
145
const uint8_t * compressed ,
143
146
size_t compressed_len ,
144
147
uint8_t * uncompressed ,
145
148
size_t * uncompressed_len )
146
149
{
150
+ BSON_ASSERT_PARAM (compressed );
151
+ BSON_ASSERT_PARAM (uncompressed );
152
+ BSON_ASSERT_PARAM (uncompressed_len );
153
+
147
154
TRACE ("Uncompressing with '%s' (%d)" , mongoc_compressor_id_to_name (compressor_id ), compressor_id );
148
155
149
156
switch (compressor_id ) {
150
157
case MONGOC_COMPRESSOR_SNAPPY_ID : {
151
158
#ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY
152
- snappy_status status ;
153
- status = snappy_uncompress ((const char * ) compressed , compressed_len , (char * ) uncompressed , uncompressed_len );
159
+ const snappy_status status =
160
+ snappy_uncompress ((const char * ) compressed , compressed_len , (char * ) uncompressed , uncompressed_len );
154
161
155
162
return status == SNAPPY_OK ;
156
163
#else
@@ -162,11 +169,28 @@ mongoc_uncompress (int32_t compressor_id,
162
169
163
170
case MONGOC_COMPRESSOR_ZLIB_ID : {
164
171
#ifdef MONGOC_ENABLE_COMPRESSION_ZLIB
165
- BSON_ASSERT (bson_in_range_unsigned (unsigned_long , compressed_len ));
166
- const int ok =
167
- uncompress (uncompressed , (unsigned long * ) uncompressed_len , compressed , (unsigned long ) compressed_len );
172
+ // Malformed message: unrepresentable.
173
+ if (BSON_UNLIKELY (!bson_in_range_unsigned (unsigned_long , compressed_len ))) {
174
+ return false;
175
+ }
176
+
177
+ // Malformed message: unrepresentable.
178
+ if (BSON_UNLIKELY (!bson_in_range_unsigned (unsigned_long , * uncompressed_len ))) {
179
+ return false;
180
+ }
181
+
182
+ uLong actual_uncompressed_len = (uLong ) * uncompressed_len ;
183
+
184
+ const int res =
185
+ uncompress (uncompressed , & actual_uncompressed_len , (const Bytef * ) compressed , (uLong ) compressed_len );
186
+
187
+ if (BSON_UNLIKELY (res != Z_OK )) {
188
+ return false;
189
+ }
168
190
169
- return ok == Z_OK ;
191
+ * uncompressed_len = (size_t ) actual_uncompressed_len ;
192
+
193
+ return true;
170
194
#else
171
195
MONGOC_WARNING ("Received zlib compressed opcode, but zlib "
172
196
"compression is not compiled in" );
@@ -176,22 +200,26 @@ mongoc_uncompress (int32_t compressor_id,
176
200
177
201
case MONGOC_COMPRESSOR_ZSTD_ID : {
178
202
#ifdef MONGOC_ENABLE_COMPRESSION_ZSTD
179
- int ok ;
203
+ const size_t res = ZSTD_decompress ( uncompressed , * uncompressed_len , compressed , compressed_len ) ;
180
204
181
- ok = ZSTD_decompress ((void * ) uncompressed , * uncompressed_len , (const void * ) compressed , compressed_len );
182
-
183
- if (!ZSTD_isError (ok )) {
184
- * uncompressed_len = ok ;
205
+ if (BSON_UNLIKELY (ZSTD_isError (res ))) {
206
+ return false;
185
207
}
186
208
187
- return !ZSTD_isError (ok );
209
+ * uncompressed_len = res ;
210
+
211
+ return true;
188
212
#else
189
213
MONGOC_WARNING ("Received zstd compressed opcode, but zstd "
190
214
"compression is not compiled in" );
191
215
return false;
192
216
#endif
193
217
}
194
218
case MONGOC_COMPRESSOR_NOOP_ID :
219
+ // Malformed message: not enough space.
220
+ if (BSON_UNLIKELY (* uncompressed_len < compressed_len )) {
221
+ return false;
222
+ }
195
223
memcpy (uncompressed , compressed , compressed_len );
196
224
* uncompressed_len = compressed_len ;
197
225
return true;
0 commit comments