This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gcj is not type-safe


Hi all,

This email is part brain-dump, part request for comments.  I've been
looking into the bug detailed in http://tinyurl.com/qcgwv, the basic
idea of which is that because of the way Java associates objects with
their classes it is possible to associate an object with an arbirtary
classe and thus circumvent its access restrictions.  So you have an
instance of this class:

  class R {
    private int r = 1;
  }

and you trick the VM into treating it as an instance of this class:

  class R {
    public int r;
  }

The code in the attached tarball is based on the code from that
website.  Test.java sets up a funky classloader that sometimes
delegates to the system classloader and sometimes does not.  It
then loads a class with it (ersatz/RT.java) and executes its main
method, which does this:

    RR rr = new RR();
    R r = rr.getR();

On the first line the classloader delegates the loading of RR to the
system classloader, which loads RR.class as you would expect.  On the
second line two things happen:

 1. rr.getR() does simply 'return new R()'.  R is not yet loaded, so
    RR's classloader (the system classloader) loads it.  It gets the
    real R.class, with the private member variable.

 2. Back in RT.main, R is not yet loaded, so RT's classloader (the
    funky one) loads it.  It gets the ersatz R.class, with the public
    member variable.

Sun fixed this in Java 1.2 by introducing loading constraints.
http://tinyurl.com/3xh934 explains this somewhat.  There are two
concepts involved:

 a) The classloader responsible for defining a type is referred to
    as that type's defining classloader.

 b) Any classloader that initiates the loading of a type, directly
    or indirectly, is referred to as an initiating classloader of
    that type.

In Sun's JRE:

 1. When RR is loaded:

    The delegating classloader is an initiating classloader of RR.
    The system classloader is an initiating classloader of RR.
    The system classloader is the defining classloader of RR.

 2. When R is loaded inside RR.getR():

    The system classloader is an initiating classloader of R.
    The system classloader is the defining classloader of R.

 3. When R is loaded inside RT.main():

    The delegating classloader is an initiating classloader of R.
    The delegating classloader is the defining classloader of R.

What Sun would seem to do is to make classes inherit the initiating
classloaders of their parent classes.  This means that in #2 above
it is also true that:

  The delegating classloader is an initiating classloader of R.

Each classloader maintains a list of the classes it is an initiating
classloader of.  The loading constraint that stops this bug is that
a classloader cannot be an initiating classloader of any class it has
already been the initiating classloader of.  So, at step #3, when
loading R in RT.main() the JRE will see that the the delegating
classloader will find that it has already been the initiating
classloader of a class named "R" and throw a LinkageError.

I looked through libgcj and it seems that partial support for this is
already in place.  There's a function, _Jv_RegisterInitiatingLoader,
which gets called from all manner of places, but what it is doing is
maintaining within each classloader a list of classes that that
classloader is the defining classloader for.  The list does not seem
to be used anywhere, and there's an entry in classpath/NEWS suggesting
that classpath used this list in the past (a broken fix for this very
issue perhaps) but that it does not use it now:

 * Removed loadedClasses map from ClassLoader. It's now the VM's
   responsibility to manage the list of defined and loaded classes
   for each class loader.  (September 6, 2005)

One possible fix would be to fix _Jv_RegisterInitiatingLoader to
actually register initiating loaders (as opposed to defining loaders)
and make it perform the check, but the number of different places
that _Jv_RegisterInitiatingLoader is called from makes me uneasy
about this: ideally I'd like to find one single place I could put
these checks. It's a pain that no method in java.lang.ClassLoader
is declared as final because you can't just put the checks in that
method and rely on the fact than no subclass can override it.  I
guess the constructor for java.lang.Class would be another place
I could look.

Ok, that's where I'm at...

Cheers,
Gary

Attachment: spoof.tar.gz
Description: GNU Zip compressed data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]