Skip to content
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

SECBUG-240 Fix out-of-bounds reads (backport to 4.15-stable) #326

Merged
merged 2 commits into from
Apr 2, 2024
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
21 changes: 18 additions & 3 deletions ext/bson/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *
static VALUE pvt_get_boolean(byte_buffer_t *b);
static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv);
static void pvt_skip_cstring(byte_buffer_t *b);
static size_t pvt_strnlen(const byte_buffer_t *b);

void pvt_raise_decode_error(volatile VALUE msg) {
VALUE klass = pvt_const_get_3("BSON", "Error", "BSONDecodeError");
Expand Down Expand Up @@ -128,7 +129,7 @@ VALUE rb_bson_byte_buffer_get_bytes(VALUE self, VALUE i)
}

VALUE pvt_get_boolean(byte_buffer_t *b){
VALUE result;
VALUE result = Qnil;
char byte_value;
ENSURE_BSON_READ(b, 1);
byte_value = *READ_PTR(b);
Expand Down Expand Up @@ -221,7 +222,7 @@ VALUE rb_bson_byte_buffer_get_cstring(VALUE self)
int length;

TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
length = (int)strlen(READ_PTR(b));
length = (int)pvt_strnlen(b);
ENSURE_BSON_READ(b, length);
string = rb_enc_str_new(READ_PTR(b), length, rb_utf8_encoding());
b->read_position += length + 1;
Expand All @@ -234,7 +235,7 @@ VALUE rb_bson_byte_buffer_get_cstring(VALUE self)
void pvt_skip_cstring(byte_buffer_t *b)
{
int length;
length = (int)strlen(READ_PTR(b));
length = (int)pvt_strnlen(b);
ENSURE_BSON_READ(b, length);
b->read_position += length + 1;
}
Expand Down Expand Up @@ -438,3 +439,17 @@ VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self){

return array;
}

/**
* Returns the length of the given string `str`. If no null-terminating byte
* is present when `len` bytes have been scanned, then `len` is
* returned.
*/
size_t pvt_strnlen(const byte_buffer_t *b) {
const char *ptr = memchr(READ_PTR(b), '\0', READ_SIZE(b));

if (!ptr)
rb_raise(rb_eRangeError, "string is too long (possibly not null-terminated)");

return (size_t)(ptr - READ_PTR(b));
}
4 changes: 4 additions & 0 deletions ext/bson/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ void pvt_put_array_index(byte_buffer_t *b, int32_t index)
c_str = buffer;
snprintf(buffer, sizeof(buffer), "%d", index);
}
// strlen is a potential vector for out-of-bounds errors, but
// the only way for that to happen here, specifically, is if `index`
// is greater than 10e16 - 1, which is far beyond the domain of an
// int32.
length = strlen(c_str) + 1;
ENSURE_BSON_WRITE(b, length);
memcpy(WRITE_PTR(b), c_str, length);
Expand Down
2 changes: 1 addition & 1 deletion lib/bson/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
# limitations under the License.

module BSON
VERSION = "4.15.0"
VERSION = "4.15.1"
end
Loading