我想将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上。