Stephen,
I think the reason you get the IllegalAccessError is because the VM
thinks you are loading from a remote url.
I don't think the user of a classloader per-se forces the
verification of the class. (I wrote a class loader like yours that
just loads a file with no package in the current dir and was able to
access the private method).
You can also note that your class isn't verified if -noverify is
passed (perhaps this is obvious :)
-- Michael
On 5/13/06, Stephen de Vries <stephen_at_corsaire.com> wrote:
>
> On 12 May 2006, at 09:10, Charles Miller wrote:
> >
> > It's not reflection: you're confusing IllegalAccessException and
> > IllegalAccessError.
> >
> > For any non-Java nerd still listening in: there are two fundamental
> > types of "Throwable" exception-conditions in Java: Exceptions and
> > Errors[1]. Exceptions represent application-level conditions --
> > things an application is likely to be able to recover from, like
> > network timeouts, trying to read beyond the end of a file, and so
> > on. Errors, on the other hand, represent VM-level problems that an
> > application can't really do anything about, like running out of
> > memory, not finding a required native library, or encountering
> > corrupted class files.
> >
> > IllegalAccessException happens when reflective code attempts to
> > access some field or method it's not supposed to. Because it's a
> > result of reflection, it's considered an application-level problem
> > and it's assumed your code can recover gracefully.
> >
> > Amusingly enough, you can get around most IllegalAccessExceptions
> > in java just by calling {field|method}.setAccessible(true). So long
> > as there's no explicit SecurityManager installed, as soon as you've
> > done that you're free to modify the field or call method to your
> > heart's content[2].
> >
> > IllegalAccess_Error_, on the other hand, happens when some non-
> > reflective code issues a bytecode instruction that attempts to
> > access a field or method it shouldn't be able to see. If you look
> > at its class hierarchy, the meaning of the class is pretty clear:
> > IllegalAccessError is a subclass of IncompatibleClassChangeError,
> > which is a subclass of LinkageError. Because this is a problem at
> > the bytecode/classloading level, and literally something that could
> > happen on _any_ method-call or field-access, it's flagged as an error.
> >
> > The Error generally occurs when class A has been compiled against a
> > version of class B where a method is public, but that method is
> > private in the version of the same class it encounters at runtime.
> > This sort of thing happens quite often in Java, you're frequently
> > stuck in "jar file hell", in a twisty turny maze of library
> > interdependencies, all with slightly different version numbers.
> >
> > More about the circumstances of IllegalAccessError here:
> >
> > http://java.sun.com/docs/books/vmspec/2nd-edition/html/
> > ConstantPool.doc.html
> >
> > Dynamic classloading isn't really at fault here. There are all
> > sorts of pits you can fall into when you start rolling your own
> > classloader (the Java webapp I develop supports dynamic runtime-
> > deployable plugins, and the classloading issues are a HUGE
> > headache), but IllegalAccessError isn't one of them.
> >
> > Charles
> >
> > [1] Exceptions are further divided into checked exceptions and
> > runtime exceptions, but that's beyond the scope of this email
> > [2] See also: http://www.javaspecialists.co.za/archive/
> > Issue014.html
>
> Thanks for clearing this up Charles.
> I've created another example that uses a class loader to load the
> classes, and this time, it throws an IllegalAccessError just like
> Tomcat does:
>
> Loading class: /Users/stephen/data/dev/classloader/myclass/
> somepackage/MyTest.class
> Loading class: /Users/stephen/data/dev/classloader/myclass/java/lang/
> Runnable.class
> Loading class: /Users/stephen/data/dev/classloader/myclass/java/lang/
> Object.class
> Loading class: /Users/stephen/data/dev/classloader/myclass/
> somepackage/MyData.class
> Loading class: /Users/stephen/data/dev/classloader/myclass/java/lang/
> System.class
> Exception in thread "main" java.lang.IllegalAccessError: tried to
> access method somepackage.MyData.getName()Ljava/lang/String; from
> class somepackage.MyTest
> at somepackage.MyTest.run(MyTest.java:15)
> at classloader.Main.main(Main.java:26)
> Java Result: 1
>
> This error is thrown irrespective of the -verify flag. So it looks
> like using a classloader causes the VM to perform verification,
> whether or not the "verifier" was enabled. Michael Silk made a
> similar statement earlier in this thread. Would you agree?
>
> PoC code below:
>
> package classloader;
>
> public class Main {
>
> public Main() {
> }
>
> public static void main(String[] args) {
> //Illegal Access Error
> try {
> CustomLoader cl = new CustomLoader(System.getProperty
> ("user.dir")+"/myclass/");
> Class myClass = cl.loadClass("somepackage.MyTest");
> Runnable r = (Runnable)myClass.newInstance();
> r.run();
>
> } catch (Exception e) {
> e.printStackTrace();
> }
>
>
> }
>
> }
>
>
> package classloader;
>
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.IOException;
>
> public class CustomLoader extends ClassLoader {
> private String path = null;
>
> public CustomLoader(String path) {
> this.path = path;
> }
>
>
> private byte[] getBytes( String filename ) throws IOException {
> File file = new File( filename );
> long len = file.length();
> byte raw[] = new byte[(int)len];
> FileInputStream fin = new FileInputStream( file );
> int r = fin.read( raw );
> if (r != len)
> throw new IOException( "Can't read all, "+r+" != "+len );
> fin.close();
> return raw;
> }
>
> public Class loadClass( String name, boolean resolve )
> throws ClassNotFoundException {
> Class clas = null;
> String fileStub = name.replace( '.', '/' );
> String classFilename = path+fileStub+".class";
> System.out.println("Loading class: "+classFilename);
> File classFile = new File( classFilename );
> try {
> byte raw[] = getBytes( classFilename );
> clas = defineClass( name, raw, 0, raw.length );
> } catch( IOException ie ) {
> }
> if (clas==null) {
> clas = findSystemClass( name );
> }
>
> if (resolve && clas != null)
> resolveClass( clas );
>
> if (clas == null)
> throw new ClassNotFoundException( name );
> return clas;
> }
> }
>
> In current directory create a folder ./myclass/somepackage with the
> following two files:
>
> package somepackage;
>
> public class MyData {
> private String name;
>
> public MyData() {
> name = "No one can read me";
> }
>
> public String getName() {
> System.out.println("private method called");
> return (name);
> }
> }
>
> package somepackage;
>
> public class MyTest implements Runnable {
> MyData m;
>
> public MyTest() {
> m = new MyData();
> }
>
> public void run() {
> System.out.println(m.getName());
> }
> }
>
> Compile both these classes, then change the MyData.getName method to
> private access, and recompile MyData.
>
>
>
> Stephen
>
> _______________________________________________
> Secure Coding mailing list (SC-L)
> SC-L_at_securecoding.org
> List information, subscriptions, etc - http://krvw.com/mailman/listinfo/sc-l
> List charter available at - http://www.securecoding.org/list/charter.php
>
-------------------------------------------------------------------------
Sponsored by: Watchfire
Methodologies & Tools for Web Application Security Assessment
With the rapid rise in the number and types of security threats, web
application security assessments should be considered a crucial phase in
the development of any web application. What methodology should be
followed? What tools can accelerate the assessment process?
Download this whitepaper today!
https://www.watchfire.com/securearea/whitepapers.aspx?id=701300000007t9h
--------------------------------------------------------------------------
Received on May 13 2006