Unlike most bugs that I run into, this one I actively went looking for. After being reminded of the cloning attack (in the context of Java) I wrote some reflection code to scan the BCL for public types that are cloneable (i.e. subclassable) and contain unmanaged pointer fields. This is a bad combination. A class that showed up as potentially vulnerable was SocketAsyncEventArgs and a few minutes with ildasm confirmed it.

I had at that time fairly recently written about another Socket vulnerability (that was fixed in MS11-039), but that was a complete coincidence. As I said this bug was found via (trivial) static analysis.

This is another one of those security vulnerabilities that I stumbled into without looking for it. When I was integrating OpenJDK 7, I merged some minor changes into AtomicReferenceArray and after that a couple of JSR-166 TCK tests failed. After a little investigation I found that the problematic code was:

One of the tests constructs the AtomicReferenceArray by passing in an java.lang.Integer array and a subsequent store in the array would fail on IKVM.NET, because the IKVM.NET implementation of AtomicReferenceArray.set() uses the ldelema instruction to get the address of the array element so it can subsequently do a volatile store to that location. When you use the ldelema instruction the CLR will do a type check to make sure the array can safely hold values of that type and this type check failed, because the code assumed that the array is always an object array, but in this case it was a java.lang.Integer array.

At first I simply fixed this by changing the constructor back to what it previously did (always allocate a new Object array), but after some reflection I realized that this might be a security issue.

To see why this could be a security issue, you need to know that HotSpot (Server) is capable of doing some pretty amazing optimizations. What I conjectured was that HotSpot might be able to inline the constructor and subsequent get operation and then optimize away a cast operation that follows the get operation. Here's an example:

HotSpot Server is able to deduce is this case that the (Integer) cast is redundant. However, what it fails to take into account is that AtomicReferenceArray uses sun.misc.Unsafe to directly access the array and this means that even though the array here is of type Integer, the AtomicReferenceArray.set() method allows you to store any reference in the array. So a slightly modified version will violate type safety:

This vulnerability was interesting to me because it required some pretty advanced HotSpot optimizations, but this also made it less of a real-world issue, because I was unable to get HotSpot Client VM to do these optimizations, so a browser running Java was not likely to be vulnerable. However, while I was preparing to report this to Oracle it occurred to me that there was a much bigger security vulnerability that had been lingering in AtomicReferenceArray since it was first introduced in Java 5. By manually constructing a serialized object graph you can stick any array you want into an AtomicReferenceArray instance and then use the AtomicReferenceArray.set() method to write an arbitrary reference to violate type safety.

IKVM.Reflection: Fixed regression introduced with AssemblyName rewrite. The AssemblyName returned from __GetReferencedAssemblies() should include an empty public key token if the referenced assembly is not strong named.

IKVM.Reflection: API change. Allow Type.MetadataToken to be called on missing type (it will return 0 or the token hint when the type was forwarded).

IKVM.Reflection: Added Universe.ResolveType() API that can be used to construct missing types.

IKVM.NET 0.46 is the last OpenJDK 6 based release, so it will be supported longer than usual. I haven't yet decided how long exactly, but in any case here is a release candidate for an update release that incorporates many of the fixes that have been done since 0.46 was released.

Bug fix. Exception blocks inside potential try { } finally { } blocks were not handled correctly. Could result in finally blocks that run multiple times (when an exception occurs).

Fix for #3404229.

Bug fix. Don't create a miranda method if the class already has a static method with the same signature.

Added workaround for another x64 JIT bug. See https://sourceforge.net/mailarchive/message.php?msg_id=28250469

Newer versions of ICSharpCode.SharpZipLib.dll require the ZipEntry size to be set explicitly, otherwise the generated archive will not be compatible with older zip implementations (like Java 6's java.util.zip).

Fixed serialization interop bugs.

Bug fix. When an abstract .NET type implements System.IComparable (and hence java.lang.Comparable) the resulting stub is not usable from Java because the compareTo method is missing. This fix adds the missing method.

Fix and enhancement. When a .NET type implements a shadowed interface, we now also publish the original interface (e.g. if the .NET type implements System.IComparable, Java code will now see java.lang.Comparable and System.IComparable). In addition, the new code makes sure that when a .NET type explicitly implements both System.IComparable and java.lang.Comparable that the Java code will not see java.lang.Comparable twice.

Bug fix. Make FileOutputStream in append mode always append.

Add support for overriding constructor body in map.xml.

Make sure that Thread.getContextClassLoader() and Thread.setContextClassLoader() are JITed before Thread.isCCLOverridden().

Workaround .NET 2.0 bug in GetType() that could cause problems with creating proxies for compiled types.

Bug fix. Exceptions declared with ThrowsAttribute(Type) (in .NET code) did not get exported properly by ikvmstub.

Fix ClassLoader.findLoadedClass0() to handle null string.

Implemented support for annotation defaults in ikvmstub.

Bug fix. Final instance fields that have a type 2 access property should also have a (private) setter for reflection and serialization.

Bug fix. Set os.name and os.version properties correctly when running on unknown Windows version (Windows 8).

Bug fix. IPInterfaceProperties.GetIPv_Properties() can throw an exception (and does so on Win 8 for some interfaces).

Don't open the remap file in read/write mode.

Bug fix. Make sure sun.misc.Launcher is initialized before setting a security manager, because Launcher assumes there is no security manager yet.

Implemented com.sun.security.auth.module.NTSystem.getCurrent().

Bug fix. When calling a final method on a remapped type we can't call the instance method in the remapped type, but we have to call the instancehelper instead.

Fix. When decoding a NameSigAttribute it is possible that a type does not exist (i.e. is an unloadable) and that results in a warning emitted against the referenced assemblies class loader.

If you compile p1 and p2 seperately with ikvmc and look inside the resulting assemblies, you'll see that ikvmc generated a foo property in Derived. It needs to do this, because the CLR won't allow code from another assembly to access the members of Base.

In the IKVM source code this type of access stubs is known as type 1. As you'd expect there are also type 2 access stubs. These are generated when a public (or protected) member exposes a non-public type:

Once again, if you compile p1 and p2 into separate assemblies with ikvmc, you'll see that field will be accessed through a property. In this case the property type is erased to the first public base type and a custom modifier is attached to make sure the property signature is unique (and to be able to recover the real type).

These type 2 access stubs were originally generated (in some cases) by ikvmc to support accessing these members from C#, because the CLR, like the JVM, doesn't care about the visibility of the types in a signature when it considers member accessibility.

However, since .NET 4.0 there is a new factor to consider, when level 2 transparent code tries to access a member, the types in the member signature (except for the custom modifiers) must all be visible to the caller.

Removed mapping of System.Security.VerificationException to java.lang.VerifyError.

IKVM.Reflection: Massive enhancements to support a very large portion of the managed PE capabilities (much more than System.Reflection.Emit).

Runtime

Code unloading (aka class GC) is not supported.

In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.

JNI

Only supported in the default AppDomain.

Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).

Cannot call string contructors on already existing string instances

A few limitations in Invocation API support

The Invocation API is only supported when running on .NET.

JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.

JNI_GetDefaultJavaVMInitArgs not implemented

JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.

DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).

DetachCurrentThread doesn't release monitors held by the thread.

Native libraries are never unloaded (because code unloading is not supported).

The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.

monitorenter / monitorexit cannot be used on unitialized this reference.

Floating point is not fully spec compliant.

A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).

Synchronized blocks are not async exception safe.

Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.

Class loading is more eager than on the reference VM.

Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).

JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.

Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.

Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).

Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).

Only code compiled together during a single compilation fully obeys the JLS binary compatibility rules.

Class Library

Most class library code is based on OpenJDK 7 build 147. Below is a list of divergences and IKVM.NET specific implementation notes.

Partial implementation. JPEGs can be read and written and there is limited metadata support.

javax.management

Limited implementation.

javax.print

There is a Win32 specific printing implementation. Not supported.

javax.script

ECMAScript implementation is not included.

javax.smartcardio

Not implemented.

javax.sound

Not implemented.

javax.swing

Not supported.

javax.tools

Not supported.

org.ietfs.jgss

Not implemented.

sun.jdbc.odbc

Implementation based on .NET ODBC managed provider.

sun.net.www.content.audio

Audio content handlers not implemented.

sun.net.www.content.image

Not supported.

The entire public API is available, so "Not implemented." for javax.smartcardio, for example, means that the API is there but there is no back-end to provide the actual smartcard communication support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas, but patches are welcome, of course.