From 547d465340b5358502483a97729a95661bcd754d Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sun, 24 Jul 2022 09:33:51 -0700 Subject: [PATCH] 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*`. --- src/variable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 38d35f636..ea7301770 100644 --- a/src/variable.c +++ b/src/variable.c @@ -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, "::");