Skip to content

Commit 5d93c2e

Browse files
committed
be more robust what we accept
1 parent 19858f6 commit 5d93c2e

3 files changed

Lines changed: 132 additions & 19 deletions

File tree

mrblib/msgpack.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
module MessagePack
22
def self.register_ext_type(type, klass, pack:, unpack:)
33
pack = pack.to_proc if pack.respond_to?(:to_proc)
4-
raise ArgumentError unless pack.is_a?(Proc)
4+
raise ArgumentError, "packer is no proc" unless pack.is_a?(Proc)
55
unpack = unpack.to_proc if unpack.respond_to?(:to_proc)
6-
raise ArgumentError unless unpack.is_a?(Proc)
6+
raise ArgumentError, "unpacker is no proc" unless unpack.is_a?(Proc)
77

88
register_pack_type(type, klass, &pack)
99
register_unpack_type(type, &unpack)

src/mrb_msgpack.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,23 @@ MRB_END_DECL
2929
#include <string_view>
3030
#include <atomic>
3131
#include <cstdint>
32+
#include <mrbconf.h>
33+
34+
#ifndef MRB_STR_LENGTH_MAX
35+
# define MRB_STR_LENGTH_MAX 1048576
36+
#endif
37+
38+
#ifndef MRB_ARY_LENGTH_MAX
39+
# define MRB_ARY_LENGTH_MAX 131072
40+
#endif
41+
42+
#define MSGPACK_STR_LIMIT MRB_STR_LENGTH_MAX
43+
#define MSGPACK_BIN_LIMIT MRB_STR_LENGTH_MAX
44+
#define MSGPACK_EXT_LIMIT MRB_STR_LENGTH_MAX
45+
#define MSGPACK_ARY_LIMIT MRB_ARY_LENGTH_MAX
46+
#define MSGPACK_MAP_LIMIT MRB_ARY_LENGTH_MAX
47+
#define MSGPACK_DEPTH_LIMIT 128
48+
3249

3350

3451
/* ------------------------------------------------------------------------
@@ -861,8 +878,17 @@ MRB_API mrb_value
861878
mrb_msgpack_unpack(mrb_state *mrb, mrb_value data)
862879
{
863880
data = mrb_str_to_str(mrb, data);
881+
msgpack::unpack_limit limit(
882+
MSGPACK_ARY_LIMIT, // array
883+
MSGPACK_MAP_LIMIT, // map
884+
MSGPACK_STR_LIMIT, // str
885+
MSGPACK_BIN_LIMIT, // bin
886+
MSGPACK_EXT_LIMIT, // ext
887+
MSGPACK_DEPTH_LIMIT // depth
888+
);
889+
864890
msgpack::object_handle oh =
865-
msgpack::unpack(RSTRING_PTR(data), RSTRING_LEN(data));
891+
msgpack::unpack(RSTRING_PTR(data), RSTRING_LEN(data), nullptr, nullptr, limit);
866892
return mrb_unpack_msgpack_obj(mrb, oh.get());
867893
}
868894

@@ -877,11 +903,20 @@ mrb_msgpack_unpack_m(mrb_state* mrb, mrb_value self)
877903
std::size_t len = RSTRING_LEN(data);
878904
std::size_t off = 0;
879905

906+
msgpack::unpack_limit limit(
907+
MSGPACK_ARY_LIMIT, // array
908+
MSGPACK_MAP_LIMIT, // map
909+
MSGPACK_STR_LIMIT, // str
910+
MSGPACK_BIN_LIMIT, // bin
911+
MSGPACK_EXT_LIMIT, // ext
912+
MSGPACK_DEPTH_LIMIT // depth
913+
);
914+
880915
try {
881916
if (mrb_type(block) == MRB_TT_PROC) {
882917
while (off < len) {
883918
try {
884-
msgpack::object_handle oh = msgpack::unpack(buf, len, off);
919+
msgpack::object_handle oh = msgpack::unpack(buf, len, off, nullptr, nullptr, limit);
885920
mrb_yield(mrb, block, mrb_unpack_msgpack_obj(mrb, oh.get()));
886921
}
887922
catch (const msgpack::insufficient_bytes&) {
@@ -891,7 +926,7 @@ mrb_msgpack_unpack_m(mrb_state* mrb, mrb_value self)
891926
return mrb_convert_number(mrb, (mrb_int)off);
892927
}
893928
else {
894-
msgpack::object_handle oh = msgpack::unpack(buf, len, off);
929+
msgpack::object_handle oh = msgpack::unpack(buf, len, off, nullptr, nullptr, limit);
895930
return mrb_unpack_msgpack_obj(mrb, oh.get());
896931
}
897932
}
@@ -951,7 +986,7 @@ mrb_msgpack_unpack_lazy_m(mrb_state *mrb, mrb_value self)
951986
try {
952987
mrb_value object_handle =
953988
mrb_obj_new(mrb,
954-
mrb_class_get_under_id(mrb, mrb_class_ptr(self), MRB_SYM(ObjectHandle)),
989+
mrb_class_get_under_id(mrb, mrb_class_ptr(self), MRB_SYM(_ObjectHandle)),
955990
1, &data);
956991

957992
auto* handle = (msgpack_object_handle*)mrb_data_get_ptr(mrb, object_handle, &msgpack_object_handle_type);
@@ -1662,7 +1697,7 @@ mrb_mruby_simplemsgpack_gem_init(mrb_state* mrb)
16621697

16631698
mrb_object_handle_class =
16641699
mrb_define_class_under_id(mrb, msgpack_mod,
1665-
MRB_SYM(ObjectHandle), mrb->object_class);
1700+
MRB_SYM(_ObjectHandle), mrb->object_class);
16661701

16671702
MRB_SET_INSTANCE_TT(mrb_object_handle_class, MRB_TT_DATA);
16681703

test/msgpack.rb

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ class HTTP2; end
424424

425425
assert("LFU: eviction removes least frequently used") do
426426
# Wir erzeugen mehr Klassen als MAX_SIZE (128)
427-
150.times do |i|
427+
1500.times do |i|
428428
Object.const_set("LFUTest#{i}", Class.new)
429429
assert_equal Object.const_get("LFUTest#{i}"), "LFUTest#{i}".constantize
430430
end
@@ -434,11 +434,11 @@ class HTTP2; end
434434
class HotA; end
435435
class HotB; end
436436

437-
50.times { assert_equal HotA, "HotA".constantize }
438-
50.times { assert_equal HotB, "HotB".constantize }
437+
500.times { assert_equal HotA, "HotA".constantize }
438+
500.times { assert_equal HotB, "HotB".constantize }
439439

440440
# Jetzt Cache fluten
441-
200.times do |i|
441+
2000.times do |i|
442442
Object.const_set("Cold#{i}", Class.new)
443443
assert_equal Object.const_get("Cold#{i}"), "Cold#{i}".constantize
444444
end
@@ -459,7 +459,7 @@ class HotB; end
459459

460460
assert("LFU: index overflow does not crash") do
461461
base = "AA"
462-
300.times do |i|
462+
3000.times do |i|
463463
key = base + i.to_s
464464
Object.const_set(key, Class.new)
465465
assert_equal Object.const_get(key), key.constantize
@@ -469,7 +469,7 @@ class HotB; end
469469
end
470470

471471
assert("LFU: GC stress does not break cache") do
472-
200.times do |i|
472+
2000.times do |i|
473473
key = "GCStress#{i}"
474474
Object.const_set(key, Class.new)
475475
assert_equal Object.const_get(key), key.constantize
@@ -481,13 +481,13 @@ class HotB; end
481481

482482
assert("LFU: entry slot reuse is safe") do
483483
# Fülle Cache
484-
128.times do |i|
484+
1280.times do |i|
485485
Object.const_set("Reuse#{i}", Class.new)
486486
assert_equal Object.const_get("Reuse#{i}"), "Reuse#{i}".constantize
487487
end
488488

489489
# Erzeuge Evictions
490-
50.times do |i|
490+
5000.times do |i|
491491
Object.const_set("ReuseEvict#{i}", Class.new)
492492
assert_equal Object.const_get("ReuseEvict#{i}"), "ReuseEvict#{i}".constantize
493493
end
@@ -499,7 +499,7 @@ class HotB; end
499499
assert("LFU: constantize correctness under pressure") do
500500
module A; module B; class C; end; end; end
501501

502-
200.times do |i|
502+
2000.times do |i|
503503
Object.const_set("Spam#{i}", Class.new)
504504
assert_equal Object.const_get("Spam#{i}"), "Spam#{i}".constantize
505505
end
@@ -511,10 +511,10 @@ module A; module B; class C; end; end; end
511511
class HotX; end
512512
class HotY; end
513513

514-
100.times { assert_equal HotX, "HotX".constantize }
515-
100.times { assert_equal HotY, "HotY".constantize }
514+
1000.times { assert_equal HotX, "HotX".constantize }
515+
1000.times { assert_equal HotY, "HotY".constantize }
516516

517-
200.times do |i|
517+
2000.times do |i|
518518
if i % 5 == 0
519519
assert_raise(NameError) { "Miss#{i}".constantize }
520520
else
@@ -523,3 +523,81 @@ class HotY; end
523523
end
524524
end
525525
end
526+
527+
assert("MessagePack: register_ext_type invalid callbacks") do
528+
# pack kein Proc
529+
assert_raise(ArgumentError) do
530+
MessagePack.register_ext_type(1, String,
531+
pack: 123,
532+
unpack: ->(x) { x }
533+
)
534+
end
535+
536+
# unpack kein Proc
537+
assert_raise(ArgumentError) do
538+
MessagePack.register_ext_type(1, String,
539+
pack: ->(x) { x },
540+
unpack: 123
541+
)
542+
end
543+
end
544+
545+
assert("MessagePack: unpack invalid bytes") do
546+
assert_raise(MessagePack::Error) { MessagePack.unpack("\xA5hel") }
547+
assert_raise(MessagePack::Error) { MessagePack.unpack("\x92\x01") }
548+
assert_raise(MessagePack::Error) { MessagePack.unpack("\x81\xA1a") }
549+
end
550+
551+
552+
assert("MessagePack: JSON Pointer syntax errors") do
553+
data = { "a" => 1 }
554+
lazy = MessagePack.unpack_lazy(MessagePack.pack(data))
555+
556+
assert_raise(ArgumentError) { lazy.at_pointer("a") }
557+
558+
assert_raise(KeyError) { lazy.at_pointer("//a") }
559+
560+
assert_raise(KeyError) { lazy.at_pointer("/~2") }
561+
562+
assert_raise(KeyError) { lazy.at_pointer("/~") }
563+
end
564+
565+
566+
assert("MessagePack: JSON Pointer extreme tokens") do
567+
data = { "a/b" => 1, "~x" => 2 }
568+
lazy = MessagePack.unpack_lazy(MessagePack.pack(data))
569+
570+
assert_equal 1, lazy.at_pointer("/a~1b")
571+
assert_equal 2, lazy.at_pointer("/~0x")
572+
573+
long_key = "x" * 10_000
574+
lazy2 = MessagePack.unpack_lazy(MessagePack.pack({ long_key => 5 }))
575+
576+
assert_equal 5, lazy2.at_pointer("/" + long_key)
577+
end
578+
579+
assert("MessagePack: JSON Pointer semantic errors") do
580+
data = { "a" => [1, 2, 3] }
581+
lazy = MessagePack.unpack_lazy(MessagePack.pack(data))
582+
583+
assert_raise(KeyError) { lazy.at_pointer("/b") }
584+
585+
assert_raise(IndexError) { lazy.at_pointer("/a/foo") }
586+
587+
assert_raise(IndexError) { lazy.at_pointer("/a/-1") }
588+
589+
assert_raise(IndexError) { lazy.at_pointer("/a/999") }
590+
end
591+
592+
assert("MessagePack: unpack ext without unpacker") do
593+
class Foo2; end
594+
595+
MessagePack.register_pack_type(42, Foo2) { "X" }
596+
597+
foo = Foo2.new
598+
packed = foo.to_msgpack
599+
600+
assert_raise(MessagePack::Error) do
601+
MessagePack.unpack(packed)
602+
end
603+
end

0 commit comments

Comments
 (0)