Wednesday May 13, 2009

Please remove the unsafe dependence on Permission.toString()

Recently, we made a correction on the implement of java.security.Permission.toString(). The specification says, "Returns a string describing this Permission. The convention is to specify the class name, the permission name, and the actions in the following format: '("ClassName" "name" "actions")'."[1] That is, the specification requires all components, ClassName, name, and actions, to be enclosed in double quotes, but JDK implementation of this method ignores this requirement, which returns string without double quotes. It seems that double quotes make sense, to differentiate between permissions of the same class with name "permit to write" and empty actions and another permission with name "permit to" and actions "write". A bug reported agasint the issue[2], and the bug was fixed recently[3].

But shortly after, I received many queries that the update break some test cases. In those test cases, the Permission.toString() is used to check against a hard coded string, which is expected no double qotes, for example,

    try {
    } catch (AccessControlException ace) {
        if (ace.getPermission().toString().indexOf("FilePermission filename read") < 0) {
            // run the codes that the exception is not a FilePermission/filename/read.
        } else {
            // run the codes that the exception is a FilePermission/filename/read.
        }
    }

The above codes' behaviors will diff with the bug fix[3], because now the the Permission.toString is expected as '"FilePermission" "filename" "read"', instead of 'FilePermission filename read".

For those application that depends on the Permission.toString() like above, I would suggest update those codes with Permission.getClass().getName(), Permissin.getName(), and Permission.getActions() accordingly. The above codes would look like:

    try {
    } catch (AccessControlException ace) {
        Permission perm = ace.getPermission();
        if (perm.getClass().getName().equals("FilePermission") && perm.getName().equals("filename") && perm.getActions("read")) {
            // run the codes that the exception is not a FilePermission/filename/read.
        } else {
            // run the codes that the exception is a FilePermission/filename/read.
        }
    }

The above code is much safer the using the Permission.toString(). For the issue, I only get reports on test cases, no reports to me on practical appliaction by now. But in case your application have similar usage as the above hard coded example, please DO remove the dependence for your application on JDK 7.

[1]: http://java.sun.com/javase/6/docs/api/java/security/Permission.html#toString()
[2]: http://bugs.sun.com/view_bug.do?bug_id=6549506
[3]: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/b656e842e1be

 

Friday Nov 10, 2006

Fine granularity diagnosis on security

You're supposed  to familiar with the java.security.debug property, otherwise please refer to the sample chapter of "Java Security".

Before Java 6, if the security debug property, java.security.debug, is enabled, a large volume of debug output will be dumped. For example, if  java.security.debug deinfed as access:stack, every stack will be dumped if a permission is checked on. Even for a simple application, the output normally runs over several pages. In server products, such as Sun Web Server and App Server, the amount of output is overwhelming, analysis them manually  is a nightmare. So customers often give up in frustration while trying to follow it to diagnose problems.

Things get changed at Java 6, the java security packages introduced two new java.security.debug options, permission and codebase. Let's have a look at the help message of security debugger.

    $ java -Djava.security.debug=help Foo

    all           turn on all debugging
    access        print all checkPermission results
    combiner      SubjectDomainCombiner debugging
    gssloginconfig
                  GSS LoginConfigImpl debugging
    jar           jar verification
    logincontext  login context results
    policy        loading and granting
    provider      security provider debugging
    scl           permissions SecureClassLoader assigns

    The following can be used with access:

    stack         include stack trace
    domain        dump all domains in context
    failure       before throwing exception, dump stack
                  and domain that didn't have permission

    The following can be used with stack and domain:

    permission.<classname>
                  only dump output if specified permission
                  is being checked
    codebase.<URL>
                  only dump output if specified codebase
                  is being checked

    Note: Separate multiple options with a comma
    

 Note that there's a bug on the help message that "permission.<classname>" should be "permission=<classname>", and "codebase.<URL>" should be "codebase=<URL>". And in the two options, spaces are not allowed before and after the sign "=".

Let's show the two options with a sample class, Foo.

// Sample class to illustrate debug options import java.io.FileInputStream; import java.io.ObjectInputStream; public class Foo { public static void main(String[] args) throws Exception { ObjectInputStream ois = null; try { FileInputStream fis = new FileInputStream("./foo.obj"); ois = new ObjectInputStream(fis); Object dummy = ois.readObject(); } finally { if (ois != null) { ois.close(); } } } }


permission=<classname>:

permission=<classname> option is used with stack trace or domain option, when a certain classname is specified, the security debugger will only dump the stacks or the domain that checking the specified permission. Here, classname is the canonical class name of the specified permission, and the classname is case sensitive.

The option is particularly useful for customers who have their own permissions to take care of, or only care to follow the evaluation details of some certain permissions.

 For the above sample class, the Java security will check the following permissions on Foo.main():

  1. java.io.FilePermission (1 time)
  2. java.lang.RuntimePermission (1 time)
  3. java.lang.reflect.ReflectPermission (5 times)

Sometimes, users maybe only want to trace the stacks that checking java.io.FilePermission, or really do not want to care java.lang.reflect.ReflectPermission. Try to run the example and see what happened.

$ java -Djava.security.manager \\
  -Djava.security.debug=access,stack Foo

(The output omitted)

$ java -Djava.security.manager \\
  -Djava.security.debug=access,stack,permission=java.io.FilePermission Foo

java.lang.Exception: Stack trace
        at java.lang.Thread.dumpStack(Thread.java:1206)
        at java.security.AccessController.checkPermission(AccessController.java:532)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
        at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
        at java.io.File.isDirectory(File.java:752)
        at sun.net.www.ParseUtil.fileToEncodedURL(ParseUtil.java:242)
        at sun.security.provider.PolicyFile.canonicalizeCodebase(PolicyFile.java:1806)
        at sun.security.provider.PolicyFile.access$700(PolicyFile.java:263)
        at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1220)
        at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1218)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1217)
        at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1165)
        at sun.security.provider.PolicyFile.implies(PolicyFile.java:1120)
        at java.security.ProtectionDomain.implies(ProtectionDomain.java:213)
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:301)
        at java.security.AccessController.checkPermission(AccessController.java:546)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
        at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
        at java.io.FileInputStream.<init>(FileInputStream.java:100)
        at java.io.FileInputStream.<init>(FileInputStream.java:66)
        at Foo.main(Foo.java:11)
access: access allowed (java.io.FilePermission /some/somedir read)

$ java -Djava.security.manager \\
  -Djava.security.debug="access,stack,permission=java.io.FilePermission \\
  permission=java.lang.RuntimePermission" Foo

(The output omitted)

codebase=<URL>:

codebase=<URL> option is used with stack trace or domain option, when a certain codebase is specified, the security debugger will only dump the stacks or the protection domain that from the specified code source defined by the codebase. Here, URL is the location of the specified code base. Note that because the comma (',") is used as multi options separator, if the URL contains comma, the security debugger would not work properly as expected, it is recommended that the URL should not include character comma (','), semicolon (';'), and  space.

This option would be useful when customer desires to trace the permissions impact of only the code in a given code souce, such as jar file.

About

A blog on security and networking

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today