Secure Coding mailing list archives

By default, the Verifier is disabled on .Net and Java


From: jeff.williams at aspectsecurity.com (Jeff Williams)
Date: Tue, 2 May 2006 22:56:57 -0400

Two important clarifications for Java (based on my experiments):

 

1) The verifier IS enabled for the classes that come with the Java platform,
such as those in rt.jar.  So, for example, if you create a class that tries
to set System.security (the private variable that points to the
SecurityManager instance), you get a verification exception. (If this was
possible, it would allow a complete bypass of the Java sandbox).

 

2) The verifier also seems to be enabled for classes running inside Tomcat.
I'm not sure about other J2EE containers.

 

So I don't think it's fair to say that most Java code is running without
verification.

 

But Denis is right. There is a real problem with verification, as
demonstrated in the message below.  This is a clear violation of the Java VM
Spec, yet my messages to the team at Sun developing the new verifier have
been ignored.  And it's a real issue, given the number of applications that
rely on libraries they didn't compile.  I don't think a real explanation of
how the Sun verifier actually works is too much to ask, given the risk.

 

--Jeff

 

  _____  

From: sc-l-bounces at securecoding.org [mailto:sc-l-bounces at securecoding.org]
On Behalf Of Dinis Cruz
Sent: Tuesday, May 02, 2006 7:48 PM
To: 'Secure Coding Mailing List'
Cc: 'owasp-dotnet at lists.sourceforge.net'
Subject: [SC-L] By default, the Verifier is disabled on .Net and Java 

 

Here is a more detailed explanation of why (in my previous post) I said:
"99% of .Net and Java code that is currently deployed is executed on an
environment where the VM verifier is disabled,  ."

------------------

In .Net the verifier (the CLR function that checks for type safety) is only
enabled on partial trust .Net environments.

For example, in Full Trust .Net you can successfully assign Type A to Type B
(also called a Type Confusion attack) which clearly breaks type safety.

I have done some research on this topic, and on my spare time I was able to
find several examples of these situations:

*       Possible Type Confusion issue in .Net 1.1 (only works in FullTrust)
(http://owasp.net/blogs/dinis_cruz/archive/2005/11/08/36.aspx)
*       Another Full Trust CLR Verification issue: Exploiting Passing
Reference Types by Reference
(http://owasp.net/blogs/dinis_cruz/archive/2005/12/28/393.aspx)
*       Another Full Trust CLR Verification issue: Changing Private Field
using Proxy Struct
(http://owasp.net/blogs/dinis_cruz/archive/2005/12/28/394.aspx)
*       Another Full Trust CLR Verification issue: changing the Method
Parameters order
(http://owasp.net/blogs/dinis_cruz/archive/2005/12/26/390.aspx)
*       C# readonly modifier is not enforced by the CLR (when in Full Trust
(http://owasp.net/blogs/dinis_cruz/archive/2005/12/26/390.aspx)
*       Also related: 

*       JIT prevents short overflow (and PeVerify doesn't catch it)
(http://owasp.net/blogs/dinis_cruz/archive/2006/01/10/422.aspx)     
*       and ANSI/UNICODE bug in System.Net.HttpListenerRequest
(http://www.owasp.net//blogs/dinis_cruz/archive/2005/12/17/349.aspx
<http://www.owasp.net/blogs/dinis_cruz/archive/2005/12/17/349.aspx> )

Here is Microsoft's 'on the record' comment about this lack of verification
(and enforcement of type safety) on Full Trust code (note: I received these
comments via the MSRC):

"...
Some people have argued that Microsoft should always enforce type safety
at runtime (i.e. run the verifier) even if code is "Fully Trusted".
We've chosen not to do this for a number of reasons (e.g. historical,
perf, etc). There are at least two important things to consider about
this scenario:

1) Even if we tried to enforce type safety using the verifier for Fully
Trusted code, it wouldn't prevent Fully Trusted from accomplishing the
same thing in 100 other different ways. In other words, your example
accessed an object as if it were a different incompatible type - The
verifier could have caught this particular technique that allowed him to
violate type safety. However, he could have accomplished the same
result using private reflection, direct memory access with unsafe code,
or indirectly doing stuff like using PInvoke/native code to disable
verification by modifying the CLR's verification code either on disk or
in memory. There would be a marginal benefit to insuring people wrote
"cleaner" more "type safe" code by enforcing verification at runtime for
Full Trust, but you wouldn't get any additional security benefits
because you can perform unverifiable actions in dozens of ways the
verifier won't prevent if you are Fully Trusted.

2) As mentioned at the end of #1 above, one argument is that it's good
for programmers (even fully trusted ones) to follow type safety rules,
and doing runtime verification would keep people writing cleaner code.
However, we don't need to do the verification at "runtime" in order to
encourage good type safety hygiene. Instead, we can rely on our
languages to do this for us. For example, C# and VB by default ensure
that you produce verifiable code. If you've written your code in a
language like C#, you're not going to run into cases where you've
accidentally created unverifiable code (This can be seen in the example
posted on the blog since you needed to use the low level assembler to
hack up a program initially compiled in C#). Given that you can't
prevent Fully Trusted code from doing unverifiable things at runtime,
there's only a marginal difference between encouraging type safety at
compile time vs at runtime for the Fully Trusted code developer.

I hope that helps to convey the message on where Microsoft stands with
this issue.
..."


Unfortunately Java is not much better. By default most Java code is also
executed with -noverify.

Here is a good explanation from this
(http://lists.grok.org.uk/pipermail/full-disclosure/2006-March/044505.html)
thread (which I started) :

"... 
I am not a Java expert, but I think that the Java Verifier is NOT  
used on Apps that 
are executed with the Security Manager disabled (which I  believe is the
default 
setting) or are loaded from a local disk (see "...  applets loaded via
the file system 
are not passed through the byte code verifier" in
http://java.sun.com/sfaq/)

I believe that as of Java 1.2, all Java code except the core  
libraries must
go through the verifier, unless it is specifically disabled (java
-noverify).

I had the same intuition about the verifier, but have just tested  
this and it is not the case.  It seems that the -noverify is the  
default setting! If you want to verify classes loaded from the local  
filesystem, then you need to explicitly add -verify to the cmd line.   
I tested this by compiling 2 classes where one accesses a public  
member of the other.  Then recompiled the other and changed the  
method access to private.  Tested on:
Jdk 1.4.2 Mac OS X
Jdk 1.5.0 Mac OS X
Jdk 1.5.0 Win XP

all behave the same.

[~/data/dev/applettest/src]java -cp . FullApp
Noone can access me!!
[~/data/dev/applettest/src]java -cp . -verify FullApp
Exception in thread "main" java.lang.IllegalAccessError: tried to  
access field MyData.secret from class FullApp at FullApp.main 
(FullApp.java:23)

Using the same code with an Applet loaded from the filesystem throws  
an IllegalAccessError exception as it should.
..."

Any Comments?

Best regards

Dinis Cruz
Owasp .Net Project
www.owasp.net

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://krvw.com/pipermail/sc-l/attachments/20060502/a75eb8a3/attachment.html 


Current thread: