如何在systemd中设置LD_PRELOAD



我想将libssl中的一些函数与systemd中的LD_PRELOAD挂钩。

在systemd文件中放入

ExecStart=/etc/myscript.sh

,在/etc/myscript.sh中放入

#!/bin/sh
LD_PRELOAD=/lib/inject_libssl.so /bin/run

当我看/proc/RUN_PID/maps时,我可以看到inject_libssl。所以实际上是注入到进程中,而不是原始的libssl。So是在被注入的库之前加载的,所以我的钩子不起作用。

我也试过

ExecStart=/bin/run 
Environment="LD_PRELOAD=/lib/inject_libssl.so"

但我得到了相同的结果。

如果我运行LD_PRELOAD=/lib/inject_libssl.so curl https://google.com注入的libssl工作良好。

为什么呢?

你能试一下这个脚本看看哪一个会被加载吗?

#!/usr/bin/env bash

cp /lib/x86_64-linux-gnu/libssl.so /tmp/inject_libssl.so
LD_PRELOAD=/tmp/inject_libssl.so /bin/run

你能试着把你的。so也放在/usr/lib/x86_64-linux-gnu吗?

原因可能是systemd以set-user-ID模式运行您的脚本/二进制文件。根据动态链接器文档,LD_PRELOAD支持是有限的:

对于set-user-ID/set-group-ID ELF二进制文件,预加载路径名包含斜杠被忽略,标准搜索中的库只有set-user-ID权限位为时,才会加载目录在库文件上启用。

因此,您需要将库复制到适当的位置并提供相应的权限。您可以使用特定的User=设置或使用包装器来解决这个问题。

我尝试了所有的建议,并在网上找到了一些地方。除了包装器,其他的都不起作用。我添加了SETUID位,首先将.so文件复制到/tmp,然后复制到/usr/lib/x86_64-linux-gnu,然后尝试包含没有斜杠的库,即

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

还不方便。然而,交互式运行如预期的那样工作(我为nginx设置了一个路由监狱)。LD_PRELOAD也不能放在ExecStart行可执行文件名的前面,因为这会导致错误。

最后,创建包装器工作了,systemctl操作似乎仍然正常,即systemctl启动服务,显示其状态,并按预期关闭它。最后是:

...
[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
...

systemd脚本中唯一修改的行是ExecStart。包装器(我将从/tmp移动到更合理的位置)很简单:

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

包装器只是chmod 755;它没有设置SETUID位。

这是在Ubuntu 22.04上。

相关内容

  • 没有找到相关文章

最新更新