I'm fully aware that the Dalvik VM makes heavy use of JNI. Not all JNI is
bad. I just want to prevent *downloaded* JNI libraries from being loaded. If
the only JNI libraries that can be loaded reside in /system then: 1) we've
reduced the attack surface, 2) we can say something about the integrity of
native code, and 3) we know how to patch the system when vulnerabilities are
discovered.
I understand why the NDK exists, but it is bad for portability, and it hurts
security (cf. my defense in depth argument). Android includes OpenGL and
crypto JNI libraries, applications should use those, not bundle their own.
Need DSP support? That's a hardware feature and should be included with the
base distribution not downloaded as an add-on. You don't insert PCI cards
into mobile phones like you do PCs.
The Dalvik VM may not be designed as a security boundary, but that doesn't
mean it cannot enhance security (or be modified to do so). I believe that
execution of downloaded native code should be a tunable security option
(whether system wide or an Android permission, or both).
I guess we can agree to disagree on this one.
-Will
PS: Using virtual machines for security isolation is not an unprecedented
concept. I've read a lot of interesting papers on this topic. Oh, and VMWare
considered the vulnerability that allowed cloudburst exploit a security
issue and handled it as such didn't they?
PPS: Limiting JNI library loads to just libraries reside in /system is
possible. I've done it, it works, the patch is below. Sure we need to
consider other things like exec(), but it's a start.
----------------------------------------------------------------------
diff --git a/vm/Native.c b/vm/Native.c
index 7a153d6..3adb76a 100644
--- a/vm/Native.c
+++ b/vm/Native.c
@@ -390,6 +390,11 @@ bool dvmLoadNativeCode(const char* pathName, Object*
classL
LOGD("Trying to load lib %s %p\n", pathName, classLoader);
+ if (strncmp(pathName, "/system", 7) != 0) {
+ LOGW("Denying lib %s (not \"/system\" prefix)\n", pathName);
+ return false;
+ }
+
/*
* See if we've already loaded it. If we have, and the class loader
* matches, return successfully without doing anything.
----------------------------------------------------------------------
Chris Palmer wrote:
Defense in depth mechanisms are good when they (a) don't break
legitimate features and (b) actually work. Your examples of a firewall
and native code exploit mitigations are good examples.
However, native code execution on Android is a legitimate feature, and
blocking its use would not actually work. Android uses Java source for
its convenience features, not for the VM's security features. The
Dalvik VM tries to be fast and small, but does not try to be a
security boundary (it's not a JVM). Furthermore, much of the platform
functionality is written as JNI and/or as a very thin wrapper around
native code -- it's not a long trip from Dalvik bytecode to machine
code in a lot of places. And that is perfectly ok.
If any Android platform distributor tried your idea, attackers would
probably not take too long to pop through to native code. And then
you'd have thrown away a good feature for no security benefit.
Defense mechanisms should rely on published API contracts, not
imagined guarantees. For example, VMWare does not claim to be a
security boundary, and it does way more separation work than Dalvik or
the JVM. And indeed, it can be popped:
http://www.immunityinc.com/documentation/cloudburst-vista.html
The difference is that VMWare does not claim (that I can see) that its
product protects hosts from guests. Linux *does* claim to separate
UIDs, so when it doesn't, everyone should agree it's a bug. It's
reasonable to trust that Linux upholds its guarantee, even if
sometimes it doesn't; on the other hand, it's not reasonable to trust
that VMWare or Dalvik upholds guarantees they never actually made.
That's enough out of me. Now I'll go back to enjoying my
high-performance Android games and crypto library and DSP apps... ;)
On Mon, Aug 24, 2009 at 11:23 AM, William Enck<e...@cse.psu.edu> wrote:
I disagree. Making things harder to exploit is a good thing.
For example, my PC only listens on port 22, but my gateway firewall
ensures
that only inbound connections on port 22 will get through. If I visit a
malicious website and it starts a webserver or SMTP server, that firewall
rule keeps the attacker from connecting to my system. I.e., in this case,
the firewall is used for defense in depth.
For another example, look at buffer overflow exploitation. Buffer
overflows
can still be exploited, but ASLR, NX bits, and stack canaries make the
adversary work harder. It can take months to turn a buffer overflow
vulnerability into an exploit.
The Dalvik VM is a virtual machine monitor. Virtual machines provide an
separate execution environment. This can be used to make the system
harder
to exploit. I'm not saying that the kernel shouldn't be patched
immediately,
but there is a reason why skydivers carry two parachutes.
-Will
Chris Palmer wrote:
Don't think of Java, perhaps especially Dalvik, as a way to protect
against kernel bugs. Userland can't generally "defend in depth" against
kernel flaws.
Like all operating systems, Android trusts the kernel to uphold the
kernel's own design guarantees. If the guarantee is broken, that's a
kernel
bug and should be fixed in the kernel.
On Aug 17, 2009 10:05 AM, "William Enck" <e...@cse.psu.edu
<mailto:e...@cse.psu.edu>> wrote:
I imagine some folks on this list have seen this (or a similar story):
http://theandroidsite.com/2009/08/16/rooting-your-android-with-one-click/
I haven't investigated it in any depth, but my speculation is that the
exploitation of the referenced kernel privilege escalation
vulnerability
(http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-2692) results
from
the ability to execute native code.
I understand the public pressure to allow native code, and that
Android's
security model provides protection at the process level; however, as an
Android user, I would like the ability to disallow third party native
libraries for security purposes (defense in depth).
I imagine there is a library path that can be checked somewhere to
ensure
JNI only allows the /system prefix. Alternatively, the LSM hook for
mmap
could be useful.
While this won't stop users from rooting their devices when kernel
privilege escalation vulnerabilities inevitably emerge, it provides a
nice
buffer between the time the vulnerability is found to the time a
security
patch is deployed that will protect many normal users.
I'm going to take a look at generating a patch when I get a chance, but
that might not be for a little while. If anyone starts to work on this,
please let me know.
Thanks,
-Will