Craig's right.
The way the Java 2 security manager works is pretty simple. Most
system classes whose methods call "sensitive" functions need to know
that callers possess the correct privileges. To do this, the security
manager does what's called a "stack walk" -- essentially, it starts
with the current stack frame (class+method+line of code) and walks its
way backwards in the call stack until it gets to the very topmost
frame (e.g., the Main method that started the program) or a
doPrivileged() block, whichever comes first. All of the code sources
in between must be granted the privilege in order for it to be granted.
The idea is very simple, and provably secure. The consequences are
complex, however... here's an example.
We've got an application (JSPWiki) running in a web container. One of
our classes has a method foo() that needs to read the file /usr/bin/
bar. You'd think that our code source (e.g., JSPWiki.jar) would needs
to be granted java.io.FilePermission "/usr/bin/bin", "read". And you'd
be right. That's easy enough to understand, but not the end of the
story.
Because of the way the security manager works, unless the code that
invokes the read operation is bracketed by a doPrivileged() block, the
code source for the stack frame that called foo() ALSO needs to be
granted the FilePermission in the security policy. And so does the
parent *that* frame. And so forth...
Practically speaking, this means that code that performs sensitive
functions (that is, causes a privilege check) needs to be isolated by
doPrivileged() blocks so that it doesn't "infect" upstream callers
with the requirement to be granted the same privileges. As it stands
now, all of the privileges we would have to grant JSPWiki would also
need to be granted to all of the Catalina JARs (or OAS, or whatever).
There are two ways of dealing with this:
1) Leaving the code the way it is, but requiring that container JARs
be granted all of the privileges we grant JSPWiki. This makes the
security policy non-portable, and would be a pain in the arse for
system admins.
2) Adding doPrivileged blocks to code that calls sensitive functions,
which makes the policy portable. But it's a pain in the arse for us
coders. :)
As it happens, one of my side projects outside of JSPWiki is a "policy-
maker" project called (with tongue planted firmly in cheek) Kissinger.
Kissinger's role is to install a dummy SecurityManager at runtime that
logs what privileges callers need. Then, after program termination it
tries to create an optimal security policy. It also recommends places
to inject doPrivileged() blocks. The recording and policy-writing part
works just fine, thanks to some clever code that works sort of like a
rootkit (Craig, as the token Sun rep here, please cover your ears).
But the analytics part -- doesn't work yet. And I haven't touched the
code in over 9 months...
Janne, if you want, I can dust off Kissinger (har har) and see what's
required to get it working.
In the meantime, the best thing to do is start looking for code that
calls methods that require privilege checks (notably file access,
serialization, system properties, SQL, reflection) and put
doPrivileged() blocks around them. The list of methods that require
permissions are here:
http://java.sun.com/j2se/1.4.2/docs/guide/security/permissions.html
The file I/O code is the most important. I've previously done this
already for the JAAS-related code.
Andrew
On Nov 21, 2007, at 4:03 PM, Craig L Russell wrote:
Hi Janne,
On Nov 21, 2007, at 12:46 PM, Janne Jalkanen wrote:
(Digression for Janne and the dev team: any time we do things like
file access, we need to bracket the code with a doPrivileged()
block so that we don't have to grant file I/O privileges to the
container... this is one of the big complicating factors that is
preventing a full enumeration of privileges at the moment...)
This sounds insane to me. It complicates everything, and what
would we gain by doing it?
What we gain is the ability to run the code inside a standard Java
EE container. Instead of mucking around with container permissions
or application permissions, you put the required privileges
associated with the jspwiki jar file.
There are just a few things that need to be wrapped in a
doPrivileged block, like i/o and reflection. It's not all i/o, just
stuff like file.createNewFile() and FileInputStream(file). Once you
have an InputStream the rest of the code is normal.
Craig
/Janne
Craig Russell
Architect, Sun Java Enterprise System http://java.sun.com/products/jdo
408 276-5638 mailto:[EMAIL PROTECTED]
P.S. A good JDO? O, Gasp!