summaryrefslogtreecommitdiff
path: root/io_buffer.c
diff options
context:
space:
mode:
authorhimura467 <akitoshitara@gmail.com>2026-05-14 14:24:44 +0900
committerSutou Kouhei <kou@cozmixng.org>2026-05-15 09:58:18 +0900
commit2552db04ddc44349c7b0f5f93aeb0fb02eccb509 (patch)
tree8dbfca42b0e56a62f241c16555c6f550870f8182 /io_buffer.c
parent356c0cd0e7953baafd240914476213566f526c85 (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.c30
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;