Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to allocate closure when SELinux is enabled and non-root user is used #1505

Open
rqpb opened this issue Feb 21, 2023 · 8 comments
Open

Comments

@rqpb
Copy link

rqpb commented Feb 21, 2023

JNA fails to load a native library if SELinux is enabled and I run my code as a non-root user. I tested with Lazysodium for Java, but I don't think that this issue is specific to this particular library only.

Changing the SELinux mode to the permissive doesn't help and there is no record in /var/log/audit/audit.log.

If I run my code as root, the error won't occur. If I disable SELinux and I run my code as a non-root, the error won't occur either.

OS: Amazon Linux 2
System architecture: x86_64
Java: OpenJDK Runtime Environment (build 1.8.0_352-b08)
JNA version: 5.13.0

Stacktrace

Exception in thread "main" java.lang.UnsupportedOperationException: Failed to allocate closure
        at com.sun.jna.Native.registerMethod(Native Method)
        at com.sun.jna.Native.register(Native.java:1906)
        at com.sun.jna.Native.register(Native.java:1775)
        at com.goterl.resourceloader.SharedLibraryLoader.registerLibraryWithClasses(SharedLibraryLoader.java:81)
        at com.goterl.resourceloader.SharedLibraryLoader.load(SharedLibraryLoader.java:58)
        at com.goterl.lazysodium.utils.LibraryLoader.loadBundledLibrary(LibraryLoader.java:134)
        at com.goterl.lazysodium.utils.LibraryLoader.loadLibrary(LibraryLoader.java:95)
        at com.goterl.lazysodium.SodiumJava.<init>(SodiumJava.java:34)
        at com.goterl.lazysodium.SodiumJava.<init>(SodiumJava.java:23)

Steps to reproduce:

import com.goterl.lazysodium.SodiumJava;

public class JnaTest {

    public static void main(String[] args) {
        SodiumJava sodiumJava = new SodiumJava();
    }

}

Dependencies:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.13.0</version>
</dependency>
<dependency>
    <groupId>com.goterl</groupId>
    <artifactId>lazysodium-java</artifactId>
    <version>5.1.4</version>
</dependency>
@matthiasblaesing
Copy link
Member

It is invalid to raise issues that are not confirmed. You think JNA is an issue here, but question should not be raised here, but on the mailinglist. I don't think, that the message in the issue template is that subtle.

At least provide steps to reproduce, that can be ran without getting an AWS machine, I might then be interested in looking into this.

@rqpb
Copy link
Author

rqpb commented Feb 22, 2023

I'm sorry for reporting this issue. I should have read the template more carefully. Feel free to close and I will use the mailinglist instead.

Anyway, I found out that the error occurs if a non-root user doesn't have write access to his home directory. The native library was loaded sucessfully, after I granted write access to home.

Can you confirm that JNA requires write access to the user's home under certain conditions? If so, what are those conditions?

I would propose to add a new section to the FAQ such as Calling Native.registerMethod() causes an UnsupportedOperationException: Failed to allocate closure.

I'm sorry that I can't provide steps to reproduce. The machine where the error occured has some hardened Amazon Linux 2 and I didn't gather enough details about it yet.

@matthiasblaesing
Copy link
Member

Anyway, I found out that the error occurs if a non-root user doesn't have write access to his home directory. The native library was loaded sucessfully, after I granted write access to home.

Yes - this commit introduces the behavior:

fe02b87

before that java.io.tmpdir was used, which was at that time often /tmp, which was mounted noexec. The new location is either $XDG_CACHE_HOME/JNA/temp or $HOME/.cache/JNA/temp. I think the expectation, that the users home is writeable is a sane default. If you need it, you can override the location using the jna.tmpdir system property.

Can you confirm that JNA requires write access to the user's home under certain conditions? If so, what are those conditions?

It is required, if you don't manually install the native library somewhere accessible on the filesystem and tell JNA to use that. Be warned: the version of the native library and the JNA library must match, if that is not the case, bad things will happen.

I would propose to add a new section to the FAQ such as Calling Native.registerMethod() causes an UnsupportedOperationException: Failed to allocate closure.

As described above, I think it is an unlikely situation.

@rqpb
Copy link
Author

rqpb commented Feb 28, 2023

I ran a few more tests and these are the results:

  1. If I unzip libjnidispatch.so manually to a new directory and point the jna.boot.library.path property to that directory, it works fine.
  2. If the home directory is writeable, then JNA will unpack libjnidispatch.so to a temporary file such as $HOME/.cache/JNA/temp/jna2472649883313566092.tmp and it works fine.
  3. If the home directory is readonly, then JNA will unpack libjnidispatch.so to a temporary directory (java.io.tmpdir), the library is loaded, but Native.registerMethod fails with the Failed to allocate closure error.
  4. If the home directory is readonly and SELinux is disabled, then JNA will unpack libjnidispatch.so to a temporary directory (java.io.tmpdir) and it works fine.

I still didn't get enough details about the hardening that was done on the target machine, so that I can't say what's the cause of the error.

Regarding the readonly home, I think it isn't so unlikely in server environments where access is restricted for security reasons. Moreover, it seems that JNA doesn't require writeable home under certain conditions. I'm wondering what these conditions are exactly.

@matthiasblaesing
Copy link
Member

If java.io.tmpdir is mounted noexec loading will fail, which was the start of the whole journey.

@dbwiddis
Copy link
Contributor

I would propose to add a new section to the FAQ such as Calling Native.registerMethod() causes an UnsupportedOperationException: Failed to allocate closure.

As described above, I think it is an unlikely situation.

There are a handful of unlikely situations, including this and other access issues, app restrictions (e.g. Apple App store) that require signed binaries, and JDK bugs like #1506, all of which can be worked around by pre-extracting or locally building the native library. Of note, Loading JNA is the first section of the overview which addresses how to do this. There's probably room for a more generic hand-wavy link to that section in the FAQ with a mention of "permissions". I can try to add something if you agree.

@rqpb
Copy link
Author

rqpb commented Mar 2, 2023

If java.io.tmpdir is mounted noexec loading will fail, which was the start of the whole journey.

Yes, if java.io.tmpdir is mounted noexec loading will fail, but with a different error, for example UnsatisfiedLinkError: failed to map segment from shared object. That error indicates that there is an issue in my environment that I need to fix on my own.

However, I think that in my case, the native library was loaded (System.loadLibrary succeeded), but there was some internal initialization that failed. As I couldn't find any description of that error, I came to a conclusion that it's either a bug or the documentation is incomplete.

@dbwiddis
Copy link
Contributor

@rqpb I'm happy to try to fix the documentation if you think it's complete, but I'd like a little more detail on where you think it should be improved.

The first section of the overview seems to solve most issues associated with the "tmpdir" and I think it's reasonable to add a Q&A in the FAQ pointing there. Can you suggest what the content should say?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants