diff options
| author | himura467 <akitoshitara@gmail.com> | 2026-05-14 14:24:44 +0900 |
|---|---|---|
| committer | Sutou Kouhei <kou@cozmixng.org> | 2026-05-15 09:58:18 +0900 |
| commit | 2552db04ddc44349c7b0f5f93aeb0fb02eccb509 (patch) | |
| tree | 8dbfca42b0e56a62f241c16555c6f550870f8182 /io_buffer.c | |
| parent | 356c0cd0e7953baafd240914476213566f526c85 (diff) | |
Fix UAF in IO::Buffer#& when self or mask is an invalidated slice
Diffstat (limited to 'io_buffer.c')
| -rw-r--r-- | io_buffer.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/io_buffer.c b/io_buffer.c index 6dbc824e59..c64a9b7fe7 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -3378,14 +3378,14 @@ io_buffer_pwrite(int argc, VALUE *argv, VALUE self) } static inline void -io_buffer_check_mask(const struct rb_io_buffer *buffer) +io_buffer_check_mask_size(size_t size) { - if (buffer->size == 0) + if (size == 0) rb_raise(rb_eIOBufferMaskError, "Zero-length mask given!"); } static void -memory_and(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) +memory_and(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { output[offset] = base[offset] & mask[offset % mask_size]; @@ -3413,13 +3413,21 @@ io_buffer_and(VALUE self, VALUE mask) struct rb_io_buffer *mask_buffer = NULL; TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer); - io_buffer_check_mask(mask_buffer); + const void *base; + size_t size; + io_buffer_get_bytes_for_reading(buffer, &base, &size); - VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size)); + const void *mask_base; + size_t mask_size; + io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size); + + io_buffer_check_mask_size(mask_size); + + VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size)); struct rb_io_buffer *output_buffer = NULL; TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer); - memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size); + memory_and(output_buffer->base, base, size, mask_base, mask_size); return output; } @@ -3453,7 +3461,7 @@ io_buffer_or(VALUE self, VALUE mask) struct rb_io_buffer *mask_buffer = NULL; TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer); - io_buffer_check_mask(mask_buffer); + io_buffer_check_mask_size(mask_buffer->size); VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size)); struct rb_io_buffer *output_buffer = NULL; @@ -3493,7 +3501,7 @@ io_buffer_xor(VALUE self, VALUE mask) struct rb_io_buffer *mask_buffer = NULL; TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer); - io_buffer_check_mask(mask_buffer); + io_buffer_check_mask_size(mask_buffer->size); VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size)); struct rb_io_buffer *output_buffer = NULL; @@ -3590,7 +3598,7 @@ io_buffer_and_inplace(VALUE self, VALUE mask) struct rb_io_buffer *mask_buffer = NULL; TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer); - io_buffer_check_mask(mask_buffer); + io_buffer_check_mask_size(mask_buffer->size); io_buffer_check_overlaps(buffer, mask_buffer); void *base; @@ -3636,7 +3644,7 @@ io_buffer_or_inplace(VALUE self, VALUE mask) struct rb_io_buffer *mask_buffer = NULL; TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer); - io_buffer_check_mask(mask_buffer); + io_buffer_check_mask_size(mask_buffer->size); io_buffer_check_overlaps(buffer, mask_buffer); void *base; @@ -3682,7 +3690,7 @@ io_buffer_xor_inplace(VALUE self, VALUE mask) struct rb_io_buffer *mask_buffer = NULL; TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer); - io_buffer_check_mask(mask_buffer); + io_buffer_check_mask_size(mask_buffer->size); io_buffer_check_overlaps(buffer, mask_buffer); void *base; |
