crun
crun copied to clipboard
Fork during static constructor makes libcrun hard to use
I'm using crun from Julia, where I'm always just calling the crun binary. As there is a build option for libcrun, I wanted to try that out, but after building crun with --enable-shared and --enable-dynamic, the resulting libcrun.so isn't loadable, and even kills my Julia session:
$ julia
julia> using Libdl
julia> Libdl.dlopen("/usr/lib/libcrun.so")
/home/tim/Julia/depot/juliaup/julia-1.8.3+0.x64.linux.gnu/bin/julia: error while loading shared libraries: libjulia.so.1: cannot open shared object file: No such file or directory
$ julia
LD_DEBUG=libs reveals that after loading libcrun a search is done for libjulia in system library directories, while libjulia typically resides in a private library directory (i.e., the search is expected to fail):
2985658: calling init: /home/tim/Julia/depot/artifacts/682a441bd76a9926b58816127b0085eed6e26604/lib/libcrun.so
2985658:
2985658: find library=libdl.so.2 [0]; searching
2985658: search path=/memfd:crun_cloned:/proc/self/../lib/glibc-hwcaps/x86-64-v3:/memfd:crun_cloned:/proc/self/../lib/glibc-hwcaps/x86-64-v2:/memfd:crun_cloned:/proc/self/../lib/tls/x86_64/x86_64:/memfd:crun_cloned:/proc/self/../lib/tls/x86_64:/memfd:crun_cloned:/proc/self/../lib/tls/x86_64:/memfd:crun_cloned:/proc/self/../lib/tls:/memfd:crun_cloned:/proc/self/../lib/x86_64/x86_64:/memfd:crun_cloned:/proc/self/../lib/x86_64:/memfd:crun_cloned:/proc/self/../lib/x86_64:/memfd:crun_cloned:/proc/self/../lib:/memfd:crun_cloned:/proc/self/../lib/julia/glibc-hwcaps/x86-64-v3:/memfd:crun_cloned:/proc/self/../lib/julia/glibc-hwcaps/x86-64-v2:/memfd:crun_cloned:/proc/self/../lib/julia/tls/x86_64/x86_64:/memfd:crun_cloned:/proc/self/../lib/julia/tls/x86_64:/memfd:crun_cloned:/proc/self/../lib/julia/tls/x86_64:/memfd:crun_cloned:/proc/self/../lib/julia/tls:/memfd:crun_cloned:/proc/self/../lib/julia/x86_64/x86_64:/memfd:crun_cloned:/proc/self/../lib/julia/x86_64:/memfd:crun_cloned:/proc/self/../lib/julia/x86_64:/memfd:crun_cloned:/proc/self/../lib/julia (RPATH from file /home/tim/Julia/depot/juliaup/julia-1.8.3+0.x64.linux.gnu/bin/julia)
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/glibc-hwcaps/x86-64-v3/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/glibc-hwcaps/x86-64-v2/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/tls/x86_64/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/tls/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/tls/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/tls/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/x86_64/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/glibc-hwcaps/x86-64-v3/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/glibc-hwcaps/x86-64-v2/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/tls/x86_64/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/tls/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/tls/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/tls/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/x86_64/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/x86_64/libdl.so.2
2985658: trying file=/memfd:crun_cloned:/proc/self/../lib/julia/libdl.so.2
2985658: search cache=/etc/ld.so.cache
2985658: trying file=/usr/lib/libdl.so.2
2985658:
2985658: find library=libpthread.so.0 [0]; searching
2985658: search cache=/etc/ld.so.cache
2985658: trying file=/usr/lib/libpthread.so.0
2985658:
2985658: find library=libc.so.6 [0]; searching
2985658: search cache=/etc/ld.so.cache
2985658: trying file=/usr/lib/libc.so.6
2985658:
2985658: find library=libjulia.so.1 [0]; searching
2985658: search cache=/etc/ld.so.cache
2985658: search path=/usr/lib/glibc-hwcaps/x86-64-v3:/usr/lib/glibc-hwcaps/x86-64-v2:/usr/lib/tls/x86_64/x86_64:/usr/lib/tls/x86_64:/usr/lib/tls/x86_64:/usr/lib/tls:/usr/lib/x86_64/x86_64:/usr/lib/x86_64:/usr/lib/x86_64:/usr/lib (system search path)
2985658: trying file=/usr/lib/glibc-hwcaps/x86-64-v3/libjulia.so.1
2985658: trying file=/usr/lib/glibc-hwcaps/x86-64-v2/libjulia.so.1
2985658: trying file=/usr/lib/tls/x86_64/x86_64/libjulia.so.1
2985658: trying file=/usr/lib/tls/x86_64/libjulia.so.1
2985658: trying file=/usr/lib/tls/x86_64/libjulia.so.1
2985658: trying file=/usr/lib/tls/libjulia.so.1
2985658: trying file=/usr/lib/x86_64/x86_64/libjulia.so.1
2985658: trying file=/usr/lib/x86_64/libjulia.so.1
2985658: trying file=/usr/lib/x86_64/libjulia.so.1
2985658: trying file=/usr/lib/libjulia.so.1
2985658:
/home/tim/Julia/depot/juliaup/julia-1.8.3+0.x64.linux.gnu/bin/julia: error while loading shared libraries: libjulia.so.1: cannot open shared object file: No such file or directory
Note that the above also reproduces with libcrun from Arch Linux, so doesn't seem related to my build.
Now, Julia being a managed environment does its fair share of library loading shenanigans, but this is something I haven't encountered with other libraries. I wonder if libcrun is doing anything special? A quick grep didn't reveal any .init/.init_array code hooking library loading.
Ah, I found it: https://github.com/containers/crun/blob/313fc8a6ad3a8c758d3fcfc62898bf199f33f0a3/src/libcrun/linux.c#L4962-L4972
That's too bad; Julia is not compatible with being forked, so I guess that makes it impossible to use libcrun.
Although this seems like a very heavyweight solution to that CVE; shouldn't it be restricted to the crun binary?
I actually think this should be made optional, in that it is only needed for security purposes to fix a potential vulnerability in the host OS. If you are running rootless containers, this vulnerability does not exists. It was found that a container process could overwrite the crun (ociruntime) executeable. @giuseppe what do you think about making this optional?
sure we can disable that and make it optional, but how will you deal with this security issue?
What should the interface look like though? I still want it to be enabled by default, so it should be opt-out.
I agree, although I still believe we should figure a way to be smarter in rootless mode.
--nofork option would fix the problem. Allow distributions to change the default in C code via Makefile, so they would not need to deal with it perhaps.