Bypassing Kotlin’s Null-Safety

In this short article, we will have a look at how we can bypass Kotlin’s native null-safety with sun.misc.Unsafe, and see why it can be dangerous even if we are not messing up with it directly.

Mythical sun.misc.Unsafe

The sun.misc.Unsafe class is an internal JVM tool for executing low-level operations like off-heap memory allocation, thread parking, CAS, and much more.

This class is like one of those scary computer game creatures that are there only to intimidate us, in theory, we can’t get close because they are part of the environment, but it’s often possible by exploiting glitches or holes.

If we try to access the Unsafe instance, we encounter a private constructor and a static getUnsafe() method that raises a SecurityException practically every time we call it:

public final class Unsafe {
    private static final Unsafe theUnsafe;
    // ...

    private Unsafe() {}

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }
}

 

So, in theory, it’s guarded by a strong encapsulation, and an exception being thrown on every getUnsafe() call… but we do have the Reflection mechanism, and we can easily bypass those:

private fun getUnsafe(): Unsafe {
    return Unsafe::class.java.getDeclaredField("theUnsafe")
            .apply { isAccessible = true }
            .let { it.get(null) as Unsafe }
}

Mighty Unsafe.allocateInstance()

This method allocates an empty instance of a given class directly on the heap ignoring field initialization and constructors.

And this allows us, indeed, to effectively bypass Kotlin’s safety checks:

A cool thing to do on Friday’s evening, but what about just not using Unsafe and staying (null)safe?

Problem: Unsafe in External Libraries

The problem is that most Java libraries were written with Java in mind, where using Unsafe for certain scenarios is slightly less unsafe than it is e.g., for Kotlin.

This is especially the case with serialization/deserialization libraries – one of such is Google’s Gson which internally uses Unsafe for instantiating objects in certain situations – which is totally acceptable for Java.

If we start using it in Kotlin, we indeed might end up with an undesired behaviour observed above:

@Test
fun unsafe_2() {
    val foo = Gson().fromJson("{}", Foo::class.java)

    assertThat(foo.nonNullable).isNull()
}

In this case, we simply need to perform checks manually after instantiation, which is not super problematic – what’s problematic is the lack of consciousness that this happens, which can cost much.

Are you sure the library you are using is not doing that internally?

Code snippets can be found on GitHub.

Key Takeaways

  • Kotlin’s null-safety does not go beyond objects’ initialization phase and is bypassable
  • External libraries that use Unsafe internally can do that too – it’s important to be aware of this
You May Also Like

Phonegap / Cordova and cross domain ssl request problem on android.

In one app I have participated, there was a use case:
  • User fill up a form.
  • User submit the form.
  • System send data via https to server and show a response.
During development there wasn’t any problem, but when we were going to release production version then some unsuspected situation occurred. I prepare the production version accordingly with standard flow for Android environment:
  • ant release
  • align
  • signing
During conduct tests on that version, every time I try to submit the form, a connection error appear. In that situation, at the first you should check whitelist in cordova settings. Every URL you want to connect to, must be explicit type in:
res/xml/cordova.xml
If whitelist looks fine, the error is most likely caused by inner implementation of Android System. The Android WebView does not allow by default self-signed SSL certs. When app is debug-signed the SSL error is ignored, but if app is release-signed connection to untrusted services is blocked.



Workaround


You have to remember that secure connection to service with self-signed certificate is risky and unrecommended. But if you know what you are doing there is some workaround of the security problem. Behavior of method
CordovaWebViewClient.onReceivedSslError
must be changed.


Thus add new class extended CordovaWebViewClient and override ‘onReceivedSslError’. I strongly suggest to implement custom onReceiveSslError as secure as possible. I know that the problem occours when app try connect to example.domain.com and in spite of self signed certificate the domain is trusted, so only for that case the SslError is ignored.

public class MyWebViewClient extends CordovaWebViewClient {

   private static final String TAG = MyWebViewClient.class.getName();
   private static final String AVAILABLE_SLL_CN
= "example.domain.com";

   public MyWebViewClient(DroidGap ctx) {
       super(ctx);
   }

   @Override
   public void onReceivedSslError(WebView view,
SslErrorHandler handler,
android.net.http.SslError error) {

String errorSourceCName = error.getCertificate().
getIssuedTo().getCName();

       if( AVAILABLE_SLL_CN.equals(errorSourceCName) ) {
           Log.i(TAG, "Detect ssl connection error: " +
error.toString() +
„ so the error is ignored”);

           handler.proceed();
           return;
       }

       super.onReceivedSslError(view, handler, error);
   }
}
Next step is forcing yours app to  use custom implementation of WebViewClient.

public class Start extends DroidGap
{
   private static final String TAG = Start.class.getName();

   @Override
   public void onCreate(Bundle savedInstanceState)
   {
       super.onCreate(savedInstanceState);
       super.setIntegerProperty("splashscreen", R.drawable.splash);
       super.init();

       MyWebViewClient myWebViewClient = new MyWebViewClient(this);
       myWebViewClient.setWebView(this.appView);

       this.appView.setWebViewClient(myWebViewClient);
       
// yours code

   }
}
That is all ypu have to do if minSdk of yours app is greater or equals 8. In older version of Android there is no class
android.net.http.SslError
So in class MyCordovaWebViewClient class there are errors because compliator doesn’t see SslError class. Fortunately Android is(was) open source, so it is easy to find source of the class. There is no inpediments to ‘upgrade’ app and just add the file to project. I suggest to keep original packages. Thus after all operations the source tree looks like:

Class SslError placed in source tree. 
 Now the app created in release mode can connect via https to services with self-signed SSl certificates.

Spring Security by example: securing methods

This is a part of a simple Spring Security tutorial:

1. Set up and form authentication
2. User in the backend (getting logged user, authentication, testing)
3. Securing web resources
4. Securing methods
5. OpenID (login via gmail)
6. OAuth2 (login via Facebook)
7. Writing on Facebook wall with Spring Social

Securing web resources is all nice and cool, but in a well designed application it's more natural to secure methods (for example on backend facade or even domain objects). While we may get away with role-based authorization in many intranet business applications, nobody will ever handle assigning roles to users in a public, free to use Internet service. We need authorization based on rules described in our domain.

For example: there is a service AlterStory, that allows cooperative writing of stories, where one user is a director (like a movie director), deciding which chapter proposed by other authors should make it to the final story.

The method for accepting chapters, looks like this:

Read more »