Need a new access modifier?

J

John Ersatznom

I've read somewhere that inner class access to a "private" member of a
nesting class causes it to be silently treated as "package-private" by
the compiler, with security implications.

Silently changing the semantics of a security-influencing construct in
the language strikes me as bad form.

This suggests that either the implementation of inner classes needs to
change (this smells like a kludge to me), or a more elegant workaround
needs developing.

The idea that occurred to me is a new access modifier, besides
"private", "public", and "protected". The new modifier would grant
access to inner classes but not to subclasses, and not to other classes
in the same package -- only to ones nested in the correct parent class.

I don't know what its name should be. Making it blank and making the
"package" keyword do double duty as the access modifier for
package-private members sounds clean but isn't source-compatible with
older code at all -- package-private members suddenly become effectively
private, in fact, in a lot of old code if that gets done.

So it needs a new name (though allowing "package" as an explicit
access-modifier is something I'd also support, while leaving it the
default access as well). I don't know if any existing keyword is a good
choice, however. Perhaps "class", to indicate access throughout a class.
Or perhaps "private", relinquishing any "private even from inner
classes" access level, which amounts to simply getting rid of the
hackish workaround so that nested classes have access but other stuff in
the same package does not.

Or, I suppose, someone could find a way to make a package secure against
the injection of a hostile class. Maybe making the class loader reject a
class that belongs to a package where a) another class that belongs to
that package has the same name as the package's name's last
dot-separated part, but with the first letter capitalizaed and b) that
class is in a jar and the class being loaded either isn't or is in a
different jar. Then you can make com.foo.my.package contain a class
Package and stick your package in a signed jar, and nobody can sneak a
class into your package because a) if they don't put it into that same
jar the classloader will reject it but b) if they do the jar signature
won't match up and if you publish its MD5-sum this makes it
tamper-evident. Using "the jar that contains a class with the same name
as the package" to define the "official" jar for a package breaks
symmetry; otherwise someone throwing in their own jar with their own
classes in a same-named package creates an ambiguity: which set of
classes to reject for security reasons and which to accept? Now the
class loader keeps the set containing the marker-class. (If classes with
the same fully-qualified name are present in two different-MD5-sum jars
along the class path, the whole system can grind to a halt and complain
of a grievous error, since there is one.)
 
J

John W. Kennedy

John said:
I've read somewhere that inner class access to a "private" member of a
nesting class causes it to be silently treated as "package-private" by
the compiler, with security implications.

A quick test seems to contradict this. "private" appears to be "private".
 
P

Patricia Shanahan

John said:
A quick test seems to contradict this. "private" appears to be "private".

I think there is a difference between compile time and run time
treatment in this area.

"private" is enforced at compile time. However, even if the inner class
is declared "private" the generated class file for it has default access
to allow its parent class to access it.

I think the key issue here is whether access to classes from inside the
same package has security implications or not. The current treatment is
good enough to prevent accidental misuse by a non-malicious programmer.

Patricia
 
C

Chris Smith

John Ersatznom said:
I've read somewhere that inner class access to a "private" member of a
nesting class causes it to be silently treated as "package-private" by
the compiler, with security implications.

What actually happens is that the compiler generates access methods,
using the $ character in the names, to allow the access. So yes, if you
are relying on access specifiers to enforce security conditions via the
Java security architecture (i.e., SecurityManager and Permission and
related classes), you should treat things as if the variable had package
access.

Specifically, what that means is that whenever you have code that
explicitly gains additional privileges via AccessController's
doPrivileged methods, you should write that code AND all code that
performs security checks for the operation inside of a sealed package,
so that the unprivileged code cannot add classes to the same package and
subvert the access control.
Silently changing the semantics of a security-influencing construct in
the language strikes me as bad form.

The idea is that the distinction between private and package access is
not significant for security, because code that changes the security
context should always be located in a sealed package.
The idea that occurred to me is a new access modifier, besides
"private", "public", and "protected". The new modifier would grant
access to inner classes but not to subclasses, and not to other classes
in the same package -- only to ones nested in the correct parent class.

The goal of the current implementation was to minimize the impact of
language changes; specifically, to avoid major changes to the class file
format. Adding a new access modifier like that would affect not only
the VM (significant parts of which are still not aware of the existence
of nested classes), but would change the language as well. It's
unlikely to go over well.
So it needs a new name (though allowing "package" as an explicit
access-modifier is something I'd also support, while leaving it the
default access as well).

Yes, I'd certainly agree with your parenthetical comment. I don't see
how it could cause any problems in parsing or ambiguity, since one could
immediately distinguish the intended usage by looking at whether we're
inside a class or not. So who will write the RFE?
Or, I suppose, someone could find a way to make a package secure against
the injection of a hostile class.

Yes, that's what sealing packages does. It already exists. In fact,
your next paragraph (which I've snipped) pretty much describes package
sealing to the tee, including using a cryptographic signature to ensure
that the JAR file has not been modified.
 
C

Chris Smith

Patricia Shanahan said:
I think the key issue here is whether access to classes from inside the
same package has security implications or not. The current treatment is
good enough to prevent accidental misuse by a non-malicious programmer.

Yes, absolutely. The private keyword is best treated as having no
security significance at all. Package access is the significant bit for
some security purposes. (In general, though, I tend to think that many
people over-estimate the relevance of access specifiers to security in
the first place; it only matters when one is installing a new
SecurityManager and running untrusted code within the context of the
application.)
 
J

jupiter

John Ersatznom said:
I've read somewhere that inner class access to a "private" member
of a nesting class causes it to be silently treated as
"package-private" by the compiler, with security implications.


John, I have (below) a case that I think fits your description.
Does it? I'm not sure what the rule is there.



package offshore.laundering.secrets;

class HaveSecrets {

private double secretNumber = 0.0; //please do not give this to
package programmers.

public HaveSecrets() {
secretNumber = 23428347876.44;
}

/* nested class with access to private outer class member. */
class NestedHaveSecrets {
double getSecretNumber() { //This is where the WantSecrets
class has some access, but it's to a private member.
return secretNumber;
}
}
}
..............................................


package offshore.laundering.secrets;


/* Uses access to inner class to retrieve private member value. */
public class WantSecrets {

public static void main(String[] args) {
HaveSecrets haveSecrets = new HaveSecrets();
HaveSecrets.NestedHaveSecrets haveNestedSecrets = haveSecrets.new
NestedHaveSecrets();
double gotSecret = haveNestedSecrets.getSecretNumber();

System.out.println("Got filthy secrets=" + gotSecret);// yes,
this returns the filthy secret. Should it? Does this represent
the problem you mentioned?

}
}
 
J

John Ersatznom

John said:
A quick test seems to contradict this. "private" appears to be "private".

Which javac and jvm? Or was it statically compiled code with gcj? I
expect the latter especially might differ in implementation.

What test case did you use? I'd suggest

package test;

public class AccessTester1 {
private int foo;

public AccessTester1 (int x) { foo = x; }
public class FooRetriever {
public int getOuterFoo() { return foo; }
}
public FooRetriever getFooRetriever () { return new FooRetriever(); }
}


package test;

public class AccessTester2 {
public static void main (String[] args) {
AccessTester1 a = new AccessTester1(3);
AccessTester1.FooRetriever fr = a.getFooRetriever();
System.out.println(""+fr.getOuterFoo()); // 3
System.out.println(""+a.foo); // Compile error
}
}

This pair should have AccessTester2 fail to compile. Change "private int
foo;" to "int foo;" in AccessTester1 and compile both to get a working
class pair. Change back to "private int foo;" in AccessTester1 and
recompile it only (obviously don't use Eclipse or anything else that
updates everything else automatically!) and run it. It should work.
Remove FooRetriever and change getFooRetriever to int getFoo() (and
change AccessTester2 to replace the 2nd and 3rd lines of main with
"System.out.println(""+a.getFoo());") and it won't compile. Change foo's
declaration to just "int foo;" and it will, and everything works. Now
change it back without recompiling AccessTester2 and AccessTester1
should compile, but AccessTester2 should print "3" and then bomb at
runtime with an access exception of some sort because foo is private.

The *compiler* seems to treat "private" as "private", but the *runtime*
seems to treat it as "package private" when there's an inner class that
accesses the member.

Try also changing FooRetriever to return zero rather than access foo
rather than remove it entirely.

Some of this behavior is probably quite implementation-dependent, but
the failure to throw exceptions at run-time when the private member is
accessed is troubling. Besides security implications, the example above
demonstrates changing semantics for one class when the private
implementation of another is fiddled with, instead of attempted access
to said private implementation always failing in a consistent way. When
code from different sources (e.g. application code and library code, or
code in collaborative efforts) get combined queer dependencies can
result, especially if one of the coders doesn't have access to the
source for some of the other code (e.g. application coder using a
closed-source library).

I guess you can also read the above as yet another argument for open source.
 
J

John Ersatznom

Patricia said:
I think the key issue here is whether access to classes from inside the
same package has security implications or not. The current treatment is
good enough to prevent accidental misuse by a non-malicious programmer.

Unfortunately, we all know what happens when a security mechanism is
designed around the threat model of "accidental misuse by a
non-malicious programmer", don't we? :)
 
P

Patricia Shanahan

John said:
Unfortunately, we all know what happens when a security mechanism is
designed around the threat model of "accidental misuse by a
non-malicious programmer", don't we? :)

Of course. The question I'm asking is whether the distinction between
private and package access should be considered part of the security
model at all.

Do you think it should, and if so, why?

Patricia
 
J

John W. Kennedy

jupiter said:
John Ersatznom said:
I've read somewhere that inner class access to a "private" member
of a nesting class causes it to be silently treated as
"package-private" by the compiler, with security implications.


John, I have (below) a case that I think fits your description.
Does it? I'm not sure what the rule is there.



package offshore.laundering.secrets;

class HaveSecrets {

private double secretNumber = 0.0; //please do not give this to
package programmers.

public HaveSecrets() {
secretNumber = 23428347876.44;
}

/* nested class with access to private outer class member. */
class NestedHaveSecrets {
double getSecretNumber() { //This is where the WantSecrets
class has some access, but it's to a private member.
return secretNumber;
}
}
}
..............................................


package offshore.laundering.secrets;


/* Uses access to inner class to retrieve private member value. */
public class WantSecrets {

public static void main(String[] args) {
HaveSecrets haveSecrets = new HaveSecrets();
HaveSecrets.NestedHaveSecrets haveNestedSecrets = haveSecrets.new
NestedHaveSecrets();
double gotSecret = haveNestedSecrets.getSecretNumber();

System.out.println("Got filthy secrets=" + gotSecret);// yes,
this returns the filthy secret. Should it? Does this represent
the problem you mentioned?

}
}

What you are describing is documented behavior. The question is whether
a third class can access it from outside. The compiler definitely won't
allow that, but it may be achievable at runtime.
 
C

Chris Smith

Chris Smith said:
What actually happens is that the compiler generates access methods,
using the $ character in the names, to allow the access.

And checking with both javap and "strings" on a sample class file, it
appears that this is no longer the case. In any event, it was true at
some point in the past. Apparently things have now been fixed so that a
class file attribute called "InnerClasses" is used during access
checking. So there; nothing to worry about. (You should still seal any
packages used for security, because other developers generally expect
it, and they may use package access for something they intend to
protect).
 
J

John Ersatznom

Patricia said:
Of course. The question I'm asking is whether the distinction between
private and package access should be considered part of the security
model at all.

Do you think it should, and if so, why?

Either it should, or package access should be easier to lock down.
Anyone can put a class in your package simply by including "package
yourpackagename;" at the start of the code, after all. The key to
locking out such classes would probably be at the level of jar files.
You'd have to have some way for one such file to be the "canonical" one
for a given package, and then prevent class-loading anything into that
package that isn't from that jar. Making that jar tamper-evident with an
MD5 sum or similar (e.g. making it a signed jar) would then complete the
picture. The trick is dealing with the case that there's multiple jars
for a package. Which one is the "right" one? Specifying it (by MD5 or
similar hash) for every security-sensitive package in another
tamper-evident file for which there's no ambiguity is one option. That
file would be per-application rather than per-jar. Another is to use
whichever jar has a class named the same as the package in question, and
consider any case of having different jars (different hash) with classes
with the same (fully qualified) name, named after the containing
package, to be an error (and any case of nonidentical classes sharing a
fully-qualified name an error, but I expect that's already the case).
 
J

John Ersatznom

John said:
What you are describing is documented behavior. The question is whether
a third class can access it from outside. The compiler definitely won't
allow that, but it may be achievable at runtime.

My latest tests show that with the 1.6 JVM and JRE it is not. An earlier
one definitely let WantSecrets access NestedHaveSecrets if the latter
were made "private", and maybe directly the private member as well.
Certainly if the private member had a package-private accessor (at
run-time) and you had a hex editor you could hack an access of that
field into WantSecrets.class, even if NestedHaveSecrets was private and
not accessible ...
 
C

Chris Smith

John Ersatznom said:
Either it should, or package access should be easier to lock down.
Anyone can put a class in your package simply by including "package
yourpackagename;" at the start of the code, after all. The key to
locking out such classes would probably be at the level of jar files.

Again, google "Java sealed package". This already exists.
 
T

Thomas Hawtin

John said:
I've read somewhere that inner class access to a "private" member of a
nesting class causes it to be silently treated as "package-private" by
the compiler, with security implications.

The basic unit of mobile code security in Java is the package (not to be
mixed up with a 'namespace'). Don't be confused by individual signatures
for class files.

Any given ClassLoader will load into a single package only classes that
are signed with the same certificate (or only unsigned classes). Classes
with the same package name loaded by different ClassLoaders, even with a
parent-child relationship, will not have package access to one another.

So if I sign my package, you cannot get your classes in without
stripping off the signature.

The documentation for a lot of this isn't to great. Published books and
articles (most of which copy one another) are largely inaccurate. If you
do find a workable way the security, the relevant contact details for
reporting the issue are here:

http://sunsolve.sun.com/pub-cgi/show.pl?target=security/sec

Tom Hawtin
 
J

jupiter

John W. Kennedy said:
What you are describing is documented behavior. The question is
whether a third class can access it from outside. The compiler
definitely won't allow that, but it may be achievable at runtime.

Achievable at runtime you say? I think I'm in the wrong era. Do
you guys have an Andy Of Mayberry thread or something?
 
E

EJP

John said:
I've read somewhere that inner class access to a "private" member of a
nesting class causes it to be silently treated as "package-private" by
the compiler, with security implications.

Only for that access. It doesn't change the general view of the private
member from the outside.
Silently changing the semantics of a security-influencing construct in
the language strikes me as bad form.

It doesn't do that.
 
E

Ed

Thomas Hawtin skrev:

The basic unit of mobile code security in Java is the package (not to be
mixed up with a 'namespace'). snip
Tom Hawtin

Hej, Thomas. Going OT, could you elaborate? What are the differences
between a Java package and a namespace (ignoring the security thread)?
I presume you'll identify that Java packages are only named
hierarchically and that this hierarchy has no programatic basis - but I
just want to be sure I haven't missed something.

Thanks,

..ed
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top