Peter Verhas, EPAM Systems
DevDays | May 24, 2018 14:00 - 14:45, Vilnius
Some hacking that were available up to Java 8
JPMS module system that prevents such hacking
Using unsafe and the liaison of Java 9 with unsafe
how will we go on with all these, future
what hacking? ... is it Perl ... or... bash ?
There are some things that are hackable
mainly because of optimizations
early times it was struggling with speed.
... well... sometimes it still does ...
some optimizations were not that optimal, for example
the Integer cache
the Integer cache
why would anyone hack it?
That is not the point. It is a security issue, it is not good.
Not a tragedy though.... but it is not nice.
the Integer cache
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// code that that fills cache[-128...127] = -128 ...127
}
private IntegerCache() {}
}
it is used inside Integer.java
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
still in Integer.java
I overwrote the cache using reflection?
if( 1 + (Integer)1 == 2 ){
System.out.println("OK");
}else{
System.out.println("WEIRD");
}
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("java.lang.Integer$IntegerCache");
Field field = clazz.getDeclaredField("cache");
field.setAccessible(true);
Integer[] cache = (Integer[]) field.get(clazz);
for (int i = 0; i < cache.length; i++) {
cache[i] = new Integer(new Random().nextInt(cache.length));
}
for (int i = 0; i < 10; i++) {
System.out.println((Integer) i);
}
}
from https://blog.jooq.org/2013/10/17/add-some-entropy-to-your-jvm/
(article from Lukas Eder)
92
221
45
48 for (int i = 0; i < 10; i++) {
236 System.out.println((Integer) i);
183 }
39
193
33
84
from https://www.sitepoint.com/10-things-you-didnt-know-about-java/
(article from Lukas Eder)
Exception in thread "main"
java.lang.reflect.InaccessibleObjectException:
Unable to make field static final java.lang.Integer[]
java.lang.Integer$IntegerCache.cache accessible: module java.base
does not "opens java.lang" to unnamed module @1bc6a36e
from my command line on my pc
(Java 9.0.1)
Exception in thread "main"
java.lang.reflect.InaccessibleObjectException:
Unable to make field static final java.lang.Integer[]
java.lang.Integer$IntegerCache.cache accessible: module java.base
does not "opens java.lang" to unnamed module @1bc6a36e
from my command line on my pc (Java 9.0.1)
Java 9 introduced JPMS
(Java Platform Module System)
Public is not so public any more
We have modules
use down arrow to transition
A module is a JAR file
that has a module-info.class file
compiled from module-info.java
declares 5 things
what the module exports
what other modules it requires
what services the module provides
what services the module uses
what packages the module opens
packages
(to certain other modules)
in which
public members of the public classes
can be used by code in other module
that requires the module
essentially the API of the library the module contains
module org.astro {
exports org.astro.api;
}
from the ORACLE documentation (almost)
http://openjdk.java.net/projects/jigsaw/quick-start
specifies the other modules that this module uses
module com.greetings {
requires org.astro;
}
from the ORACLE documentation
service implementation
service provision is an extension of ServiceLoader (available since 1.2, nobody used really)
does anyone know what ServiceLoader is?
module org.fastsocket {
requires com.socket;
provides com.socket.spi.NetworkSocketProvider
with org.fastsocket.FastNetworkSocketProvider;
}
from the ORACLE documentation
module com.socket {
exports com.socket;
exports com.socket.spi;
uses com.socket.spi.NetworkSocketProvider;
}
from the ORACLE documentation
packages
(to certain other modules)
for reflective access
module com.socket {
exports com.socket;
exports com.socket.spi;
opens com.socket.spi to network.helper;
uses com.socket.spi.NetworkSocketProvider;
}
from the ORACLE documentation
Exception in thread "main"
java.lang.reflect.InaccessibleObjectException:
Unable to make field static final java.lang.Integer[]
java.lang.Integer$IntegerCache.cache accessible: module java.base
does not "opens java.lang" to unnamed module @1bc6a36e
what we see here is...
JDK is modular and does not opens (sic) Integer cache
access the internal parts of the JDK any more
do things developers are not supposed to do
for example using unsafe
use down arrow to transition
that we are not supposed to use.
Because it is unsafe.
It is there for INTERNAL USE!
So we do not touch it!
I mean other than using the JDK that is obviously using its internals.
YOU DID.
if you are a Java programmer and used
Hibernate
Spring
Mockito
Netty, Hazelcast, Cassandra, EasyMock, JMock, PowerMock, Scala Specs, Spock, Robolectric, Grails, Neo4j, Akka, Apache Kafka, Apache Wink, Apache Storm, Apache Hadoop, Apache Continuum, ...
It was not supposed to be used!!!
and still... what is better?
Note on the door: please do not come in!
... or ...
Lock the door!
lock the door!
Java is mature
Java is enterprisey
Java is fast
Java should not tolerate hacking any more
Don't you say!
So what?
Stay compatible, no new features, no change, ... Java is the new COBOL?
Limit backward compatibility
When implementation becomes API backward compatibility hinders the development of the implementation.
true for a library
true for a language
can you list some feature?
Underscore cannot be variable name
APIs get deprecated, like
...applet
...observer
Were all previous Java releases backward compatible?
1.2 String.hashCode() has changed
1.4 cannot import class from default package
1.5 BigDecimal.toString() was changed
enum was introduced as keyword in Java 1.5
... not to mention concurrency
and some other
just small fixes and Java tried to remain backward compatible
from now on.... backward compatibility is limited
@deprecated( forRemoval=true )
_ is invalid as variable
there was a hint already
unsafe is not available any more
reflectively access IntegerCache
not even via reflective access provided by unsafe
public static void main(String[] args) throws Exception {
Class usf = Class.forName("sun.misc.Unsafe");
Field unsafeField = usf.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
sun.misc.Unsafe unsafe = (sun.misc.Unsafe)unsafeField.get(null);
Class> clazz = Class.forName("java.lang.Integer$IntegerCache");
Field field = clazz.getDeclaredField("cache");
Integer[] cache = (Integer[])unsafe.getObject(
unsafe.staticFieldBase(field),
unsafe.staticFieldOffset(field));
// the rest is the same
from my command line on my pc
(Java 9.0.1)
Exception in thread "main" java.lang.IllegalAccessError:
class devdays.lt2018.prevent.hacking.IntegerHack (in module integer.hack)
cannot access class sun.misc.Unsafe (in module jdk.unsupported)
because module integer.hack does not read module jdk.unsupported
at integer.hack/devdays.lt2018.prevent.hacking.IntegerHack.main
from my command line on my pc
(Java 9.0.1)
because module integer.hack does not read module jdk.unsupported
at integer.hack/devdays.lt2018.prevent.hacking.IntegerHack.main
module integer.hack {
requires jdk.unsupported;
}
92
221
45
48 for (int i = 0; i < 10; i++) {
236 System.out.println((Integer) i);
183 }
39
193
33
84
actual output may random and different
unsafe is still there (by default)
but you have to be really desperate
libraries (Spring, Hibernate etc.) will upgrade
they are desperate
but it will
what we have learned from all this
Java got matured
it cannot grow hackable and it will not be hackable
but it will grow and stay with us for long long time
it is complex... ever more complex
which is GOOD!
we will have jobs!!!
Peter Verhas, EPAM Systems