如何向本机库添加功能,而不是向运行它的可执行文件添加功能?

Chr*_*ckx 6 java linux java-native-interface linux-capabilities

语境

我已经完成了一个 Java 库,它使用带有 JNI 的 C 库。C库在linux中编译成.so文件。这个库需要cap_net_raw 能力

目标

执行一个没有额外权限的java 进程,该进程使用所述 java 库。将使用该库的实际进程是产品中已经存在的进程,我们不想授予它们更多权限。

为了测试这一点,我创建了一个jar并在使用和不使用sudo. 正如预期的那样,使用它会成功,但如果没有它,它就会失败。

重现测试的步骤

  1. 创建一个带有本地方法的java类,我们来调用它SocketTester.java
static {
    System.loadLibrary("SocketTester");
}
private native int socketTest();
Run Code Online (Sandbox Code Playgroud)
  1. socketTester.h使用命令生成文件
javac -h . SocketTester.java
Run Code Online (Sandbox Code Playgroud)
  1. 创建socketTester.c实现socketTester.h并需要该cap_net_raw功能的文件
  2. 编译用
gcc -o libSocketTester.so socketTester.c -shared -I/usr/lib/jvm/java-14-openjdk-amd64/include -I/usr/lib/jvm/java-14-openjdk-amd64/include/linux
Run Code Online (Sandbox Code Playgroud)
  1. 移动libSocketTester.so到/usr/lib
  2. 跑步
sudo ldconfig
Run Code Online (Sandbox Code Playgroud)
  1. 设置上限
cd /usr/lib
sudo setcap cap_net_raw=epi libSocketTester.so
Run Code Online (Sandbox Code Playgroud)
  1. 创建一个Test.java
public static void main(final String[] args) {
    SocketTester tester = new SocketTester();
    tester.socketTest();
}
Run Code Online (Sandbox Code Playgroud)
  1. SocketTester.java使用和创建一个 jarTest.java
  2. 运行测试
java -cp socketTester.jar Test
Run Code Online (Sandbox Code Playgroud)

我已经尝试过的

.so向库添加上限

sudo setcap cap_net_raw=epi libSocketTester.so
Run Code Online (Sandbox Code Playgroud)

结果:失败

为java添加上限

sudo setcap cap_net_raw=epi /usr/lib/jvm/java-14-openjdk-amd64/bin/java
Run Code Online (Sandbox Code Playgroud)

结果:它有效,但这不是我想要的,因为现在所有 java 进程都具有该功能(请参阅目标部分中的粗体)。

问题

为什么添加上限不起作用.so?我还能如何实现目标?

And*_*gan 1

无数年前,我想出了如何让 PAM 模块分叉一个帮助程序,以便从非特权上下文中执行特权操作。这就是如何pam_unix.so能够调用unix_chkpwd来帮助非特权应用程序(ascreensaverscreen)接受用户密码以在 Linux 下解锁。

最近,我学习了使共享库对象(libcap.sopam_cap.so作为独立二进制文件工作的技巧。从那时起,我一直在考虑将这两种技术结合起来......研究这一点时,我遇到了这个问题。由于我能够为绑定到 port 的非特权程序的示例任务执行此操作80,因此我认为这里的答案可能会很有趣。

我已经完整地描述了它在完全可用的libcap分发站点上的工作原理,但它本质上可以归结为三件事:

  • 使文件作为独立程序.so可执行,具有自己的文件功能
  • 在文件中包含一些代码,.so用于在链接到另一个程序时计算出自己的文件名(这使用_GNU_SOURCE扩展名:)dladdr()
  • 为库本身创建一些机制,libcap:cap_launch()以通过私有通信机制(我使用使用 生成的 Unix 域套接字)分叉/执行自身(我使用socketpair())返回到应用程序链接的共享库代码。

流程基本上是,应用程序调用该.so函数,该函数将.so文件作为分叉子进程调用并执行特权操作。然后它通过 Unix 域套接字将结果返回给应用程序并退出。