/*
* Reallocate memory buffer if read pointer differs
+ * NOT FOR RDONLY
*/
static int mem_buf_sync(BIO *b)
{
long ret = 1;
char **pptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
- BUF_MEM *bm;
+ BUF_MEM *bm, *bo; /* bio_mem, bio_other */
+ long off, remain;
- if (b->flags & BIO_FLAGS_MEM_RDONLY)
+ if (b->flags & BIO_FLAGS_MEM_RDONLY) {
bm = bbm->buf;
- else
+ bo = bbm->readp;
+ } else {
bm = bbm->readp;
+ bo = bbm->buf;
+ }
+ off = bm->data - bo->data;
+ remain = bm->length;
switch (cmd) {
case BIO_CTRL_RESET:
}
}
break;
+ case BIO_C_FILE_SEEK:
+ if (num < 0 || num > off + remain)
+ return -1; /* Can't see outside of the current buffer */
+
+ bm->data = bo->data + num;
+ bm->length = bo->length - num;
+ bm->max = bo->max - num;
+ off = num;
+ /* FALLTHRU */
+ case BIO_C_FILE_TELL:
+ ret = off;
+ break;
case BIO_CTRL_EOF:
ret = (long)(bm->length == 0);
break;
&& !OSSL_DESERIALIZER_is_a(deser, new_deser_inst->input_type))
continue;
- if (loc == 0) {
- if (BIO_reset(bio) <= 0)
- goto end;
- } else {
- if (BIO_seek(bio, loc) <= 0)
- goto end;
- }
+ /*
+ * Checking the return value of BIO_reset() or BIO_seek() is unsafe.
+ * Furthermore, BIO_reset() is unsafe to use if the source BIO happens
+ * to be a BIO_s_mem(), because the earlier BIO_tell() gives us zero
+ * no matter where we are in the underlying buffer we're reading from.
+ *
+ * So, we simply do a BIO_seek(), and use BIO_tell() that we're back
+ * at the same position. This is a best effort attempt, but BIO_seek()
+ * and BIO_tell() should come as a pair...
+ */
+ (void)BIO_seek(bio, loc);
+ if (BIO_tell(bio) != loc)
+ goto end;
/* Recurse */
new_data.current_deser_inst_index = i;