mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
Reject relabeling a module via TYPE_UCLASS in Marshal.load (#19115)
This is not a real-world problem. Marshal.dump never emits this payload.
It can only be hand-crafted. Loading untrusted Marshal data is already
unsafe. This fix only avoids false positives from security scanners.
TYPE_UCLASS ('C') relabels the wrapped object's class with RBASIC_SET_CLASS.
It assumes the object was freshly allocated during load. But a wrapped
module is not. The read returns the live, shared module object. So the
relabel hits that global object instead.
Classes were already rejected here. Now reject modules too. This restores
the behavior before 959d5febcf.
This commit is contained in:
1 parent
32154539ad
commit
ea28d3839b
2 files changed
+15
-2
Notes:
git
2026-09-29 20:58:21 +00:00
Merged-By: kou <kou@clear-code.com>
No files matched your search
@@ -2013,10 +2013,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex
|
||||
goto type_hash;
|
||||
}
|
||||
v = r_object_for(arg, partial, 0, c, extmod, type);
|
||||
if (RB_SPECIAL_CONST_P(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
|
||||
if (RB_SPECIAL_CONST_P(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE)) {
|
||||
goto format_error;
|
||||
}
|
||||
if (RB_TYPE_P(v, T_MODULE) || !RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) {
|
||||
if (!RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) {
|
||||
VALUE tmp = rb_obj_alloc(c);
|
||||
|
||||
if (TYPE(v) != TYPE(tmp)) goto format_error;
|
||||
|
||||
@@ -169,6 +169,19 @@ class TestMarshal < Test::Unit::TestCase
|
||||
assert_equal(Enumerable, Marshal.load(Marshal.dump(Enumerable)))
|
||||
end
|
||||
|
||||
class ModuleSubclass < Module
|
||||
end
|
||||
|
||||
def test_uclass_module_not_relabeled
|
||||
# TYPE_UCLASS ('C') wrapping a module must be rejected, not relabel it.
|
||||
uclass = Marshal.dump(ModuleSubclass.name.to_sym)[2..-1] # ":<name>"
|
||||
wrapped = Marshal.dump(TestModule)[2..-1] # "m<name>"
|
||||
payload = "\x04\x08C#{uclass}#{wrapped}"
|
||||
assert_raise_with_message(ArgumentError, "dump format error (user class)") do
|
||||
Marshal.load(payload)
|
||||
end
|
||||
end
|
||||
|
||||
class C2
|
||||
def initialize(ary)
|
||||
@ary = ary
|
||||
|
||||
Reference in new issue
Block a user