Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protecting fields from Reflection - The strange case of the System.security

I am currently looking into java security and came across a strange phenomenon. The SecurityManager in java is stored in the field "security" in java.lang.System. Interestingly, the field seems to be protected against reflective access, which does make sense, but as far as I know this field is the only one which is. So here is the example:

for(Field f : System.class.getDeclaredFields())
    System.out.println(f);

outputs

public static final java.io.InputStream java.lang.System.in
public static final java.io.PrintStream java.lang.System.out
public static final java.io.PrintStream java.lang.System.err
private static volatile java.io.Console java.lang.System.cons
private static java.util.Properties java.lang.System.props
private static java.lang.String java.lang.System.lineSeparator

Interestingly: the field declared as

private static volatile SecurityManager security = null;

is not in the list, and sure enough a call to

System.class.getDeclaredField("security"); 

yields a NoSuchFieldException. As I couldn't find anything about this online, and I am pretty sure this field used to be accessible via reflection (see also, for example, this blog post from 2010 which describes accessing this field) I was wondering a) was this implemented as a quick fix to prevent easily disabling the securitymanager via reflection and b) how this is implemented (or rather is there any chance of protecting other private fields from reflection as well).

like image 1000
Arno Mittelbach Avatar asked Jul 22 '13 20:07

Arno Mittelbach


1 Answers

A colleague pointed out that the answer is not in the jvm but in the jdk, more precisely in the class sun.reflect.Reflection. There you'll find a static initializer that does the following

static {
    Map<Class,String[]> map = new HashMap<Class,String[]>();
    map.put(Reflection.class,
        new String[] {"fieldFilterMap", "methodFilterMap"});
    map.put(System.class, new String[] {"security"});
    fieldFilterMap = map;

    methodFilterMap = new HashMap<Class,String[]>();
}

If we now look a bit closer at the getDeclaredFields method in java.lang.Class we'll find that the fields are filtered using a call to the Reflection class:

Reflection.filterFields(this, getDeclaredFields0(publicOnly));

where filterFields is implemented as

public static Field[] filterFields(Class containingClass,
                                   Field[] fields) {
    if (fieldFilterMap == null) {
        // Bootstrapping
        return fields;
    }
    return (Field[])filter(fields, fieldFilterMap.get(containingClass));
}

So .. this solves the issue how the field is protected. I am however still curious as to why this was implemented.

like image 93
Arno Mittelbach Avatar answered Oct 31 '22 07:10

Arno Mittelbach