How to set LD_PRELOAD in systemd - linux

I want to hook some functions in libssl with LD_PRELOAD in systemd.
In systemd file I put
ExecStart=/etc/myscript.sh
and in /etc/myscript.sh I put
#!/bin/sh
LD_PRELOAD=/lib/inject_libssl.so /bin/run
When I look at /proc/RUN_PID/maps I can see that inject_libssl.so is realy injected to the process but the original libssl.so is loaded before the the injected library, so my hook doesn't work.
I olso tried
ExecStart=/bin/run
Environment="LD_PRELOAD=/lib/inject_libssl.so"
But I got the same results.
If I run LD_PRELOAD=/lib/inject_libssl.so curl https://google.com the injected libssl works well.
Why is that please?

Can you try this script to see which one will be loaded ?
#!/usr/bin/env bash
cp /lib/x86_64-linux-gnu/libssl.so /tmp/inject_libssl.so
LD_PRELOAD=/tmp/inject_libssl.so /bin/run
Can you also try to put your .so in /usr/lib/x86_64-linux-gnu ?

The reason is probably that systemd runs your script / binary in set-user-ID mode. According to the dynamic linker documentation, LD_PRELOAD support is limited then:
For set-user-ID/set-group-ID ELF binaries, preload pathnames
containing slashes are ignored, and libraries in the standard search
directories are loaded only if the set-user-ID permission bit is
enabled on the library file.
So you need to copy your library to the proper place and provide the permission accordingly. You might be able to work around this with a specific User= setting or by using a wrapper.

Related

make: i686-linux-gnu-ld: Command not found

i want to install cpanm WWW::Curl::Form on my Synology NAS. But that fails. Here is the output cpanm WWW::Curl::Form WWW::Curl::Easy File::Find::Rule String::CRC32 URI::Escape
--> Working on WWW::Curl::Form
Fetching http://www.cpan.org/authors/id/S/SZ/SZBALINT/WWW-Curl-4.17.tar.gz ... OK
Configuring WWW-Curl-4.17 ... OK
Building and testing WWW-Curl-4.17 ... FAIL
! Installing WWW::Curl::Form failed. See /var/services/homes/fox/.cpanm/work/1541095458.25803/build.log
the log file gives me:
make: i686-linux-gnu-ld: Command not found
But i dont know how to fix it on my Synology NAS (DSM 6.2 and appollolake architecture DS918+)
After reviewing your additional comments, I believe I have potential solution. It looks like you are trying to install some Perl modules via the default Perl shell, cpan. As part of the installation process, the make utility is being executed. This utility is heavily used for compiling and building source from C and C++ source code, along with other languages.
The make utility is trying to call some executable i686-linux-gnu-ld which is a linker, see ld. A linker is a utility used in C programming for linking (combining) multiple compiled object files into a single executable binary. make is calling this utility as some sort of build process. Instead of calling i686-linux-gnu-ld it should probably just be calling ld. The only thing I am not sure about is why it is using the full name of the utility instead of ld.
I can think of two solutions. The first would be to update the make file to use the correct name for the linker. I'm not sure how you would do this when it is being installed via cpan since it is downloading a package and executing the make file before you have a chance to modify it. The other option is to create a symbolic link from the incorrect name and path of ld that the make file is using to the correct path /opt/bin/ld. This will result in ld being called when i686-linux-gnu-ld is called. Also, I forgot to mention it earlier but the which command will tell you where an executable / command is located on your shell's path.
The Stack Overflow post, How to symlink a file in Liunx?, gives a good explanation of how to create a symlink. You need to create a symlink to point to the correct name and path of the linker. To do so run the following command:
ln -s /opt/bin/ld /usr/bin/i686-linux-gnu-ld
Depending on the permissions of these directories you may need to run this command under a account with elevated permissions or via sudo. I apologize for this post being rather long and verbose. I just wanted to explain my solution in detail. I hope this helps. Please let me know if this doesn't resolve the problem.
edit: fixed typo in the command.

Set linker search path for build in CMake

It seems this question has been asked very often before but none of the solutions seem to apply in my case.
I'm in a CMake/Linux environment and have to run an executable binary during the build step (protoc in particular).
This binary needs a library but it's not installed (and cannot be) in the in the standard directories like /usr, so the library cannot be found.
Unfortunately I cannot manipulate the protoc call because it's embedded in a 3rd party script.
I can now set LD_LIBRARY_PATH before every make or set it system wide but this is very inconvenient especially when it comes to IDEs in which the build takes place or distributed build scenarios with continuous build environments.
I tried to set LD_LIBRARY_PATH via
set(ENV{LD_LIBRARY_PATH} "/path/to/library/dir")
but this seems to have no effect during the build step.
So my question is: can I set a library search path in CMake which is used during the build?
Try this
SET(ENV{LD_LIBRARY_PATH} "/path/to/library/dir:$ENV{LD_LIBRARY_PATH}")
I also used this dirty trick to temporary change some environment variables:
LD_LIBRARY_PATH="/path/to/library/dir:$LD_LIBRARY_PATH" cmake ...
After execution of this line LD_LIBRARY_PATH is not changed in the current shell.
Also, I do not find it bad to change LD_LIBRARY_PATH before invoking cmake:
export LD_LIBRARY_PATH=...
It won't change anything system-wide, but it would be used for your current shell, current build process. The same holds for CI builds. You can save the variable and restore it after cmake invocation:
MY_LD=$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=...
cmake...
export LD_LIBRARY_PATH=$MY_LD
I have recently run into a somewhat similar problem.
My solution was to incorporate sourcing a file that set the appropriate environment into every command.
For example, this custom command:
add_custom_command(
OUTPUT some_output
COMMAND some_command
ARGS some_args
DEPENDS some_dependencies
COMMENT "Running some_command some_args to produce some_output"
)
Would become:
set(my_some_command_with_environment "source my_environment_script.sh && some_command")
add_custom_command(
OUTPUT some_output
COMMAND bash
ARGS -c "${my_some_command_with_environment} some_args"
DEPENDS some_dependencies
COMMENT "Running some_command some_args to produce some_output"
VERBATIM
)
Obviously, this has some disadvantages:
It relies on a bash shell being available.
It sources the environment script for every command invocation (performance issue) and you will have to change all invocations of commands that rely on that environment variables.
It changes the normal syntax of having the command follow COMMAND and the arguments follow ARGS, as now the 'real' command is part of the ARGS.
My CMake-Fu has proven insufficient to find a syntactically nicer way of doing this, but maybe somebody can comment a nicer way.
I had a similar issue for an executable provided by a third party library. The binary was linked against a library not provided by the distribution but the required library was included in the libs directory of the third party library.
So running LD_LIBRARY_PATH=/path/to/thirdparty/lib /path/to/thirdparty/bin/executable worked. But the package config script didn't set up the executable to search /path/to/thirdparty/lib for the runtime dependent so CMake would complain when CMake tried to run the executable.
I got around this by configuring a bootstrap script and replacing the IMPORTED_LOCATION property with the configured bootstrapping script.
_thirdpartyExe.in
#!/bin/bash
LD_LIBRARY_PATH=#_thirdpartyLibs# #_thirdpartyExe_LOCATION# "$#"
CMakeLists.txt
find_package(ThirdPartyLib)
get_target_property(_component ThirdPartyLib::component LOCATION)
get_filename_component(_thirdpartyLibs ${_component} DIRECTORY)
get_target_property(_thirdpartyExe_LOCATION ThirdPartyLib::exe IMPORTED_LOCATION)
configure_file(
${CMAKE_CURRENT_LIST_DIR} _thirdpartyExe.in
${CMAKE_BINARY_DIR}/thirdpartyExeWrapper #ONLY
)
set_target_properties(ThirdPartyLib::exe PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/thirdpartyExeWrapper)
Honestly I view this as a hack and temporary stop gap until I fix the third party library itself. But as far as I've tried this seems to work on all the IDE's I've thrown at it, Eclipse, VSCode, Ninja, QtCreator, ... etc

Starting a program in a chroot environment returns immediately

I am working in a virtual environment, trying to start open vm tools in a chroot environment.
I tested with bash and it seems to work fine.
I used ./configure --options --prefix=/home/chroot_env to install the program, then using ldd on vmtoolsd, i copied the corresponding libraries to the /lib directory.
Now when I start chroot /home/chroot_env /bin/vmtoolsd, nothing happens, the chroot returns directly. Launching the same binary in the normal environment does work.
Does someone have an idea why it isn't working, the correct libraries are there, and it works with bash.
EDIT : strace showed that vmtoolsd is trying to access /dev/console, I added mount --bind /dev/ /home/chroot_env/dev/ but it is still failing.
EDIT2 : another strace showed it was looking for another plugin loaded dynamically, i added it and it worked, conclusion strace is great for debugging such issue!
When you run a program and nothing happens, you can always run it with strace in order to see which syscalls are made. This is an easy way to obtain the list of the files (regular or not) that are opened. In your case, check that your program doesn't try to access a file that is not in the chroot.

Linux binary can't find shared library, but works while running in strace

(Note: names of the binary and binary and library below are obfuscated to protect the innocent. ;-) The app is proprietary under NDA but the behavior may not depend on it.)
I have a Linux binary which prints the following error when run:
binary: error while loading shared libraries: libshared.so: cannot open shared object file: No such file or directory
Which is confusing on its own since libshared.so is in the LD_LIBRARY_PATH. However,
The library is found correctly when running ldd binary (i.e., the ldd output points to the file location)
The library is found correctly when running strace binary, so that the program manages to print its usage information!
I have never seen an application which behaves differently when run on its own vs in strace, but I figure maybe someone else has seen this happen before? Any ideas how to resolve this?
I don't have the source so I can't rebuild. Running the app in production under strace is probably a non-starter. The OS is RHEL 6.2.
(Old question, but hopefully this will help somebody else)
Under new Linux installations, LD_LIBRARY_PATH is not used by the standard system runtime linker for programs with SUID set. It appears that strace, gdb and friends work differently, and do use LD_LIBRARY_PATH.
For suid programs, all libraries must be found in the system library cache. Check (as root) whether your "missing" library is present using
ldconfig -p | grep <my_library_name>
and, if anything's missing, add it to a new file in /etc/ld.so.conf or ld.so.conf.d/ as appropriate, and then rebuild using
ldconfig -v
Or remove the SUID bit if it's not required, of course.
This really helped me a lot!
I was having a similar problem where libraries were not being picked up properly from the LD_LIBRARY_PATH, even when the ldd command showed all libraries were satisfied. However, when troubleshooting using strace, it was working. In my case, however, the problem was that SGID (set group ID sticky bit being on). When the files were installed, the sysadmin did a recursive chmod that set it on all files (including the executables). Once the SGID was removed on the executables, the libraries were now found without strace and everything worked as it should using the LD_LIBRARY_PATH.

ERROR: ld.so: object LD_PRELOAD cannot be preloaded: ignored

I am using ubuntu 12.04. Every time I start my bash terminal and every time when I finish typing a command(and press enter) , I get this message:
ERROR: ld.so: object '/usr/lib/liblunar-calendar-preload.so' from
LD_PRELOAD cannot be preloaded: ignored.
It is weird.
So what is the environment variable LD_PRELOAD used for? And what is the going on behind the scene?
Thanks.
The linker takes some environment variables into account. one is LD_PRELOAD
from man 8 ld-linux:
LD_PRELOAD
A whitespace-separated list of additional, user-specified, ELF
shared libraries to be loaded before all others. This can be
used to selectively override functions in other shared
libraries. For setuid/setgid ELF binaries, only libraries in
the standard search directories that are also setgid will be
loaded.
Therefore the linker will try to load libraries listed in the LD_PRELOAD variable before others are loaded.
What could be the case that inside the variable is listed a library that can't be pre-loaded. look inside your .bashrc or .bash_profile environment where the LD_PRELOAD is set and remove that library from the variable.
If you want to make sure that the library is loaded if and only if the program lunar-calendar-gtk is launched, you can apply this:
You set the environment variable per command by prefixing the command with it:
$ LD_PRELOAD="liblunar-calendar-preload.so" printenv "LD_PRELOAD"
liblunar-calendar-preload.so
$ printenv "LD_PRELOAD"
$
You can then choose to put this in a shell script and make lunar-calendar-gtk a symlink to this shell script, replaceing the original referencee. This effectively makes sure that the library is loaded everytime the original application is executed.
You will have to rename the original lunar-calendar-gtk to something else, which might not be too intriguing as it possibly may cause issues with uninstallation and upgrading. However, I found it useful with a former version of Skype.
Thanks for the responses. I think I've solved the problem just now.
Since LD_PRELOAD is for setting some library proloaded, I check the library that ld preloads with LD_PRELOAD, one of which is "liblunar-calendar-preload.so", that is not existing in the path "/usr/lib/liblunar-calendar-preload.so", but I find a similar library "liblunar-calendar-preload-2.0.so", which is a difference version of the former one.
Then I guess maybe liblunar-calendar-preload.so was updated to a 2.0 version when the system updated, leaving LD_PRELOAD remain to be "/usr/lib/liblunar-calendar-preload.so". Thus the preload library name was not updated to the newest version.
To avoid changing environment variable, I create a symbolic link under the path "/usr/lib"
sudo ln -s liblunar-calendar-preload-2.0.so liblunar-calendar-preload.so
Then I restart bash, the error is gone.
It means the path you input caused an error. In your LD_PRELOAD command, modify the path like the error tips:
/usr/lib/liblunar-calendar-preload.so
I got this type of error when I installed Citrix client on my Raspberry Pi. In short there is a file /etc/ld.so.preload. The library my system was complaining about was listed in that file. I commented it out with a # and system stopped complaining.
The solution that worked for me was using sudo vim and going into /etc/ld.so.preload
I then just removed the line
/usr/local/lib/AppProtection/libAppProtection.so
Then I just saved the file and everything worked without issues.
When I executed the following command, everything became better.
unset LD_PRELOAD
You can check /etc/ld.so.preload file content
I fix it by:
echo "" > /etc/ld.so.preload

Resources