Hello everybody,
Inspired by some constructive criticism on a well
known Java forum, I'm recently thinking of how much effort it would be to
achieve code based security in SWT. I will use my SWT/Fox port as a playground.
Your thoughts on the following questions are
very welcome:
Would it be useful? Perhaps, yes. SWT is probably
the single Java API that currently cannot be sandboxed due to the exposure of
various "crash-friendly" things like OS.java, Control.handle,
etcetera.
Would this be easy to achieve, without
sacrificing the simplicity of the code and without the need for total rework of
the SWT internals? Perhaps, yes. Please, read on.
My plan is as follows:
There are several main sources
of crashes in SWT:
1. The native layer (OS.java and friends) is
exposed for everyone to use. This is something I'm able to tolerate as otherwise
probably we need tons of abstractions or something related to C++'s "friend"
construct in order to cross package-level boundaries and still preserve private
visibility. Note that there is already a JSR which is supposed to bring a
similar facility to Java. The main problem with the exposed native layer is that
everyone is able to call a static function in OS.java with bogus parameters
provided, thus crashing the JVM process. If this is remedied somehow, the
exposure of "support" structures like LOGFONT, LOGPEN, BITMAP etc. should not be
a problem: the important thing to grok here is that user may create and change
these as he wills, but as long as he is not allowed to directly call
functions of OS.java, he can't crash the JVM, as OS.java represents
the "code" of the operating system, whiule everything else is the
"data".
One way OS.java
can be protected is by a) marking all natives as package protected or
private and b) creating non-static public wrapper functions for all
the natives. Note that in some X11 ports this is already done (module
non-static) due to the need to lock the calls going into into XLIB.
What are these non-static wrappers going to
buy us? Well, if the primary interface of OS.java becomes non-static, then the
constructor of OS.java can be protected by doing a permission
check with AccessController and friends and throwing exception if the caller's
stack does not have enough permissions. The usage pattern of OS.java from
within SWT would be like this:
In the base class of every SWT, package needing
native access, i.e. in Widget.java, Resource.java, Printer.java,
etc:
<snip>
static OS os;
static {
AccessController.doPrivileged(new
PrivilegedAction() {
public Object run()
{
os = new OS();
return
null;
}
});
}
</snip>
and then all calls to functions in OS in all
classes should be prefixed not with "OS." but with "os."
Note that protecting only the constructor is a)
sufficient and b) give significant performance advantage, as security checks
should not be done on every OS API call; not to mention that having to do the
doPrivileged() thing all the time is inconvenient, at best.
2. public int Control.handle
This is also dangerous, as user is free to change
the handle of the control to bogus value, at will. This can be remedied by
instead providing:
public int Control.handle()
3. Resource tracking.
This is nasty. Here's a sample of the
problem:
<snip>
GC gc = ...;
Font font = ...;
gc.setFont(font);
font.dispose();
gc.drawString("test"); // <-- Crash
on platforms based on Toolkits like Fox or probably even GTK+, or weird
output on Win32
</snip>
The problem here is that after the disposal of
the Font instance, there is no valid Font object selected in the GC. In SWT
ports wrapping toolkits where Font is represented by a C++ object, this means
that the C++ GC class will try to access the C++ Font class, which is already
free-d, which leads to memory corruption and possible GPF.
The best thing for solving this I've come so far
is some sort of resource tracking utility class. The "selection" of every SWT
object in another SWT object is tracked there. When the selected object is
disposed, the "selector" object is signalled so that it has can switch to
using another font handle, usually the default system one which cannot be freed
anyway.
That's it. I know I've missed a tons of stuff.
For one thing I haven't covered how in this framework a costom "native" control
is supposed to receive native callbacks (WM_* on win32).
Regards,
Ivan