crun icon indicating copy to clipboard operation
crun copied to clipboard

Fork during static constructor makes libcrun hard to use

Open maleadt opened this issue 2 years ago • 4 comments
trafficstars

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.

maleadt avatar Dec 09 '22 21:12 maleadt

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?

maleadt avatar Dec 09 '22 21:12 maleadt

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?

rhatdan avatar Dec 10 '22 12:12 rhatdan

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.

giuseppe avatar Dec 12 '22 13:12 giuseppe

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.

rhatdan avatar Dec 12 '22 20:12 rhatdan