diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-09-01 18:06:49 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-10-12 18:20:10 +0900 |
| commit | 4cf1da9542d6554ec23de6324c5f2d5eebe138c9 (patch) | |
| tree | ecaa1f4ecd92243e2a6939a10ee02c25c494429e | |
| parent | b01207ea94095bc855b8e6fef0dc65d7eae0d8ad (diff) | |
| download | mruby-4cf1da9542d6554ec23de6324c5f2d5eebe138c9.tar.gz mruby-4cf1da9542d6554ec23de6324c5f2d5eebe138c9.zip | |
Separate jump destination check in `OP_R_RETURN`.
In the past code, the current `callinfo (ci)` was modified, thus it was
possible to pop `ci` beyond the `cibase`, that could cause out of memory
bound access for the code like the following:
```ruby
def m2
lambda {
Proc.new {
return :return # return from the method
}
}.call.call
:never_reached
end
p m2
```
| -rw-r--r-- | src/vm.c | 17 |
1 files changed, 11 insertions, 6 deletions
@@ -2029,11 +2029,20 @@ RETRY_TRY_BLOCK: goto L_RAISE; } } + /* check jump destination */ while (cibase <= ci && ci->proc != dst) { - if (ci->acc < 0) { + if (ci->acc < 0) { /* jump cross C boudary */ localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } + ci--; + } + if (ci <= cibase) { /* no jump destination */ + localjump_error(mrb, LOCALJUMP_ERROR_RETURN); + goto L_RAISE; + } + ci = mrb->c->ci; + while (cibase <= ci && ci->proc != dst) { CHECKPOINT_RESTORE(RBREAK_TAG_RETURN_BLOCK) { cibase = mrb->c->cibase; dst = top_proc(mrb, proc); @@ -2045,12 +2054,8 @@ RETRY_TRY_BLOCK: pc = ci->pc; ci = cipop(mrb); } - mrb->exc = NULL; /* clear break object */ proc = ci->proc; - if (ci <= cibase) { - localjump_error(mrb, LOCALJUMP_ERROR_RETURN); - goto L_RAISE; - } + mrb->exc = NULL; /* clear break object */ break; } /* fallthrough */ |
