Skip to content

Rework memory BIOs and implement BIO_seek (2nd try) #2433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 94 additions & 24 deletions crypto/bio/bio_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,18 @@

#include "../internal.h"

typedef struct bio_buf_mem_st {
struct buf_mem_st *buf; /* allocated buffer */
size_t read_off; /* read pointer offset from current buffer position */
} BIO_BUF_MEM;


BIO *BIO_new_mem_buf(const void *buf, ossl_ssize_t len) {
BIO *ret;
BUF_MEM *b;
const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len;
BIO_BUF_MEM *bbm;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'bbm' is not initialized [cppcoreguidelines-init-variables]

Suggested change
BIO_BUF_MEM *bbm;
BIO_BUF_MEM *bbm = NULL;


const size_t size = (len < 0 || (size_t)len > SIZE_MAX) ? strlen((char *)buf) : (size_t)len;

if (!buf && len != 0) {
OPENSSL_PUT_ERROR(BIO, BIO_R_NULL_PARAMETER);
Expand All @@ -81,7 +88,8 @@ BIO *BIO_new_mem_buf(const void *buf, ossl_ssize_t len) {
return NULL;
}

b = (BUF_MEM *)ret->ptr;
bbm = (BIO_BUF_MEM *)ret->ptr;
b = bbm->buf;
// BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to.
b->data = (void *)buf;
b->length = size;
Expand All @@ -98,19 +106,25 @@ BIO *BIO_new_mem_buf(const void *buf, ossl_ssize_t len) {
}

static int mem_new(BIO *bio) {
BUF_MEM *b;
BIO_BUF_MEM *bbm = OPENSSL_zalloc(sizeof(*bbm));

if (bbm == NULL) {
return 0;
}

b = BUF_MEM_new();
if (b == NULL) {
bbm->buf = BUF_MEM_new();
if (bbm->buf == NULL) {
OPENSSL_free(bbm);
return 0;
}

// |shutdown| is used to store the close flag: whether the BIO has ownership
// of the BUF_MEM.
bbm->read_off = 0;
bio->shutdown = 1;
bio->init = 1;
bio->num = -1;
bio->ptr = (char *)b;
bio->ptr = (char *)bbm;

return 1;
}
Expand All @@ -120,35 +134,53 @@ static int mem_free(BIO *bio) {
return 1;
}

BUF_MEM *b = (BUF_MEM *)bio->ptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bio->ptr;
BUF_MEM *b = bbm->buf;

if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data = NULL;
}
BUF_MEM_free(b);
bio->ptr = NULL;

OPENSSL_free(bbm);
return 1;
}

static void mem_buf_sync(BIO *bio) {
if (bio->init != 0 && bio->ptr != NULL) {
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *) bio->ptr;
BUF_MEM *b = bbm->buf;

if (b->data != NULL) {
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data += bbm->read_off;
} else {
OPENSSL_memmove(b->data, &b->data[bbm->read_off], b->length);
}
bbm->read_off = 0;
}
}
}

static int mem_read(BIO *bio, char *out, int outl) {
BIO_clear_retry_flags(bio);
if (outl <= 0) {
return 0;
}

BUF_MEM *b = bio->ptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *) bio->ptr;
BUF_MEM *b = bbm->buf;

int ret = outl;
if ((size_t)ret > b->length) {
ret = (int)b->length;
}

if (ret > 0) {
OPENSSL_memcpy(out, b->data, ret);
OPENSSL_memcpy(out, &b->data[bbm->read_off], ret);
b->length -= ret;
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data += ret;
} else {
OPENSSL_memmove(b->data, &b->data[ret], b->length);
}
bbm->read_off += ret;
} else if (b->length == 0) {
ret = bio->num;
if (ret != 0) {
Expand All @@ -169,7 +201,11 @@ static int mem_write(BIO *bio, const char *in, int inl) {
return -1;
}

BUF_MEM *b = bio->ptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *) bio->ptr;
BUF_MEM *b = bbm->buf;

mem_buf_sync(bio);

if (!BUF_MEM_append(b, in, inl)) {
return -1;
}
Expand All @@ -185,16 +221,21 @@ static int mem_gets(BIO *bio, char *buf, int size) {

// The buffer size includes space for the trailing NUL, so we can read at most
// one fewer byte.
BUF_MEM *b = bio->ptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *) bio->ptr;
BUF_MEM *b = bbm->buf;
int ret = size - 1;
if ((size_t)ret > b->length) {
ret = (int)b->length;
}

// Stop at the first newline.
const char *newline = OPENSSL_memchr(b->data, '\n', ret);
if (newline != NULL) {
ret = (int)(newline - b->data + 1);
if (b->data != NULL) {
char *readp = &b->data[bbm->read_off];

const char *newline = OPENSSL_memchr(readp, '\n', ret);
if (newline != NULL) {
ret = (int)(newline - readp + 1);
}
}

ret = mem_read(bio, buf, ret);
Expand All @@ -207,20 +248,45 @@ static int mem_gets(BIO *bio, char *buf, int size) {
static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
long ret = 1;

BUF_MEM *b = (BUF_MEM *)bio->ptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *) bio->ptr;
BUF_MEM *b = bbm->buf;

switch (cmd) {
case BIO_CTRL_RESET:
if (b->data != NULL) {
// For read only case reset to the start again
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data -= b->max - b->length;
b->data -= b->max - b->length - bbm->read_off;
b->length = b->max;
} else {
OPENSSL_cleanse(b->data, b->max);
b->length = 0;
}
bbm->read_off = 0;
} else {
ret = -1;
}
break;
case BIO_C_FILE_SEEK:
if (b->data == NULL || num < 0 || (size_t)num > b->max) {
ret = -1;
break;
}

if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data -= b->max - b->length - bbm->read_off;
b->length = b->max - num;
} else {
if ((size_t)num > bbm->read_off + b->length) {
ret = -1;
break;
}

b->length = (b->length + bbm->read_off) - num;
}

bbm->read_off = num;
ret = num;
break;
case BIO_CTRL_EOF:
ret = (long)(b->length == 0);
Expand All @@ -232,7 +298,7 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
ret = (long)b->length;
if (ptr != NULL) {
char **pptr = ptr;
*pptr = b->data;
*pptr = (b->data != NULL) ? &b->data[bbm->read_off] : NULL;
}
break;
case BIO_C_SET_BUF_MEM:
Expand All @@ -242,6 +308,7 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
break;
case BIO_C_GET_BUF_MEM_PTR:
if (ptr != NULL) {
mem_buf_sync(bio);
BUF_MEM **pptr = ptr;
*pptr = b;
}
Expand Down Expand Up @@ -281,12 +348,15 @@ const BIO_METHOD *BIO_s_mem(void) { return &mem_method; }

int BIO_mem_contents(const BIO *bio, const uint8_t **out_contents,
size_t *out_len) {
const BUF_MEM *b;
if (!bio || bio->method != &mem_method) {
return 0;
}

b = (BUF_MEM *)bio->ptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *) bio->ptr;
const BUF_MEM *b = bbm->buf;

mem_buf_sync((BIO *)bio);

if (out_contents != NULL) {
*out_contents = (uint8_t *)b->data;
}
Expand Down
Loading
Loading