summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2022-02-19 15:59:12 +0000
committerjsing <>2022-02-19 15:59:12 +0000
commit25a9629e43e037feecbfc10137ec9671aac8194a (patch)
tree0d7dce316bfd02d76d70207678ebbaff2d3d10b6 /src
parent486359b287c701ccfeaf658337192a78b563e4b4 (diff)
downloadopenbsd-25a9629e43e037feecbfc10137ec9671aac8194a.tar.gz
openbsd-25a9629e43e037feecbfc10137ec9671aac8194a.tar.bz2
openbsd-25a9629e43e037feecbfc10137ec9671aac8194a.zip
Reduce memmoves in memory BIOs.
Currently, a read/write memory BIO pulls up the data via memmove() on each read. This becomes very expensive when a lot of small reads are performed, especially if there is a reasonable amount of data stored in the memory BIO. Instead, store a read offset into the buffer and only perform a memmove() to pull up the data on a write, if we have read more than 4096 bytes. This way we only perform memmove() when the space saving will potentially be of benefit, while avoiding frequent memmove() in the case of small interleaved reads and writes. Should address oss-fuzz #19881. ok inoguchi@ tb@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/bio/bss_mem.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/src/lib/libcrypto/bio/bss_mem.c b/src/lib/libcrypto/bio/bss_mem.c
index 6100a1861e..2d03083235 100644
--- a/src/lib/libcrypto/bio/bss_mem.c
+++ b/src/lib/libcrypto/bio/bss_mem.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: bss_mem.c,v 1.20 2022/02/19 08:11:16 jsing Exp $ */ 1/* $OpenBSD: bss_mem.c,v 1.21 2022/02/19 15:59:12 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -69,8 +69,24 @@
69 69
70struct bio_mem { 70struct bio_mem {
71 BUF_MEM *buf; 71 BUF_MEM *buf;
72 size_t read_offset;
72}; 73};
73 74
75static size_t
76bio_mem_pending(struct bio_mem *bm)
77{
78 if (bm->read_offset > bm->buf->length)
79 return 0;
80
81 return bm->buf->length - bm->read_offset;
82}
83
84static uint8_t *
85bio_mem_read_ptr(struct bio_mem *bm)
86{
87 return &bm->buf->data[bm->read_offset];
88}
89
74static int mem_new(BIO *bio); 90static int mem_new(BIO *bio);
75static int mem_free(BIO *bio); 91static int mem_free(BIO *bio);
76static int mem_write(BIO *bio, const char *in, int in_len); 92static int mem_write(BIO *bio, const char *in, int in_len);
@@ -185,8 +201,8 @@ mem_read(BIO *bio, char *out, int out_len)
185 if (out == NULL || out_len <= 0) 201 if (out == NULL || out_len <= 0)
186 return 0; 202 return 0;
187 203
188 if ((size_t)out_len > bm->buf->length) 204 if ((size_t)out_len > bio_mem_pending(bm))
189 out_len = bm->buf->length; 205 out_len = bio_mem_pending(bm);
190 206
191 if (out_len == 0) { 207 if (out_len == 0) {
192 if (bio->num != 0) 208 if (bio->num != 0)
@@ -194,14 +210,9 @@ mem_read(BIO *bio, char *out, int out_len)
194 return bio->num; 210 return bio->num;
195 } 211 }
196 212
197 memcpy(out, bm->buf->data, out_len); 213 memcpy(out, bio_mem_read_ptr(bm), out_len);
198 bm->buf->length -= out_len; 214 bm->read_offset += out_len;
199 if (bio->flags & BIO_FLAGS_MEM_RDONLY) { 215
200 bm->buf->data += out_len;
201 } else {
202 memmove(&(bm->buf->data[0]), &(bm->buf->data[out_len]),
203 bm->buf->length);
204 }
205 return out_len; 216 return out_len;
206} 217}
207 218
@@ -221,6 +232,13 @@ mem_write(BIO *bio, const char *in, int in_len)
221 return -1; 232 return -1;
222 } 233 }
223 234
235 if (bm->read_offset > 4096) {
236 memmove(bm->buf->data, bio_mem_read_ptr(bm),
237 bio_mem_pending(bm));
238 bm->buf->length = bio_mem_pending(bm);
239 bm->read_offset = 0;
240 }
241
224 /* 242 /*
225 * Check for overflow and ensure we do not exceed an int, otherwise we 243 * Check for overflow and ensure we do not exceed an int, otherwise we
226 * cannot tell if BUF_MEM_grow_clean() succeeded. 244 * cannot tell if BUF_MEM_grow_clean() succeeded.
@@ -247,18 +265,15 @@ mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
247 switch (cmd) { 265 switch (cmd) {
248 case BIO_CTRL_RESET: 266 case BIO_CTRL_RESET:
249 if (bm->buf->data != NULL) { 267 if (bm->buf->data != NULL) {
250 /* For read only case reset to the start again */ 268 if (!(bio->flags & BIO_FLAGS_MEM_RDONLY)) {
251 if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
252 bm->buf->data -= bm->buf->max - bm->buf->length;
253 bm->buf->length = bm->buf->max;
254 } else {
255 memset(bm->buf->data, 0, bm->buf->max); 269 memset(bm->buf->data, 0, bm->buf->max);
256 bm->buf->length = 0; 270 bm->buf->length = 0;
257 } 271 }
272 bm->read_offset = 0;
258 } 273 }
259 break; 274 break;
260 case BIO_CTRL_EOF: 275 case BIO_CTRL_EOF:
261 ret = (long)(bm->buf->length == 0); 276 ret = (long)(bio_mem_pending(bm) == 0);
262 break; 277 break;
263 case BIO_C_SET_BUF_MEM_EOF_RETURN: 278 case BIO_C_SET_BUF_MEM_EOF_RETURN:
264 bio->num = (int)num; 279 bio->num = (int)num;
@@ -266,14 +281,15 @@ mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
266 case BIO_CTRL_INFO: 281 case BIO_CTRL_INFO:
267 if (ptr != NULL) { 282 if (ptr != NULL) {
268 pptr = (void **)ptr; 283 pptr = (void **)ptr;
269 *pptr = bm->buf->data; 284 *pptr = bio_mem_read_ptr(bm);
270 } 285 }
271 ret = (long)bm->buf->length; 286 ret = (long)bio_mem_pending(bm);
272 break; 287 break;
273 case BIO_C_SET_BUF_MEM: 288 case BIO_C_SET_BUF_MEM:
274 BUF_MEM_free(bm->buf); 289 BUF_MEM_free(bm->buf);
275 bio->shutdown = (int)num; 290 bio->shutdown = (int)num;
276 bm->buf = ptr; 291 bm->buf = ptr;
292 bm->read_offset = 0;
277 break; 293 break;
278 case BIO_C_GET_BUF_MEM_PTR: 294 case BIO_C_GET_BUF_MEM_PTR:
279 if (ptr != NULL) { 295 if (ptr != NULL) {
@@ -291,7 +307,7 @@ mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
291 ret = 0L; 307 ret = 0L;
292 break; 308 break;
293 case BIO_CTRL_PENDING: 309 case BIO_CTRL_PENDING:
294 ret = (long)bm->buf->length; 310 ret = (long)bio_mem_pending(bm);
295 break; 311 break;
296 case BIO_CTRL_DUP: 312 case BIO_CTRL_DUP:
297 case BIO_CTRL_FLUSH: 313 case BIO_CTRL_FLUSH:
@@ -316,7 +332,7 @@ mem_gets(BIO *bio, char *out, int out_len)
316 332
317 BIO_clear_retry_flags(bio); 333 BIO_clear_retry_flags(bio);
318 334
319 out_max = bm->buf->length; 335 out_max = bio_mem_pending(bm);
320 if (out_len - 1 < out_max) 336 if (out_len - 1 < out_max)
321 out_max = out_len - 1; 337 out_max = out_len - 1;
322 if (out_max <= 0) { 338 if (out_max <= 0) {
@@ -324,7 +340,7 @@ mem_gets(BIO *bio, char *out, int out_len)
324 return 0; 340 return 0;
325 } 341 }
326 342
327 p = bm->buf->data; 343 p = bio_mem_read_ptr(bm);
328 for (i = 0; i < out_max; i++) { 344 for (i = 0; i < out_max; i++) {
329 if (p[i] == '\n') { 345 if (p[i] == '\n') {
330 i++; 346 i++;