From 0337e0e0f17f235b9bebd9c2d0403807b3745a0f Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 19 Nov 2024 22:47:04 +0900 Subject: [PATCH] Need to update `ci` variable after re-entry to VM Some functions called by `mrb_vm_exec()` involve re-entry into the mruby VM. If the `ci` variable is not updated after re-entry, use-after-free is caused. This patch makes the following after-call fixes. | called | might call methods | ----------------------- | ---------------- | `mrb_ary_splat()` | `#to_a` | `hash_new_from_regs()` | `#eql?` `#hash` | `mrb_hash_delete_key()` | `#eql?` `#hash` | `mrb_hash_get()` | `#eql?` `#hash` `#default` | `mrb_hash_key_p()` | `#eql?` `#hash` | `mrb_hash_merge()` | `#eql?` `#hash` | `mrb_hash_set()` | `#eql?` `#hash` | `mrb_range_new()` | `#<=>` --- src/vm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 40a8a8971..4d78035ad 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1373,6 +1373,7 @@ hash_new_from_regs(mrb_state *mrb, mrb_int argc, mrb_int idx) mrb_callinfo *ci = mrb->c->ci; while (argc--) { mrb_hash_set(mrb, hash, regs[idx+0], regs[idx+1]); + ci = mrb->c->ci; idx += 2; } return hash; @@ -1601,6 +1602,7 @@ RETRY_TRY_BLOCK: break; case MRB_TT_HASH: va = mrb_hash_get(mrb, va, vb); + ci = mrb->c->ci; regs[a] = va; break; case MRB_TT_STRING: @@ -1875,6 +1877,7 @@ RETRY_TRY_BLOCK: else if (nk > 0) { /* pack keyword arguments */ mrb_int kidx = a+(n==CALL_MAXARGS?1:n)+1; mrb_value kdict = hash_new_from_regs(mrb, nk, kidx); + ci = mrb->c->ci; regs[kidx] = kdict; nk = CALL_MAXARGS; c = n | (nk<<4); @@ -2247,8 +2250,10 @@ RETRY_TRY_BLOCK: RAISE_FORMAT(mrb, E_ARGUMENT_ERROR, "missing keyword: %v", k); } v = mrb_hash_get(mrb, kdict, k); + ci = mrb->c->ci; regs[a] = v; mrb_hash_delete_key(mrb, kdict, k); + ci = mrb->c->ci; NEXT; } @@ -2260,6 +2265,7 @@ RETRY_TRY_BLOCK: if (kidx >= 0 && mrb_hash_p(kdict=regs[kidx])) { key_p = mrb_hash_key_p(mrb, kdict, k); + ci = mrb->c->ci; } regs[a] = mrb_bool_value(key_p); NEXT; @@ -2669,6 +2675,7 @@ RETRY_TRY_BLOCK: CASE(OP_ARYCAT, B) { mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); + ci = mrb->c->ci; if (mrb_nil_p(regs[a])) { regs[a] = splat; } @@ -2690,6 +2697,7 @@ RETRY_TRY_BLOCK: CASE(OP_ARYSPLAT, B) { mrb_value ary = mrb_ary_splat(mrb, regs[a]); + ci = mrb->c->ci; regs[a] = ary; mrb_gc_arena_restore(mrb, ai); NEXT; @@ -2804,6 +2812,7 @@ RETRY_TRY_BLOCK: for (int i=a; ic->ci; } regs[a] = hash; mrb_gc_arena_restore(mrb, ai); @@ -2818,6 +2827,7 @@ RETRY_TRY_BLOCK: mrb_ensure_hash_type(mrb, hash); for (int i=a+1; ic->ci; } mrb_gc_arena_restore(mrb, ai); NEXT; @@ -2827,6 +2837,7 @@ RETRY_TRY_BLOCK: mrb_assert(mrb_hash_p(hash)); mrb_hash_merge(mrb, hash, regs[a+1]); + ci = mrb->c->ci; mrb_gc_arena_restore(mrb, ai); NEXT; } @@ -2860,13 +2871,16 @@ RETRY_TRY_BLOCK: } CASE(OP_RANGE_INC, B) { - regs[a] = mrb_range_new(mrb, regs[a], regs[a+1], FALSE); + mrb_value v = mrb_range_new(mrb, regs[a], regs[a+1], FALSE); + ci = mrb->c->ci; + regs[a] = v; mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_RANGE_EXC, B) { mrb_value v = mrb_range_new(mrb, regs[a], regs[a+1], TRUE); + ci = mrb->c->ci; regs[a] = v; mrb_gc_arena_restore(mrb, ai); NEXT;