Home AMX User Forum Duet/Cafe Duet

Java restrictive vs permissive permissions

tombadgertombadger Posts: 22
edited July 2023 in Duet/Cafe Duet

Hi,

Related to below command:
set java [permissive|restrictive] Set/Query java permissions

What are differences between those two java operation modes?
Should permissive mode disable custom security manager (KFSecurityManager) ?

Another command should have disabled security manager.
java security
Java Security Manager is DISABLED.

But it seems security manager is still being used.

Before Java 1.8u172 there was a bug related to custom security manager and possible stack overflow issue.
https://bugs.openjdk.org/browse/JDK-8166366

Since NX is running on 1.8u171 (as of FW 1.6.205 and even 1.8.x) we are experiencing above issue that usually leads to SNAPI router crash and there is no longer communication between Netlinx and Java parts.

Exception in thread "SWROUTER" java.lang.StackOverflowError
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessController.doPrivileged(Native Method)
at java.io.FilePermission.init(FilePermission.java:203)
at java.io.FilePermission.init(FilePermission.java:203)
at java.io.FilePermission.(FilePermission.java:277)
at java.io.FilePermission.(FilePermission.java:277)
at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
at java.io.File.isDirectory(File.java:844)
at java.io.File.isDirectory(File.java:844)
at sun.net.www.ParseUtil.fileToEncodedURL(ParseUtil.java:269)
at sun.net.www.ParseUtil.fileToEncodedURL(ParseUtil.java:269)
at sun.security.provider.PolicyFile.canonicalizeCodebase(PolicyFile.java:1733)
at sun.security.provider.PolicyFile.canonicalizeCodebase(PolicyFile.java:1733)
at sun.security.provider.PolicyFile.access$700(PolicyFile.java:257)
at sun.security.provider.PolicyFile.access$700(PolicyFile.java:257)
at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1186)
at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1186)
at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1184)
at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1184)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1183)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1183)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1130)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1130)
at sun.security.provider.PolicyFile.implies(PolicyFile.java:1084)
at sun.security.provider.PolicyFile.implies(PolicyFile.java:1084)
at org.knopflerfish.framework.permissions.FrameworkPolicy$1.run(FrameworkPolicy.java:146)
at org.knopflerfish.framework.permissions.FrameworkPolicy$1.run(FrameworkPolicy.java:146)
at org.knopflerfish.framework.permissions.FrameworkPolicy$1.run(FrameworkPolicy.java:144)
at org.knopflerfish.framework.permissions.FrameworkPolicy$1.run(FrameworkPolicy.java:144)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessController.doPrivileged(Native Method)
at org.knopflerfish.framework.permissions.FrameworkPolicy.implies(FrameworkPolicy.java:144)
at org.knopflerfish.framework.permissions.FrameworkPolicy.implies(FrameworkPolicy.java:144)
at java.security.ProtectionDomain.implies(ProtectionDomain.java:285)
at java.security.ProtectionDomain.implies(ProtectionDomain.java:285)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:450)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:450)
at org.knopflerfish.framework.permissions.PostponementCheck.run(PostponementCheck.java:100)
at org.knopflerfish.framework.permissions.PostponementCheck.run(PostponementCheck.java:100)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessController.doPrivileged(Native Method)
at org.knopflerfish.framework.permissions.KFSecurityManager.checkPermission(KFSecurityManager.java:71)
at org.knopflerfish.framework.permissions.KFSecurityManager.checkPermission(KFSecurityManager.java:71)
at org.knopflerfish.framework.permissions.KFSecurityManager.checkPermission(KFSecurityManager.java:83)
at org.knopflerfish.framework.permissions.KFSecurityManager.checkPermission(KFSecurityManager.java:83)
at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
at java.lang.SecurityManager.checkRead(SecurityManager.java:888)

Comments

  • Try setting the system security manager to null in the module class constructor:

    System.setSecurityManager(null);

  • tombadgertombadger Posts: 22

    @HARMAN_icraigie said:
    Try setting the system security manager to null in the module class constructor:

    System.setSecurityManager(null);

    I believe I've tried that already, but it was not allowed (permission denied).

  • @tombadger said:

    @HARMAN_icraigie said:
    Try setting the system security manager to null in the module class constructor:

    System.setSecurityManager(null);

    I believe I've tried that already, but it was not allowed (permission denied).

    hmm - that's been the solution here for the few times we have found that same issue. You could try setting Java permissive but that has not been a requirement from our observations.

  • tombadgertombadger Posts: 22

    I was wrong, System.setSecurityManager(null) does not return permission denied.

    On the other hand I did some metric monitoring and I have noticed that there is memory leak when using HttpsUrlConnection.
    With single duet module and 64MB of JVM memory, JVM starts crashing within 6h from boot.
    Memory usage varies between 40 and 100%.

    After increasing memory to 128MB, it seems to work ok for few days, but memory usage is also increasing slowly over that time (so again memory leak).

    This is first time I decided to use HttpsURLConnection instead of Apache Http Client in duet module.
    Here is the affected code:

    public void sendData() {
        if (queue.isEmpty()) {
            log(DEBUG, "No data points to send");
            return;
        }
    
        if (getDebugState() == INFO) {
            log(INFO, String.format("%s data points to send", queue.size()));
        }
    
        SSLSocketFactory sslSocketFactory;
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom());
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (Exception e) {
            log(ERROR, "SSL context creation error: " + e.getMessage());
            return;
        }
    
        HttpsURLConnection connection = null;
        try {
            connection = (HttpsURLConnection) new URL(serverUrl).openConnection();
            connection.setConnectTimeout(5_000);
            connection.setReadTimeout(5_000);
            connection.setHostnameVerifier((hostname, session) -> true);
            connection.setSSLSocketFactory(sslSocketFactory);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("Authorization", "Token " + serverToken);
            connection.setRequestProperty("Connection", "close");
            connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
            connection.setChunkedStreamingMode(0);
    
            try (OutputStream outputStream = connection.getOutputStream();
                 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
                String point;
                int pollCount = 0;
                int writeCount = 0;
                while (queue.size() > 0 && pollCount < 15) {
                    point = queue.poll();
                    pollCount++;
                    if (point != null) {
                        bufferedOutputStream.write(point.getBytes(StandardCharsets.UTF_8));
                        writeCount++;
                    }
                }
                if (getDebugState() == INFO) {
                    log(INFO, String.format("Sent %s data points", writeCount));
                }
            }
    
            int responseCode = connection.getResponseCode();
            boolean isSuccessful = responseCode >= 200 && responseCode < 400;
            log(isSuccessful ? DEBUG : ERROR, "Server response code: " + responseCode);
    
            try (InputStream inputStream = isSuccessful ? connection.getInputStream() : connection.getErrorStream();
                 ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                if (getDebugState() == DEBUG) {
                    String response = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
                    log(DEBUG, "Server response body: " + response);
                }
            }
        } catch (IOException e) {
            log(ERROR, "Error while sending data points:  " + e.getMessage());
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
    
  • I'm not aware of that leak but there is an implementation of Apache httpclient/HttpsUrl in all released AMX Duet modules so that may have been a work around the pre dates me.

Sign In or Register to comment.