Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fork during static constructor makes libcrun hard to use #1097

Open
maleadt opened this issue Dec 9, 2022 · 4 comments
Open

Fork during static constructor makes libcrun hard to use #1097

maleadt opened this issue Dec 9, 2022 · 4 comments

Comments

@maleadt
Copy link
Contributor

maleadt commented Dec 9, 2022

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
Copy link
Contributor Author

maleadt commented Dec 9, 2022

Ah, I found it:

crun/src/libcrun/linux.c

Lines 4962 to 4972 in 313fc8a

/* Protection for attacks like CVE-2019-5736. */
int ensure_cloned_binary ();
__attribute__ ((constructor)) static void
libcrun_rexec (void)
{
if (ensure_cloned_binary () < 0)
{
fprintf (stderr, "Failed to re-execute libcrun via memory file descriptor\n");
_exit (EXIT_FAILURE);
}
}

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?

@rhatdan
Copy link
Member

rhatdan commented Dec 10, 2022

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?

@maleadt maleadt changed the title dlopening libcrun kills managed runtime Fork during static constructor makes libcrun hard to use Dec 10, 2022
@giuseppe
Copy link
Member

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.

@rhatdan
Copy link
Member

rhatdan commented Dec 12, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants