Derby
  1. Derby
  2. DERBY-3363

AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.net.www.protocol.c)

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 10.3.2.1
    • Fix Version/s: None
    • Component/s: Services, Tools
    • Environment:
    • Urgency:
      Normal
    • Bug behavior facts:
      Security

      Description

      I got one AccessControlException when I tried to backup my derby database using code like:

      Statement statement;
      String dbPath;
      ...

      statement.executeUpdate("CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE('" + dbPath + "')");

      ==

      I run my code with the default security manager installed. The exception stack trace is:

      java.security.AccessControlException: access denied (java.lang.RuntimePermission
      accessClassInPackage.sun.net.www.protocol.c)
      at java.security.AccessControlContext.checkPermission(AccessControlConte
      xt.java:264)
      at java.security.AccessController.checkPermission(AccessController.java:
      427)
      at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
      at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:151
      2)
      at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:265)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
      at java.net.URL.getURLStreamHandler(URL.java:1141)
      at java.net.URL.<init>(URL.java:572)
      at java.net.URL.<init>(URL.java:464)
      at java.net.URL.<init>(URL.java:413)
      at org.apache.derby.impl.store.raw.RawStore.backup(Unknown Source)
      at org.apache.derby.impl.store.access.RAMAccessManager.backup(Unknown So
      urce)
      at org.apache.derby.impl.db.BasicDatabase.backup(Unknown Source)
      at org.apache.derby.catalog.SystemProcedures.SYSCS_BACKUP_DATABASE(Unkno
      wn Source)
      at org.apache.derby.exe.ac3a7f0048x0117xc98bxe062x0000001202800.g0(Unkno
      wn Source)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
      java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
      sorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:585)
      at org.apache.derby.impl.services.reflect.ReflectMethod.invoke(Unknown S
      ource)
      at org.apache.derby.impl.sql.execute.CallStatementResultSet.open(Unknown
      Source)
      at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown So
      urce)
      at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown So
      urce)
      at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
      at org.apache.derby.impl.jdbc.EmbedStatement.executeUpdate(Unknown Sourc
      e)
      at com.elixirtech.ers2.db.DBSystem.systemUpdate(Unknown Source)

      ==

      I did some quick debug. I guess the problem happens because Derby generates some classes on the fly but forgets to assign proper security domains when loading the generated classes (such as 'org.apache.derby.exe.ac3a7f0048x0117xc98bxe062x0000001202800'). When the generated code tried to access some sun.* packages, the security check failed.

      Ideally, Derby code should call

      ClassLoader.defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain)

      instead of

      ClassLoader.defineClass(String name, byte[] b, int off, int len)

      1. DerbyBackupTest.zip
        2.17 MB
        Song Guo Qiang

        Activity

        Hide
        Kathey Marsden added a comment -

        Do you have a reproducible test case for this issue?

        Show
        Kathey Marsden added a comment - Do you have a reproducible test case for this issue?
        Hide
        Daniel John Debrunner added a comment -

        Derby intentionally does not assign any security domain to the generated class (loader). This is for two reasons:

        1) Derby being a library does not assume that all the code in the stack has permissions to perform any security controlled action, thus it uses privileged blocks around sensitive operations to allow the privilege to be only granted to Derby code. Thus there is no need to grant permissions (though a security domain) to generated code on the stack.

        2) Generated code having zero permissions provides a level of security where remote code installed by a (remote) user cannot perform privileged actions such as shutting down the vm or opening files, thus bypassing Derby's SQL security.

        Thus I think the fix is that code that opens the URL (or creates it?) needs to be in a privilege block.

        Show
        Daniel John Debrunner added a comment - Derby intentionally does not assign any security domain to the generated class (loader). This is for two reasons: 1) Derby being a library does not assume that all the code in the stack has permissions to perform any security controlled action, thus it uses privileged blocks around sensitive operations to allow the privilege to be only granted to Derby code. Thus there is no need to grant permissions (though a security domain) to generated code on the stack. 2) Generated code having zero permissions provides a level of security where remote code installed by a (remote) user cannot perform privileged actions such as shutting down the vm or opening files, thus bypassing Derby's SQL security. Thus I think the fix is that code that opens the URL (or creates it?) needs to be in a privilege block.
        Hide
        Song Guo Qiang added a comment - - edited

        This test case (see attachment) helps to reveal the problems when Derby does not assign proper security domain to generated classes.

        This folder contains a Eclipse project so you can open it and run the test case in the current folder.

        Then you should see the following exception stack trace (using JDK 1.5.0_11):

        java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.net.www.protocol.c)
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
        at java.security.AccessController.checkPermission(AccessController.java:427)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
        at ElxSecurityManager.checkPermission(ElxSecurityManager.java:18)
        at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1512)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:265)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
        at java.net.URL.getURLStreamHandler(URL.java:1141)
        at java.net.URL.<init>(URL.java:572)
        at java.net.URL.<init>(URL.java:464)
        at java.net.URL.<init>(URL.java:413)
        at org.apache.derby.impl.store.raw.RawStore.backup(Unknown Source)
        at org.apache.derby.impl.store.access.RAMAccessManager.backup(Unknown Source)
        at org.apache.derby.impl.db.BasicDatabase.backup(Unknown Source)
        at org.apache.derby.catalog.SystemProcedures.SYSCS_BACKUP_DATABASE(Unknown Source)
        at org.apache.derby.exe.ac601a400fx0117xe8b9x0cb5x0000001875c80.g0(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.derby.impl.services.reflect.ReflectMethod.invoke(Unknown Source)
        at org.apache.derby.impl.sql.execute.CallStatementResultSet.open(Unknown Source)
        at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
        at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
        at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
        at org.apache.derby.impl.jdbc.EmbedStatement.executeUpdate(Unknown Source)
        at BackupTest.main(BackupTest.java:34)

        ==

        What happended was:

        1/ I tried to backup the database into folder 'C:/the_project_location/db/backup'.

        2/ In derby's method (RawStore.backup()), the code does the following:

        String backupDirURL = null;
        try

        { URL url = new URL(backupDir); backupDirURL = url.getFile(); }

        catch (MalformedURLException ex) {}

        if (backupDirURL != null)
        backupDir = backupDirURL;

        Basically it treats the given file path as URL. So the java.net.URL class was called.

        3/ The URL class checked the input, and assume "C" is a protocol name, so it tried to look for protocol handler for it and it tried to load the handler as "sun.net.www.protocol.c.Handler" from system class loader (sun.misc.Launcher$AppClassLoader)

        4/ The system class loader checked if the caller has permission to access package "sun.net.www.protocol.c" and found that the Derby-generated class (org.apache.derby.exe.ac3a7f0048x0117xc98bxe062x0000001202800) did not have any security domain, so it threw AccessControlException.

        5/ The ElxSecurityManager class noticed the exception and logged it. (That's what we saw on console.)

        6/ The java.net.URL.getURLStreamHandler method captures the exception and ignored it. Then it tired some other ways to determine the protocol handler. At last, the method could not find any handler for "C", so it threw MalformedURLException.

        7/ The RawStore.backup method captured this MalformedURLException, knowing it's not a URL, and treated the input as a file path.

        8/ At last, the database was backuped successfully.

        ==

        So in conclusion:

        1/ The exception we saw on the console was a warning, but there was no real problem.

        2/ This test shows you some potential problem if Derby does not assign proper security domain to the generated classes.

        Personally, I think the generated classes should have the same security domain as classes loaded from Derby.jar. Then you (as Derby developer) can avoid calling doPrivileged and save a lot of time for debuging issues like this.

        Show
        Song Guo Qiang added a comment - - edited This test case (see attachment) helps to reveal the problems when Derby does not assign proper security domain to generated classes. This folder contains a Eclipse project so you can open it and run the test case in the current folder. Then you should see the following exception stack trace (using JDK 1.5.0_11): java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.net.www.protocol.c) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264) at java.security.AccessController.checkPermission(AccessController.java:427) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at ElxSecurityManager.checkPermission(ElxSecurityManager.java:18) at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1512) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:265) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.net.URL.getURLStreamHandler(URL.java:1141) at java.net.URL.<init>(URL.java:572) at java.net.URL.<init>(URL.java:464) at java.net.URL.<init>(URL.java:413) at org.apache.derby.impl.store.raw.RawStore.backup(Unknown Source) at org.apache.derby.impl.store.access.RAMAccessManager.backup(Unknown Source) at org.apache.derby.impl.db.BasicDatabase.backup(Unknown Source) at org.apache.derby.catalog.SystemProcedures.SYSCS_BACKUP_DATABASE(Unknown Source) at org.apache.derby.exe.ac601a400fx0117xe8b9x0cb5x0000001875c80.g0(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.derby.impl.services.reflect.ReflectMethod.invoke(Unknown Source) at org.apache.derby.impl.sql.execute.CallStatementResultSet.open(Unknown Source) at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source) at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source) at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source) at org.apache.derby.impl.jdbc.EmbedStatement.executeUpdate(Unknown Source) at BackupTest.main(BackupTest.java:34) == What happended was: 1/ I tried to backup the database into folder 'C:/the_project_location/db/backup'. 2/ In derby's method (RawStore.backup()), the code does the following: String backupDirURL = null; try { URL url = new URL(backupDir); backupDirURL = url.getFile(); } catch (MalformedURLException ex) {} if (backupDirURL != null) backupDir = backupDirURL; Basically it treats the given file path as URL. So the java.net.URL class was called. 3/ The URL class checked the input, and assume "C" is a protocol name, so it tried to look for protocol handler for it and it tried to load the handler as "sun.net.www.protocol.c.Handler" from system class loader (sun.misc.Launcher$AppClassLoader) 4/ The system class loader checked if the caller has permission to access package "sun.net.www.protocol.c" and found that the Derby-generated class (org.apache.derby.exe.ac3a7f0048x0117xc98bxe062x0000001202800) did not have any security domain, so it threw AccessControlException. 5/ The ElxSecurityManager class noticed the exception and logged it. (That's what we saw on console.) 6/ The java.net.URL.getURLStreamHandler method captures the exception and ignored it. Then it tired some other ways to determine the protocol handler. At last, the method could not find any handler for "C", so it threw MalformedURLException. 7/ The RawStore.backup method captured this MalformedURLException, knowing it's not a URL, and treated the input as a file path. 8/ At last, the database was backuped successfully. == So in conclusion: 1/ The exception we saw on the console was a warning, but there was no real problem. 2/ This test shows you some potential problem if Derby does not assign proper security domain to the generated classes. Personally, I think the generated classes should have the same security domain as classes loaded from Derby.jar. Then you (as Derby developer) can avoid calling doPrivileged and save a lot of time for debuging issues like this.
        Hide
        Daniel John Debrunner added a comment -

        Existing Application impact is a flag that indicates the solution will affect existing applications by requiring change to an application, thus since no solution exists yet the flag is not valid.
        http://db.apache.org/derby/DerbyBugGuidelines.html#Set+appropriate+special+%22flags%22

        Show
        Daniel John Debrunner added a comment - Existing Application impact is a flag that indicates the solution will affect existing applications by requiring change to an application, thus since no solution exists yet the flag is not valid. http://db.apache.org/derby/DerbyBugGuidelines.html#Set+appropriate+special+%22flags%22
        Hide
        Tiago R. Espinha added a comment -

        Triaged for 10.5.2.

        No changes made.

        Show
        Tiago R. Espinha added a comment - Triaged for 10.5.2. No changes made.

          People

          • Assignee:
            Unassigned
            Reporter:
            Song Guo Qiang
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:

              Time Tracking

              Estimated:
              Original Estimate - 48h
              48h
              Remaining:
              Remaining Estimate - 48h
              48h
              Logged:
              Time Spent - Not Specified
              Not Specified

                Development