From 040868f2863d945e56bf48dd42035881b9e8f00b Mon Sep 17 00:00:00 2001 From: Arthur Chan Date: Mon, 9 Nov 2026 04:28:01 +0000 Subject: [PATCH] OSS-Fuzz: Add new fuzzer/corpus/dicts/options/scripts targets deserialisers Signed-off-by: Arthur Chan --- Makefile | 7 +- corp-marshal/big_tuple_v4.marshal | Bin 0 -> 5005 bytes corp-marshal/code_nested_v4.marshal | Bin 0 -> 290 bytes corp-marshal/code_object_v4.marshal | Bin 0 -> 98 bytes corp-marshal/containers_v2.marshal | Bin 0 -> 127 bytes corp-marshal/containers_v3.marshal | Bin 0 -> 127 bytes corp-marshal/containers_v4.marshal | Bin 0 -> 109 bytes corp-marshal/float_variants_v4.marshal | Bin 0 -> 50 bytes .../negative_and_huge_ints_v4.marshal | Bin 0 -> 45 bytes corp-marshal/recursive_list_v4.marshal | Bin 0 -> 10 bytes corp-marshal/strings_v2.marshal | Bin 0 -> 791 bytes corp-marshal/strings_v3.marshal | Bin 0 -> 791 bytes corp-marshal/strings_v4.marshal | Bin 0 -> 779 bytes corp-marshal/types_v2.marshal | Bin 0 -> 102 bytes corp-marshal/types_v3.marshal | Bin 0 -> 102 bytes corp-marshal/types_v4.marshal | Bin 0 -> 99 bytes corp-pickle/basic_dict_p0.pickle | 27 +++++++ corp-pickle/basic_dict_p1.pickle | Bin 0 -> 128 bytes corp-pickle/basic_dict_p2.pickle | Bin 0 -> 122 bytes corp-pickle/basic_dict_p3.pickle | Bin 0 -> 82 bytes corp-pickle/basic_dict_p4.pickle | Bin 0 -> 71 bytes corp-pickle/basic_dict_p5.pickle | Bin 0 -> 71 bytes corp-pickle/bytes_and_bytearray.pickle | Bin 0 -> 623 bytes corp-pickle/complex_and_ellipsis.pickle | Bin 0 -> 78 bytes corp-pickle/empty_stream_variants.pickle | Bin 0 -> 27 bytes corp-pickle/float_values.pickle | Bin 0 -> 70 bytes corp-pickle/framed_proto4.pickle | Bin 0 -> 2066 bytes corp-pickle/global_ref_type.pickle | Bin 0 -> 23 bytes corp-pickle/long_int.pickle | Bin 0 -> 222 bytes corp-pickle/memo_reuse.pickle | Bin 0 -> 53 bytes corp-pickle/neg_int_p2.pickle | 1 + corp-pickle/nested_p0.pickle | 41 ++++++++++ corp-pickle/nested_p1.pickle | Bin 0 -> 185 bytes corp-pickle/nested_p2.pickle | Bin 0 -> 184 bytes corp-pickle/nested_p3.pickle | Bin 0 -> 178 bytes corp-pickle/nested_p4.pickle | Bin 0 -> 100 bytes corp-pickle/nested_p5.pickle | Bin 0 -> 100 bytes corp-pickle/proto0_text.pickle | 12 +++ corp-pickle/recursive_list.pickle | Bin 0 -> 17 bytes corp-pickle/stopiteration_and_range.pickle | Bin 0 -> 67 bytes corp-pickle/unicode_strs.pickle | Bin 0 -> 544 bytes fuzz_targets.txt | 2 + fuzzer-marshal.dict | 53 +++++++++++++ fuzzer-pickle.dict | 71 ++++++++++++++++++ marshal.py | 30 ++++++++ pickle.py | 31 ++++++++ 46 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 corp-marshal/big_tuple_v4.marshal create mode 100644 corp-marshal/code_nested_v4.marshal create mode 100644 corp-marshal/code_object_v4.marshal create mode 100644 corp-marshal/containers_v2.marshal create mode 100644 corp-marshal/containers_v3.marshal create mode 100644 corp-marshal/containers_v4.marshal create mode 100644 corp-marshal/float_variants_v4.marshal create mode 100644 corp-marshal/negative_and_huge_ints_v4.marshal create mode 100644 corp-marshal/recursive_list_v4.marshal create mode 100644 corp-marshal/strings_v2.marshal create mode 100644 corp-marshal/strings_v3.marshal create mode 100644 corp-marshal/strings_v4.marshal create mode 100644 corp-marshal/types_v2.marshal create mode 100644 corp-marshal/types_v3.marshal create mode 100644 corp-marshal/types_v4.marshal create mode 100644 corp-pickle/basic_dict_p0.pickle create mode 100644 corp-pickle/basic_dict_p1.pickle create mode 100644 corp-pickle/basic_dict_p2.pickle create mode 100644 corp-pickle/basic_dict_p3.pickle create mode 100644 corp-pickle/basic_dict_p4.pickle create mode 100644 corp-pickle/basic_dict_p5.pickle create mode 100644 corp-pickle/bytes_and_bytearray.pickle create mode 100644 corp-pickle/complex_and_ellipsis.pickle create mode 100644 corp-pickle/empty_stream_variants.pickle create mode 100644 corp-pickle/float_values.pickle create mode 100644 corp-pickle/framed_proto4.pickle create mode 100644 corp-pickle/global_ref_type.pickle create mode 100644 corp-pickle/long_int.pickle create mode 100644 corp-pickle/memo_reuse.pickle create mode 100644 corp-pickle/neg_int_p2.pickle create mode 100644 corp-pickle/nested_p0.pickle create mode 100644 corp-pickle/nested_p1.pickle create mode 100644 corp-pickle/nested_p2.pickle create mode 100644 corp-pickle/nested_p3.pickle create mode 100644 corp-pickle/nested_p4.pickle create mode 100644 corp-pickle/nested_p5.pickle create mode 100644 corp-pickle/proto0_text.pickle create mode 100644 corp-pickle/recursive_list.pickle create mode 100644 corp-pickle/stopiteration_and_range.pickle create mode 100644 corp-pickle/unicode_strs.pickle create mode 100644 fuzzer-marshal.dict create mode 100644 fuzzer-pickle.dict create mode 100644 marshal.py create mode 100644 pickle.py diff --git a/Makefile b/Makefile index 01df3e8..9845b33 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: fuzzer-binascii fuzzer-html fuzzer-email fuzzer-httpclient fuzzer-json fuzzer-difflib fuzzer-csv fuzzer-decode fuzzer-ast fuzzer-tarfile fuzzer-tarfile-hypothesis fuzzer-zipfile fuzzer-zipfile-hypothesis fuzzer-re fuzzer-configparser fuzzer-tomllib fuzzer-plistlib fuzzer-xml fuzzer-zoneinfo +all: fuzzer-binascii fuzzer-html fuzzer-email fuzzer-httpclient fuzzer-json fuzzer-difflib fuzzer-csv fuzzer-decode fuzzer-ast fuzzer-tarfile fuzzer-tarfile-hypothesis fuzzer-zipfile fuzzer-zipfile-hypothesis fuzzer-re fuzzer-configparser fuzzer-tomllib fuzzer-plistlib fuzzer-xml fuzzer-zoneinfo fuzzer-marshal fuzzer-pickle PYTHON_CONFIG_PATH=$(CPYTHON_INSTALL_PATH)/bin/python3-config CXXFLAGS += $(shell $(PYTHON_CONFIG_PATH) --cflags) @@ -42,3 +42,8 @@ fuzzer-xml: clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"xml.py\"" -ldl $(LDFLAGS) -o fuzzer-xml fuzzer-zoneinfo: clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"zoneinfo.py\"" -ldl $(LDFLAGS) -o fuzzer-zoneinfo + +fuzzer-marshal: + clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"marshal.py\"" -ldl $(LDFLAGS) -o fuzzer-marshal +fuzzer-pickle: + clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"pickle.py\"" -ldl $(LDFLAGS) -o fuzzer-pickle diff --git a/corp-marshal/big_tuple_v4.marshal b/corp-marshal/big_tuple_v4.marshal new file mode 100644 index 0000000000000000000000000000000000000000..90dd1b285434090edd46759f325695cfd826a80b GIT binary patch literal 5005 zcmWm2Lx30t006;@ZQHhO+qP}nwr$(CZQE*-Hg=k3_A!r5`7%gAz^i~iy$XcD__G3D z1w}9fM+k&OD1=5Bghe=nM+8JfBt%9OL`5`2M-0S7EW}0}#6>*BM*<{7A|yrCS*nyWJNY)M-JpfF62fYArwXt6h$!w>E3`%% zv_(6#M+bC7Cv-*^bVWCGM-TKwFZ4zq^hH1P#{dk(APmM348<@E#|VtXD2&D!jKw&N z#{^8oBuvH>OvN-z#|+HGEX>9n%*8y+#{w+GA}q!dEX6V`#|o^(Dy+sDti?L4#|CV~ zCTzwQY{fQg#}4eoF6_o0?8QFp#{nF~AsogL9K|sl#|fOoDV)X`oW(hu#|2!(C0xc8 zT*Wn9#|_-XE!@T(+{HcI#{)dXBRs|vJjF9S#|yl~EBuAO@fvUN5B|klyu*8Zz(;(- zXMDj|e8YGAz)$?bfB21nKmh@*0wFMhASi+%I6@#KLLoH5AS}WmJR%?>A|W!OAS$9E zI$|IuVj(u-ATHt|J`x}y5+N~?ASsd|IZ_}cQXw_cAT81%Ju)C8G9fdvAS<#VJ8~c= zav?YJATRPEKMJ5A3ZXEHpeTx=I7*--N})8$pe)LvJSw0fDxor}pem}NI%=RMYN0mj zpf2j6J{q7Q8lf?opedT6Ia;74TA?-Cpe@>=JvyKxI-xVVpewqeJ9?ledZ9P^pfCEN zKL%hR24OIUU?_%RI7VP3MqxC@U@XRAJSJcwCSfwBU@E3zI%Z%dW??qwU@qoiJ{Djh z7GW`#U@4YiIaXjLR$(>PU@g{RJvLw?HeoZiU@Nv^J9c0vc40U6U@!JzKMvp^4&gA4 z;3$saI8NXsPT@4p;4IGJJTBlOF5xn+;3}@+I&R=5Zs9iW;4bdrJ|5s99^o;b;3=Nr zIbPr;Ug0nNjn{aCfABBf;vL@O13uytKI03%;v2r>2Y%ug{=;ts1pY%H1V#`9MKAMKUBu3Zz6T zq(&N~MLMKM24qAgWJVTbMK)wd4&+2GOR7Mq4MKx4M4b(&})J7fDMLpC<12jY1WMLV=d z2XsUybVe6+MK^Ru5A;MY^hO`_ML+b%01U(+48{-)#V`!V2#mxijK&y@#W;+|1Wd#v zOvV&U#WYOE49vtV%*Gtd#XQW%0xZNLEXEQn#WF0%3arE`ti~Fw#X79V25iJ8Y{nLB z#Wrlm4(!A(?8YAK#XjuE0UX339L5nG#W5Vm37o_!oW>cP#W|eE1zf}>T*eh##Wh^V z4cx>n+{PW;#Xa1|13bhdJjN3|#WOs|3%tZD{Dr^q8gK9q{>59o!+U(dM|{F(e8E?I z!*~3^PyE7v_>F)de+Y!Y2!fyphTsT+kO+m)2!pT)hwzAih=_#9h=QnyhUkcan23eg zh=aI@hxkZ4JD1)*nhw`X^il~IjsDi4fhU%z+ny7`^sDrwwhx%xM zhG>MwXo99_hURF2mS~06XoI$BhxX`zj_8EW=z^~3hVJNrp6G?%=!3rKhyECVff$6r z7=ob~hT#~2kr;*17=y7Ghw+$ziI{}Rn1ZR8hUu7rnV5yyn1i{Phxu55g;<2eSc0Wk zhUHj+l~{$;hy6H!gE)l4ID(@%hT}Ma zlQ@ObID@k|hx53Ai@1c#xPq&=hU>V2o4AGBxP!a6hx>Sdhj@g?c!H;RhUa+khyMXj Cb_m=6 literal 0 HcmV?d00001 diff --git a/corp-marshal/code_nested_v4.marshal b/corp-marshal/code_nested_v4.marshal new file mode 100644 index 0000000000000000000000000000000000000000..a6e08893ba1ac9e810280b7256d8706959e02443 GIT binary patch literal 290 zcmYdhKmv?V_Gd02V=6;1gA_v%Lpq}-Q!-2jq<|HOnSuDT2auS`5Dk|LW;BJeg&D#a zi<$HpikXBNJlGi+@&!W~bb`+Yf)le zda5SVEyl!KjG4tuKv4ySTg*1acDESQih!mufNUvN01^!hccc{-2+gs)%&j`hazf$+ z#va$1mKV8IFR-Zoyu__q%mP%@$0yI?r^yJ`xsu^CP=uj~4M^PLu*uC&Da}c>D+1XJ WHWbA8z|6?V_?d~3QLPB*SOx&O+c4e$ literal 0 HcmV?d00001 diff --git a/corp-marshal/code_object_v4.marshal b/corp-marshal/code_object_v4.marshal new file mode 100644 index 0000000000000000000000000000000000000000..c3e16fc62aea0465557e87bf804551dfa5c40ed4 GIT binary patch literal 98 zcmYdhKmv?V_Gbixq!q6W=2NF8!ViSj72O!E&%9a5fuOc literal 0 HcmV?d00001 diff --git a/corp-marshal/containers_v2.marshal b/corp-marshal/containers_v2.marshal new file mode 100644 index 0000000000000000000000000000000000000000..a30df32ed72288059aa404330a3dcbdd7abadf59 GIT binary patch literal 127 zcmb;}Wn^GrNU6>QQJG92f*C}x00{%IT!{u)0976=lM{_i1|(LTT4Dn>3$Cja#7!%< N1B-$T&twJJ005|)4fp^6 literal 0 HcmV?d00001 diff --git a/corp-marshal/containers_v3.marshal b/corp-marshal/containers_v3.marshal new file mode 100644 index 0000000000000000000000000000000000000000..30eff82157ba71f07d96a389044a3e275cd93367 GIT binary patch literal 127 zcmb>a!pOkDkW&2;M7?AJ5zHWh1xOfxCR!^g^=YngKh*^93hfw|+kJupTPK;{X6V)DHgu literal 0 HcmV?d00001 diff --git a/corp-marshal/negative_and_huge_ints_v4.marshal b/corp-marshal/negative_and_huge_ints_v4.marshal new file mode 100644 index 0000000000000000000000000000000000000000..198f649326c5d11af288c405d638bd60117f3783 GIT binary patch literal 45 jcma!MVPIg$`ThU@e;^G3EIF(&CWvNv36%W*62t@m?W+q5 literal 0 HcmV?d00001 diff --git a/corp-marshal/recursive_list_v4.marshal b/corp-marshal/recursive_list_v4.marshal new file mode 100644 index 0000000000000000000000000000000000000000..b4f6d3c06906fcdd387c0565682cee4894c0afc9 GIT binary patch literal 10 Pcmcc3$iTo*1jGyg3flos literal 0 HcmV?d00001 diff --git a/corp-marshal/strings_v2.marshal b/corp-marshal/strings_v2.marshal new file mode 100644 index 0000000000000000000000000000000000000000..5bd92b22019b12c9f742250c1439f0ea3b1af33c GIT binary patch literal 791 zcma!MV_;w?1!9I$Mj(+`$^;^lN}0h_a;XkbG;tIV9Rj6?fB|-RPu}76$@wX%ql_UM F2movuaPI&B literal 0 HcmV?d00001 diff --git a/corp-marshal/strings_v3.marshal b/corp-marshal/strings_v3.marshal new file mode 100644 index 0000000000000000000000000000000000000000..168cd577dffd3ea7157c2f68ac9885022379e2e0 GIT binary patch literal 791 zcma!MV_;zT0>lho7=c9M7bXyy^o1ErC4bQYiYAT%qC?>8Az*+V-jjEDeR6(E>L_D~ G1_A)j^KgONtGq3#l=h@R-#{sTd*Dg$ebAy literal 0 HcmV?d00001 diff --git a/corp-marshal/types_v4.marshal b/corp-marshal/types_v4.marshal new file mode 100644 index 0000000000000000000000000000000000000000..fdab933222b7bd3fb9afb7cc34b33e229d1991e1 GIT binary patch literal 99 zcma#%V_;x-sRbgg{r~^}4J(iZ0|E@sAxsl2S_&3z=dInKj%UKztyGU<48sg)GVO$@wX% z$;Di$c_0Q?A*%*hsv-1kkil8z>v$+z2r8-b`(U?4^1D(ytNt literal 0 HcmV?d00001 diff --git a/corp-pickle/basic_dict_p4.pickle b/corp-pickle/basic_dict_p4.pickle new file mode 100644 index 0000000000000000000000000000000000000000..514bbed0808ca7609a0e8a651a73e241ad6ddbd8 GIT binary patch literal 71 zcmZo*nQFrT0ku;!dRP;43NjL>cr*5}B&C)lPKlkO;qJf!k?&!wnBvS>ImNG|Gqr~` QJux>Iq|lqGZAz&g0IF{kmH+?% literal 0 HcmV?d00001 diff --git a/corp-pickle/basic_dict_p5.pickle b/corp-pickle/basic_dict_p5.pickle new file mode 100644 index 0000000000000000000000000000000000000000..980e794161ac476f90a6d54d1a8b7bfa4e63d0aa GIT binary patch literal 71 zcmZo*ood4X0ku;!dRP;43NjL>cr*5}B&C)lPKlkO;qJf!k?&!wnBvS>ImNG|Gqr~` QJux>Iq|lqGZAz&g0IIbVmjD0& literal 0 HcmV?d00001 diff --git a/corp-pickle/bytes_and_bytearray.pickle b/corp-pickle/bytes_and_bytearray.pickle new file mode 100644 index 0000000000000000000000000000000000000000..23f30ad629b918102bb85a6c5857882ce3ce7909 GIT binary patch literal 623 zcmZo*nVQ1H00yyBG@Nu8A?#6-xDc4)!~hC0MkZz!RyKAHPA+a9UOs*SK_OugQ894| zNhxU=Svh$HMI~hwRW)@DO)YI5T|IpRLnC7oQ!{f5ODk&|TRVFPM<-_&S2uSLPcLsD zUqAnVz@Xre(6I1`$f)R;*tqzF#H8eu)U@=B%&hF3+`RmP!lL4m(z5c3%Bt#`+PeCN z#-`?$*0%PJ&aUpB-oE|`6DLicGIiSY88c_io-=pe`~?daEnc#8+42=DSFK*NcHR07 z8#isOqo2z-TnhaiMs<-ZQGQfDH)7C T9IiPznFYm}#Xv<85RSy7Blm__# literal 0 HcmV?d00001 diff --git a/corp-pickle/float_values.pickle b/corp-pickle/float_values.pickle new file mode 100644 index 0000000000000000000000000000000000000000..3cd750d01307ae4e8c95ef63dae7cabb4979d00f GIT binary patch literal 70 zcmZo*nQF}d0kKmw+@VYc_Xa4-z5d~u&#kXdEO2+=RQw&{qATHE{{bTBUjGBaNYw)X D5>^mO literal 0 HcmV?d00001 diff --git a/corp-pickle/framed_proto4.pickle b/corp-pickle/framed_proto4.pickle new file mode 100644 index 0000000000000000000000000000000000000000..42a395ed247be029b57fe8d2771e41f7e94e14aa GIT binary patch literal 2066 zcma*nH&O&K6og^S!Y=rbc`DGZqrYblJG5$mZa zqZhFuY>wCzuDpmX;o6JX7H+(V9pToC*cI-)h&|!ni`W+)yodwg(TfPFsG=8fDD2&& zB#wm55y!%{7jYuocoC<Q_7Q`w~b{VdMwXBTTb>fYFR zQKu~QegyYLmS?izsjeG0ik3Z1_~};mrCP$xzcJ`#>Kj40Llu2d) literal 0 HcmV?d00001 diff --git a/corp-pickle/memo_reuse.pickle b/corp-pickle/memo_reuse.pickle new file mode 100644 index 0000000000000000000000000000000000000000..59918eb3e138af4970812ab714e81d0438692d35 GIT binary patch literal 53 xcmZo*nX1JA0ku;!dKeR@!~!X{;*7+i)RZY1%n+E`!S5oy}k1*sjV@%uh z5lMxVSg$2cD`doWL_X~|ktb%v8Rrr6UPQcAt(S?SfQ^1-_fm0g1(yY#%@60AXw@ zgs4N?A#sp~qAEkuAvL51WMhA3zF|TsWp7MdX0|F)Eq9nz-j{u-yU=*AW1^8e==ejD t6u&Spu&{YtU+&ijH(zG?$NX}QmBZTDB#uwmj9y|pdWBv5+7~$V#}9;3F)#oC literal 0 HcmV?d00001 diff --git a/corp-pickle/nested_p3.pickle b/corp-pickle/nested_p3.pickle new file mode 100644 index 0000000000000000000000000000000000000000..3c66a18b518ad2200d7b945a234ce61a8bbe9b18 GIT binary patch literal 178 zcmYL>yAHxI3`Nr>1sdLukI2N2cArRT(" +")" +"0" +"C" +"w" +"\x80" +"\x81" +"\x84" +"\x88" +"\x89" +"\x8a" +"\x8d" +"\x8e" +"\x91" +"\xa0" +"\xa1" +"\xa2" +"\xa3" +"\xa4" +"\xa5" +"\xa6" +"\xa7" +"\xa8" +"\xa9" +"\xc0" +"\xc1" +"\xe0" +"\xe9" +"ab" +"aaa" +"\x00\x01" diff --git a/fuzzer-pickle.dict b/fuzzer-pickle.dict new file mode 100644 index 0000000..2e705ef --- /dev/null +++ b/fuzzer-pickle.dict @@ -0,0 +1,71 @@ +# pickle opcode bytes (protocol 0-5) and typical atoms +"\x80" +"\x80\x02" +"\x80\x04" +"\x80\x05" +"(" +")" +"]" +"}" +"." +"t" +"G" +"X" +"U" +"T" +"V" +"S" +"C" +"B" +"L" +"K" +"M" +"J" +"F" +"I" +"o" +"i" +"R" +"P" +"Q" +"N" +"e" +"a" +"s" +"u" +"r" +"p" +"q" +"h" +"j" +"0" +"1" +"g" +"f" +"\x8a" +"\x8b" +"\x8c" +"\x8d" +"\x8e" +"\x8f" +"\x90" +"\x91" +"\x92" +"\x93" +"\x94" +"\x95" +"\x96" +"\x97" +"\x98" +"builtins" +"__main__" +"copyreg" +"_reconstructor" +"collections" +"OrderedDict" +"defaultdict" +"encode" +"loads" +"\x8cbuiltins" +"\x8cdict" +"\x94" diff --git a/marshal.py b/marshal.py new file mode 100644 index 0000000..b0d9f22 --- /dev/null +++ b/marshal.py @@ -0,0 +1,30 @@ +"""Fuzz marshal.loads() over untrusted bytes. + +marshal is the deserialiser behind .pyc files and marshal.dumps()/loads(); +unmarshalling attacker-supplied bytes must stay memory-safe: invalid type +tags, negative or oversized length fields, dangling ref tags and malformed +code objects are all attacker-controlled. Input is capped at 1 MiB; the +deserialisation itself is expected to reject malformed streams with +EOFError/ValueError/TypeError/RecursionError/MemoryError -- anything else +propagates and aborts the fuzzer as a finding. +""" +import marshal + +MAX_MARSHAL_TEST_SIZE = 0x100000 # 1 MiB, matching the other size-capped targets + + +def FuzzerRunOne(FuzzerInput): + if len(FuzzerInput) > MAX_MARSHAL_TEST_SIZE: + return + try: + marshal.loads(FuzzerInput) + except EOFError: + pass + except ValueError: + pass + except TypeError: + pass + except RecursionError: + pass + except MemoryError: + pass diff --git a/pickle.py b/pickle.py new file mode 100644 index 0000000..a46bb01 --- /dev/null +++ b/pickle.py @@ -0,0 +1,31 @@ +"""Fuzz the C unpickler over untrusted bytes. + +pickle is the classic "never unpickle untrusted data" surface: the load +loop lives in the C accelerator _pickle.Unpickler. We subclass it only to +disable find_class, so mutated payloads cannot import arbitrary modules or +execute code inside the fuzzer process while every opcode-handling code +path (stack/memo manipulation, string and framing parsing, object +reconstruction of built-in types) stays covered. Invalid streams raise +UnpicklingError/EOFError, and object reconstruction (REDUCE, SETSTATE, +APPEND on built-in containers) can raise arbitrary exceptions -- those are +expected for attacker bytes; memory-safety bugs in the opcode machinery +still crash the sanitiser. +""" +import _pickle +import io + +MAX_PICKLE_TEST_SIZE = 0x100000 # 1 MiB + + +class FuzzerUnpickler(_pickle.Unpickler): + def find_class(self, module, name): + raise _pickle.UnpicklingError("find_class is disabled") + + +def FuzzerRunOne(FuzzerInput): + if len(FuzzerInput) > MAX_PICKLE_TEST_SIZE: + return + try: + FuzzerUnpickler(io.BytesIO(FuzzerInput)).load() + except Exception: + pass