22
Dec
09

Tighter rows in TreeView with SWT + GTK

As mentioned here and here and here, the GTK version of SWT wastes much space in tables and trees. Even with the GTK theming, rows in trees have still too much space between them:

I spent some time with GDB to find out where the additional padding above and below the text of each item comes from. In the end I found out, that text cell renderers in GTK (gtk/gtkcellrenderertext.c) have a default y-padding of 2 pixels set:
GTK_CELL_RENDERER (celltext)->ypad = 2

While you can’t do much to fix it in Eclipse right now, here’s the hack to make it work for your own SWT programs:

val t: swt.widgets.Tree = //

import swt.internal.gtk.OS
val rendererMethod = t.getClass.getDeclaredMethod("getTextRenderer", java.lang.Long.TYPE)
rendererMethod.setAccessible(true)
val h = OS.gtk_tree_view_get_column (t.handle, 0)
val r = rendererMethod.invoke(t,java.lang.Long.valueOf(h)).asInstanceOf[java.lang.Long].longValue
OS.g_object_set (r, OS.ypad, 0, 0)

With this set, the tree from above looks much more compact:

06
Mar
09

Breaking the JVM

In my recently finished thesis, I stressed the importance of the JVM verifier and briefly talked about the security issues rogue bytecode might introduce if not detected by the verifier. I did so, just by assumption, only theoretically knowing that an attack might work (and probably how), but without having tried it in practice.

So now, I turned off the verifier and looked what happened…

I generated a simple class with ASM which looks like this when disassembled:

% javap -c MemoryTools
public class MemoryTools extends java.lang.Object{
public MemoryTools();
  Code:
   0:	aload_0
   1:	invokespecial	#9; //Method java/lang/Object."<init>":()V
   4:	return

public static int addressOfObject(java.lang.Object);
  Code:
   0:	aload_0
   1:	ireturn
}

It has just a no-op constructor and one method addressOfObject. It loads the object reference passed as first parameter and tries to return it as if it were an integer. We assume that a reference to an object is just a 32-bit pointer to some memory structure representing the object, which basically is an integer. This bytecode sequence is, of course, rejected by the JVM bytecode verifier. To test the class I wrote another class with a main-method:

public class MemoryLoader {
	public static void main(String[] args) {
		System.out.println(MemoryTools.addressOfObject(new Object()));
	}
}

Executing the code fails as expected:

% java -cp .:bin MemoryLoader
Exception in thread "main" java.lang.VerifyError: (class: MemoryTools, method: addressOfObject signature: (Ljava/lang/Object;)I) Expecting to find integer on stack
at MemoryLoader.main(MemoryLoader.java:3)

The verifier is doing its job. When verifying the ireturn instruction, the verifier notices that an object reference is on the stack, which ireturn can’t handle. When generating bytecode, e.g. when writing a compiler, verifier errors are common at testing and expected. In our particular case, however, we want to test what happens without the verifier.

The Sun JVM has some options which affect the verifier, most notably -Xbootclasspath. Classes from the bootclasspath are simply not verified at all. So, let’s try:

% java -Xbootclasspath/a:.:bin MemoryLoader
=============== DEBUG MESSAGE: illegal bytecode sequence - method not verified ================
Exception in thread "main" java.lang.NullPointerException
at MemoryTools.addressOfObject(MemoryTools.java)
at MemoryLoader.main(MemoryLoader.java:3)

Even with the verifier turned off, now the execution fails (before it was the loading) with a debug message and a seemingly misplaced NullPointerException. If the JVM finds illegal bytecode sequences on its own, perhaps the verifier isn’t needed at all?!?

Some googling turned up parts of the source code of the Sun Hotspot VM’s interpreter, where this error message is defined. An entry point to the error message was stuffed into some dispatch table, from where it was difficult to examine when the message actually was shown. I had more luck in another file listing all the bytecodes in a table next to their return types. So I guessed, that the JVM bytecode interpreter probably does some simple verification of pairs of bytecodes by checking if the two bytecode instructions can be next to each other based on their types. How to outsmart this simple verification? Nothing as simple as that:

% javap -c MemoryTools
public class MemoryTools extends java.lang.Object{
//...
public static int addressOfObject(java.lang.Object);
  Code:
   0:    aload_0
   1:    nop
   2:    ireturn
}

A nop between aload and ireturn might already defeats the simple verification. Since both pairs of instructions (aload,nop) and (nop,ireturn) are potentially valid, the interpreter might be deceived. Let’s try again:

% java -Xbootclasspath/a:.:bin MemoryLoader
-1331261416

Here we are.

Getting the memory address of an object is somewhat boring. Reading arbitrary memory of the JVM runtime process, however, would be nice… Since a reference is just a pointer to the object’s internal structure, there probably are bytecode instructions to dereference the pointer to access members as well. I tried this simple class:

public class Data {
	public int x;
}

In order to do something useful with this, we have to know the internal structure of an object. I didn’t make the effort to go through the sources of the JVM again, but found some hints here. A java object in the Sun JVM, accordingly, has an 8-byte header followed by the fields ordered by decreasing field-length. In pseudo-C syntax the structure of Data would look like this:

struct Data{
  int hashCode;
  void* clazz;
  int x;
};

On a 32-bit platform the field x should have an offset of 8 from the beginning of the structure. Given a pointer to an object of class Data p, retrieving Data.x can be expressed in terms of pseudo-C syntax as the dereferencing of a pointer offset by 8:

char *p; // pointer to an object of type Data
int x = *((int *)(p + 8));

Vice versa this means, that reading an integer from an arbitrary address can be realized by subtracting 8 from that address, treating the address as a pointer to Data and reading Data.x. In bytecode that looks like this:

% javap -c MemoryTools
public class MemoryTools extends java.lang.Object{
//...
public static int readInt(int);
  Code:
   0:	iload_0
   1:	bipush	8
   3:	isub
   4:	nop
   5:	getfield	#21; //Field Data.x:I
   8:	ireturn
}

I wrote another short program, which, using readInt, should read 0x48 bytes of memory from the start of a byte-array object and write it to the standard output.

public class MemoryLoader {
	public static void int2bytes(int i,byte[] ar){
		ar[3] = (byte)((i>>24) & 0xff);
		ar[2] = (byte)((i>>16) & 0xff);
		ar[1] = (byte)((i>>8) & 0xff);
		ar[0] = (byte)(i & 0xff);
	}
	public static void main(String[] args) throws IOException {
                byte[] res = new byte[4];
		Object test = "das ist das haus des nikolaus".getBytes();
		
		int pos = MemoryTools.addressOfObject(test);
		for (int i=0;i<0x30;i+=4){
			int2bytes(MemoryTools.readInt(pos+i),res);
			System.out.write(res);
		}
	}
}
&#91;/sourcecode&#93;
Piping the output through <code>hexdump</code> shows:

% java -Xbootclasspath/a:.:bin MemoryLoader|hexdump -C
00000000  01 00 00 00 00 08 b4 8c  1d 00 00 00 64 61 73 20  |............das |
00000010  69 73 74 20 64 61 73 20  68 61 75 73 20 64 65 73  |ist das haus des|
00000020  20 6e 69 6b 6f 6c 61 75  73 00 00 00 00 00 00 00  | nikolaus.......|
00000030

The hashCode is 1 (because it wasn’t calculated yet), then the pointer to byte-array’s internal class structure follows. The next 4 bytes represent the length of the byte-array, 0x1d, then the content bytes themselves follow.

These experiments probably only work on a 32-bit JVM, since the memory layout of structures is different on x64. I used Ubuntu intrepid, and the OpenJDK 6:


java version "1.6.0_0"
IcedTea6 1.3.1 (6b12-0ubuntu6.1) Runtime Environment (build 1.6.0_0-b12)
OpenJDK Server VM (build 1.6.0_0-b12, mixed mode)

You can get the source code from github. Please try yourself and tell from the journeys into the depth of the JVM you made.

07
Aug
06

Hello world!

Yeah I’m here. Read the about page to get started 😉




May 2024
M T W T F S S
 12345
6789101112
13141516171819
20212223242526
2728293031