Subject Re: [Firebird-Architect] External engines - security
Author Roman Rokytskyy
> Here is how this is handled in Oracle:
> dbms_java.grant_permission('USER_NAME',
> 'SYS:java.lang.RuntimePermission', 'getClassLoader', '' );
>
> So Java code in USER_NAME schema is allowed to call getClassLoader() method.
> ----
>
> As i understand "getClassLoader" is an Java method name, not registered
> external function. Am i wrong ?

The things are bit more complicated. You can't deny calling some
particular method through the configuration (the config would be huge).
The whole security model is based on the fact that a class can check
whether the caller has a permission to perform some particular action.

Example: MyClass tries to open a file /tmp/firebird/myfile.txt. To do
this it creates instance of java.io.FileInputStream class. It is the
responsibility of the FileInputStream to check whether MyClass has
permission to open a file. Here's the code in the class constructor:

SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}

This in turn goes to checking whether current policy file (usually
java.policy) contains entry:

grant codeBase "/some/path/to/jar/with/MyClass" {
permission java.io.FilePermission "/tmp/firebird/-" "rw";
}

It is possible also to restrict to signed classes (and you can check the
signatures of the particular class).

Now, when you consider the fact that one can replace the class
implementation by simply changing the classpath and putting own class
before the original classes (that was a standard method to override
JBuilder's license class with own implementation allowing everything),
this all scheme does not seem very reliable. But here are few
limitations in JVM to secure the stuff:

a) it is not allowed to override class implementations from the java.*
packages via classpath (only via bootclasspath, bootclasspath can be
specified only when constructing the JVM). Since the classes from java.*
package provide an interface to underlying OS, they also check access to
the stuff like file access or socket access (client or server). Also the
system classloader (the topmost in the hierarchy) can check whether
classes are loaded from a particular location or are signed by a known
certificate.

b) the trusted classes can use AccessController.doPriviledged(...)
method thus perfoming some action on behalf of the untrusted classes. In
our example we might have a trusted class that is part of our plugin
that is allowed to read and write in /tmp/firebird directory. When this
class is invoked by the stored procedure, it might check some parameters
in the database, for example, and if everything is ok, perform file
system access.

c) Security contexts can be local to a particular thread. So one thread
of execution might have one policy (e.g. strict sandbox) and another
thread can have another context.

d) the classes can define their own permission classes which can be
specified in the policy file.

The item b) allows very important usage scenario for us. If sysadmin is
willing to protect his host from spam sending, but does not want to
prohibit access to remote Firebird servers (not limiting the access to a
particular host or port), it can give a socket opening permission to
Jaybird, while prohibiting it to others. If Jaybird would perform all
socket access in doPriviledged(...) part (currently it doesn't), you get
a system where it is possible to query remote Firebird databases, but be
still protected from spam-sending functionality.

As to restricting calling the methods that were not registered as
procedures. First, it is virtually impossible to do, but it is also
senseless to do it. An unregistered method might implement very
important functionality used by different procedures. Anyway, if
properly configured, the JVM won't let any untrusted code doing anything
wrong.

Java's security model is extremely powerful and flexible, so I think we
can postpone this discussion to the late implementation stage - at the
moment I hardly see any situation where the current functionality might
not be enough. I'd define the possibility of a risk "Java security model
does not hadle all needed scenarios" as very unlikely, but even with the
high impact (re-writing the code) the standard measure in this case is
"wait and watch".

Roman

P.S. The worst thing about Java security is that things are getting very
complex. And we not only will require a DBA, but also a Java specialist
for security configuration. This will no longer be a DBA-free RDBMS.
Well... at least there's alway a possibility to say:

grant {
permission java.security.AllPermission;
}

which removes any restriction imposed by the security manager.