I've done a java library that uses a C library with JNI.
The C library is compiled in linux into a .so
file. This library needs cap_net_raw
capabilities.
Execute a java process without additional privileges, that uses said java library. The actual processes that are going to use the library are existing processes already in prod and we don't want to give them more rights.
To test that, I've created a jar
and run it both with and without sudo
. As expected, it succeeds with but fail without it.
SocketTester.java
static {
System.loadLibrary("SocketTester");
}
private native int socketTest();
socketTester.h
file with the commandjavac -h . SocketTester.java
socketTester.c
file that implements socketTester.h
and which needs the cap_net_raw
capabitilygcc -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
libSocketTester.so
to /usr/libsudo ldconfig
cd /usr/lib
sudo setcap cap_net_raw=epi libSocketTester.so
Test.java
classpublic static void main(final String[] args) {
SocketTester tester = new SocketTester();
tester.socketTest();
}
SocketTester.java
and Test.java
java -cp socketTester.jar Test
.so
libsudo setcap cap_net_raw=epi libSocketTester.so
Result: Failure
sudo setcap cap_net_raw=epi /usr/lib/jvm/java-14-openjdk-amd64/bin/java
Result: It works, but it's not what I want because now all java process have the capability (see bold in goal section).
Why is adding the cap to the .so
doesn't work? How else can I accomplish the goal?
Typically the native libraries are in the RID specific section, so for example in ".NETCoreApp,Version=v2.1/ubuntu.14.04-x64", so that on a any given platform the right native library is picked. Oh okay, could you make that work without copying the file to the output directory?
Managed assemblies are referenced like: Typically the native libraries are in the RID specific section, so for example in ".NETCoreApp,Version=v2.1/ubuntu.14.04-x64", so that on a any given platform the right native library is picked. Sorry, something went wrong. This is the default behavior.
To deploy a native library with a Xamarin.Android library project, add the library binary to the project and set its Build Action to EmbeddedNativeLibrary. Note that since Android supports multiple Application Binary Interfaces (ABIs), Xamarin.Android must know which ABI the native library is built for.
If you want to add a native library without interfering with java.library.path at development time in Eclipse (to avoid including absolute paths and having to add parameters to your launch configuration), you can supply the path to the native libraries location for each Jar in the Java Build Path dialog under Native library location.
A zillion years ago I figured out how to have PAM modules fork a helper program to do privileged things from unprivileged contexts. This is how pam_unix.so
is able to invoke unix_chkpwd
to help an unprivileged application (a screensaver
, or screen
) accept a user password to unlock under Linux.
More recently, I learned the trick to making shared library objects (libcap.so
, pam_cap.so
etc) work as standalone binaries. I've since been thinking about combining both of these techniques... Researching that, I came across this question. Since I was able to do it for the example task of an unprivileged program binding to port 80
, I thought it might be of interest as an answer here.
I've done a full write up of how it works on the Fully Capable libcap
distribution site, but it essentially boils down to three things:
.so
file executable as a stand alone program, with its own file capability.so
file that figures out its own filename when linked into another program (this uses a _GNU_SOURCE
extension: dladdr()
)libcap:cap_launch()
) with a private communication mechanism (I use a Unix domain socket generated with socketpair()
) back to the app-linked shared library code.The flow is basically, app calls the .so
function, that function invokes the .so
file as a forked child and performs the privileged operation. It then returns the result to the app over the Unix domain socket and exits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With