3

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?

Kokomelom
  • 143
  • 1
  • 10

3 Answers3

0

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 ?

Philippe
  • 20,025
  • 2
  • 23
  • 32
0

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.

Alex O
  • 7,746
  • 2
  • 25
  • 38
  • I don't sure that I understand you offer but 1)my library is injected not ignored. 2)how can I verify of `systemd`runs my ELF in set-user-ID mode? – Kokomelom May 04 '22 at 20:02
  • Handling of `LD_PRELOAD` within `systemd` environments depends on your particular version of `ld.so` and `systemd`. E.g., the `ld.so` version on Arch Linux has a special [secure execution mode](https://man.archlinux.org/man/ld.so.8.en) that disables `LD_PRELOAD` support in certain environments. – Alex O May 05 '22 at 06:53
  • how can I read that configuration on my system and loaded(is that write on /etc/*** ?)? And as I wrote in the post, my inject_libssl.so is loaded but loaded after the original so – Kokomelom May 06 '22 at 05:21
0

I tried all the suggestions in this and some locations on the web I could find. None worked except the wrapper. I added the SETUID bit, copied the .so file first to /tmp, then to /usr/lib/x86_64-linux-gnu, then tried to include the library without slashes, i.e.

...
[Service]
Environment="MARK=10 LD_PRELOAD=mark.so"
...

Still no-go. An interactive run, however, worked as expected (I was setting up a route-jail for nginx). The LD_PRELOAD also could not be placed in front of the executable name on the ExecStart line, as it resulted in an error.

In the end, creating a wrapper worked, and the systemctl operation still seems to be normal, i.e., systemctl brings up the service, shows its status, and shuts it down as expected. I ended up with:

...
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/tmp/testnginx.sh
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
...

The only line modified in the systemd script is ExecStart. The wrapper (which I'll move to some more sensible location from /tmp), is simple:

#!/bin/bash

MARK=10 LD_PRELOAD=mark.so /usr/sbin/nginx -g 'daemon on; master_process on;'

The wrapper is just chmod 755; it doesn't have the SETUID bit set.

This is on Ubuntu 22.04.

Ville
  • 4,088
  • 2
  • 37
  • 38