From 9b9424fe3276811c805a09bc7948fd6958265563 Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 2 May 2022 14:28:27 +0900 Subject: [PATCH] Strict acquisition of the `Random` class given by `mrb_get_args()` This is to prevent data corruption of the substituted `Random` instance. If the `Object::Random` constants are redefined to a different `MRB_TT_ISTRUCT` object class, they can pass `mrb_get_args()` validation. The following is an example of how the `Array#shuffle` method rewrites the data of a non `Random` instance. ```c // code.c #include #include #include #include #define EVAL_LIT(MRB, ...) mrb_load_string((MRB), #__VA_ARGS__) static mrb_value fake_initialize(mrb_state *mrb, mrb_value self) { char *p = ISTRUCT_PTR(self); for (int i = 0; i < ISTRUCT_DATA_SIZE; i++) { p[i] = 'A' + i; } return self; } static mrb_value fake_to_bytes(mrb_state *mrb, mrb_value self) { const char *p = ISTRUCT_PTR(self); return mrb_str_new(mrb, p, ISTRUCT_DATA_SIZE); } int main(int argc, char *argv[]) { mrb_state *mrb = mrb_open(); struct RClass *fake = mrb_define_class(mrb, "Fake", mrb->object_class); MRB_SET_INSTANCE_TT(fake, MRB_TT_ISTRUCT); mrb_define_method(mrb, fake, "initialize", fake_initialize, MRB_ARGS_NONE()); mrb_define_method(mrb, fake, "to_bytes", fake_to_bytes, MRB_ARGS_NONE()); EVAL_LIT(mrb, Random = Fake \n fake = Fake.new \n p [fake, fake.to_bytes] \n p a = (1..10).to_a \n p a.shuffle(fake) \n p [fake, fake.to_bytes] ); mrb_close(mrb); return 0; } ``` ```console % `bin/mruby-config --cc --cflags --ldflags` code.c `bin/mruby-config --libs` % ./a.out [#, "ABCDEFGHIJKLMNOPQRSTUVWX"] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1, 7, 8, 10, 2, 6, 9, 3, 4, 5] [#, "\xe81{\v\fM\xb0D<\x99\xb1V+l\x84\x86QRSTUVWX"] ``` --- mrbgems/mruby-random/src/random.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index ae917d33e..fc99e334f 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -167,6 +167,7 @@ random_default(mrb_state *mrb) { #define random_ptr(v) (rand_state*)mrb_istruct_ptr(v) #define random_default_state(mrb) random_ptr(random_default(mrb)) +#define ID_RANDOM_STRICT MRB_SYM(mruby_Random) static mrb_value random_m_init(mrb_state *mrb, mrb_value self) @@ -245,7 +246,7 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) rand_state *random; if (RARRAY_LEN(ary) > 1) { - struct RClass *c = mrb_class_get_id(mrb, MRB_SYM(Random)); + struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM_STRICT); if (mrb_get_args(mrb, "|I", &random, c) == 0) { random = random_default_state(mrb); } @@ -305,7 +306,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) mrb_bool given; rand_state *random; mrb_int len; - struct RClass *c = mrb_class_get_id(mrb, MRB_SYM(Random)); + struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM_STRICT); if (mrb_get_args(mrb, "|i?I", &n, &given, &random, c) < 2) { random = random_default_state(mrb); @@ -386,6 +387,7 @@ void mrb_mruby_random_gem_init(mrb_state *mrb) mrb_define_method(mrb, mrb->kernel_module, "srand", random_f_srand, MRB_ARGS_OPT(1)); random = mrb_define_class(mrb, "Random", mrb->object_class); + mrb_const_set(mrb, mrb_obj_value(mrb->object_class), ID_RANDOM_STRICT, mrb_obj_value(random)); // for mrb_get_args() MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT); mrb_define_class_method(mrb, random, "rand", random_f_rand, MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, random, "srand", random_f_srand, MRB_ARGS_OPT(1));