Fix possible use after free in mrb_class_find_path

`mrb_class_find_path` resolves a `char*` pointer to a class name string
by calling `mrb_class_name`. It then allocates a new string with
capacity 40 to copy that `char*` into.

https://github.com/mruby/mruby/blob/e04184185ab43b94980550e850d8813a415fa438/src/variable.c#L1111-L1112

`mrb_class_name` resolves the class name via `class_name_str`, which
returns an `mrb_value` with type tag `MRB_TT_STRING` and backed by an
`RString*`. Then `mrb_class_name` extracts the `RSTRING_PTR`:

https://github.com/mruby/mruby/blob/e04184185ab43b94980550e850d8813a415fa438/src/class.c#L2133-L2134

That `RString*`-backed `mrb_value` ultimately comes from `mrb_class_path`
which resolves the string from the symbol table:

https://github.com/mruby/mruby/blob/e04184185ab43b94980550e850d8813a415fa438/src/class.c#L2111

The allocation of the target `str` after resolving the class name
`mrb_value` and extracting its pointer is fragile and assumes the
`RString*` is "static". If the `RString*` is not static, the
interleaving of extracting the `RSTRING_PTR` followed by a subsequent
allocation might result in the class name `mrb_value` being garbage
collected, which will leave the extracted pointer invalid.

Fix this bad interleaving by allocating the destination string first
before taking a raw pointer to an `RString*`.
This commit is contained in:
Ryan Lopopolo
2022-07-24 09:33:51 -07:00
parent e04184185a
commit 547d465340
+1 -1
View File
@@ -1108,8 +1108,8 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c)
if (outer == NULL) return mrb_nil_value();
name = find_class_sym(mrb, outer, c);
if (name == 0) return mrb_nil_value();
str = mrb_class_name(mrb, outer);
path = mrb_str_new_capa(mrb, 40);
str = mrb_class_name(mrb, outer);
mrb_str_cat_cstr(mrb, path, str);
mrb_str_cat_cstr(mrb, path, "::");