Security

David M. Lloyd david.lloyd at redhat.com
Wed Oct 21 11:38:57 UTC 2015


On 10/05/2015 01:45 PM, mark.reinhold at oracle.com wrote:
> 2015/9/17 8:34 -0700, david.lloyd at redhat.com:
>> On 09/17/2015 09:56 AM, mark.reinhold at oracle.com wrote:
>>> 2015/9/11 10:15 -0700, forax at univ-mlv.fr:
>>>> While this change may improve the security, it's a
>>>> backward incompatible change is not strictly required to support
>>>> modules it's more an enhancement of the current security model and i
>>>> don't think it's a good idea to mix it with the introduction of the
>>>> module support.
>>>
>>> This is not an enhancement of the security model per se (which would,
>>> anyway, be beyond the scope of this JSR).  This change is, rather, in
>>> service of the strong-encapsulation goal (which does, of course, help
>>> ensure security).
>>
>> I think this assertion should be substantiated with some examples.
>>
>> While strong encapsulation is good in terms of design principles, to me
>> it's only evident that this somehow leads to better security in the most
>> hand-wavy possible way (in particular, as it relates to this specific
>> mechanism).
>
> Three of the five zero-day vulnerabilities reported since JDK 7 GA would
> have been prevented if we'd had the ability to strongly encapsulate
> JDK-internal packages in the manner proposed, via access-control checks
> enforced by the VM.
>
> Here are public analyses of two of them:
>
>    https://partners.immunityinc.com/idocs/Java%20MBeanInstantiator.findClass%200day%20Analysis.pdf
>    http://immunityproducts.blogspot.com/2012/08/java-0day-analysis-cve-2012-4681.html
>
> The lead of Oracle's Java Vulnerability Team estimates that at least a
> third of all the vulnerabilities reported since JDK 7 GA would have been
> prevented if we'd had the ability to strongly encapsulate JDK-internal
> packages.

Fair enough, though I do want to point out that examining these two 
analyses doesn't lead me to believe that this would be the only (or 
best) way to prevent these exploits, which seem to be rooted in coding 
errors in other parts of the JDK.

>>               On the other hand, there is strong evidence to support the
>> assertion that enhancing the security model in any way immediately leads
>> to new CVEs.  The more behavioral rules there are in place, the more
>> vectors for exploitation will appear.
>
> In the abstract, I agree with you.  The proposed means of encapsulation,
> however, does not depend upon the existing complex security architecture,
> so it should be easier to validate.

The reason it concerns me is that the Java language access modifiers and 
this new access check solve the same problem in different ways, leading 
to a sort of NxM growth of possibilities for access checking behavior. 
Apart from the theoretical danger of the more complex rules, I don't 
know that the average developer will understand why the (now) two 
language-level access checks are separated rather than combined.

Adding a "traditional" access level - even the simple approach of 
"weakening" package-private to module-private (even if just for Java 9+ 
module classes) - seems much safer to me because it's just another point 
in a well-understood linear spectrum of behavior, and thus I think can 
be shown to introduce little or no substantial negative impact on the 
security of existing code, while at the same time definitely improving 
the security of any code which deescalates the accessibility of 
otherwise public members.  The simplicity of the model ensures that it 
will be well-understood by both existing and new developers, and also 
directly implies a lower risk in at least a couple of categories 
(security and compatibility spring to mind).

I think the principle of "Public is public" is important to maintain.

>> ...
>>
>>> To truly support strong encapsulation would require taking setAccessible
>>> away completely.  I think that's desirable in the (very) long term, but
>>> it would break too much existing code in the near term.
>>
>> I don't agree that this is true.  Encapsulation is really a social
>> construct; while accessibility can be used to create and enforce
>> encapsulation-justified rules, it doesn't *have* to.  You do need some
>> kind of back door, no matter what, or else you severely limit the power
>> and capability of the platform (as evidenced by the widespread usage of
>> the reflection back door by many widely-used frameworks generally
>> considered to be powerful and capable).
>>
>> If encapsulation as a design principle is the goal, then simple
>> isolation rules between modules (as between unrelated class loaders) has
>> already been proven to be highly effective.
>
> If all you mean by "encapsulation" is a social construct then sure, none
> of this would be necessary.  That's insufficient, however, in the face
> of actual security threats.  Aside from security considerations, a social
> contract implies a level of understanding and trust that is difficult,
> if not impossible, to achieve in a broad community of millions of
> developers.

I understand that, but consider: of those millions of developers, I 
think it is very safe to say that the majority of them know what 
"private" versus "public" means.

>> In this light, I don't see how these changes cannot be considered a
>> modification of the security model just because they ride in on the
>> coattails of a new abstraction.
>
> It depends upon what you mean by "security model".
>
> If you mean some high-level, abstract view of all the various mechanisms
> in the language, VM, and libraries that help ensure security then yes,
> the proposed changes are an extension of that model.
>
> When I write "security model", however, I usually mean the subsystem
> which evolved from the simple (and simplistic) java.lang.SecurityManager
> API in Java 1.0 to the complex policy/permission-based architecture of
> the 1.2 release.  Many run-time operations (in class loaders, reflection,
> I/O, etc.) are subject to checks done by the security subsystem, and if
> just one of those checks is missing or incorrect then it may well be
> "game over".

What I'm thinking of here is the compiler/VM security model, which (in 
terms of specification at least) I believe is presently limited to 
access level checking on classes and members.

> The proposed enforcement of module boundaries via access restrictions
> expressed in the language, recorded in class files, and enforced by the
> compiler and the VM do not in any way depend upon that subsystem, nor do
> they extend it.  The VM will never upcall into the security subsystem in
> order to determine whether one type is permitted to access another.  The
> implementation of access-control checks in a JVM is typically highly
> localized and much easier to validate than the comparatively large body
> of code in the (mostly) Java-level security subsystem.

I do agree that enforcing module boundaries via access restrictions in 
the language and class files should be enforced by the compiler and VM. 
  I'm just hoping we can arrive at something that doesn't create a new 
sort of Java puzzler: "when is a public class not public?".

>>>                                        ...  If encapsulation is to mean
>>> anything then it should not be possible to break it solely from within
>>> the language itself.  Enabling such powers via an external, second-class
>>> mechanism such as a command-line option or a debugger is fine, but the
>>> history of Java has shown that if it's easy to break encapsulation then
>>> people will do so, increasing everyone's maintenance burdens over the
>>> long haul.
>>
>> I think this may be a somewhat narrow view.  People break encapsulation
>> when they need a capability that cannot be provided another way.  Now
>> the JDK, unfortunately, historically contains very many "goodies" and
>> bits of useful functionality that users want access to, so it is a
>> disproportionately popular target for such breakage, but apart from
>> accessing JDK internals, I believe that the use cases for breaking in
>> through the security model are legitimate and should be allowed to
>> adequately privileged code.
>
> How do you identify "adequately privileged code"?  (This is an open issue
> we need to address.)

Good question... today, my understanding is that such code is (a) any 
code running in a JVM with no security manager, or (b) any class which 
has a protection domain which is somehow granted the 
"suppressAccessChecks" RuntimePermission.  But I see your point, and I 
think it is reasonable to want to strengthen this somehow.

Specifically I don't like having public classes that aren't actually 
public - this adds another layer of complexity which I don't think is 
necessary.  Ideally a public class is *always* public.  A module with a 
public class in a non-exported package is (intuitively speaking) not 
saying "this class is not really public", it's saying "this class is 
public, but not to link against".

If the goal is to eliminate the need for this back door, then the "front 
door" must suffice for all use cases.  This means that frameworks that 
access modules must be able to do so in a way that is allowable by 
module authors.  If public classes are always public, even when they're 
hidden, our various EE specs can be changed to say "your EJB 
implementation (or whatever) must be public, but it MAY be in a 
non-exported package".  This allows anyone who can get access to the 
Class object free access to its public members *without* a special 
permission, which actually goes a long way towards getting rid of the 
desire for a backdoor in the first place.  Such classes could be 
available by name, service loading, or annotation lookup, but not via 
direct linkage, which is a nice and logical way of saying "you can 
access this public class indirectly, but it is definitely NOT API".

>>                               Using an appropriate security model, it is
>> not difficult to ensure that such powers are not exploited (though while
>> in practice it is more difficult due to a variety of factors, I do not
>> believe those factors are directly related to this mechanism but rather
>> to exceptions, special "holes", and other technical debt that exists in
>> the JDK itself for historical or other reasons).
>
> I don't think that the future of the platform would be well-served by a
> model that works well only for code outside of the JDK, if that's what
> you mean.

Sure, but the reverse is also true.  Clearly a solution needs to 
accommodate both, though at the same time it is generally not good to 
bake in rules that only exist to accommodate JDK implementation choices, 
I'm sure you'd agree.  At most, you'd want to leave certain things 
unspecified to allow the JDK flexibility, but even that might go too far 
in many cases.

-- 
- DML


More information about the jpms-spec-experts mailing list