Fix a failure to start as normal user, and make a custom security policy available for migrating from 1.5 #334
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Issue #331 prevents extension startup by a normal (non-superuser, non-
pg_read_all_settings) user. Fix that.Further, by request, make available a custom security policy that can log permission requests that the regular policy would deny, but then allow them, so that existing code being migrated from PL/Java 1.5 can be run without disruption while evaluating it for permission grants that may need to be added to the regular policy.
It works like this:
pljava.policy_urlspoint to the normal policy file(s), as usual. That's where the ultimate policy for production will be developed.You can create another policy file somewhere, the "trial" policy, and point to it with
-Dorg.postgresql.pljava.policy.trial=url added topljava.vmoptions. Anything this policy allows will be allowed, but will be logged if the regular policy would have denied it. So you can make this one more generous than the regular policy, and use the log entries to identify grants that might belong in the regular policy. As you add the missing ones to the real policy, they stop getting logged by this one, and the log gets quieter. You can make this one as generous as you are comfortable making it during the period of testing and tuning.At the very extreme of generosity it could be this:
and it would happily allow the code under test to do anything at all, while logging whatever permissions aren't in the regular policy. (A side effect of this would be to erase any distinction between
javaandjavaU.) Such a setting would be difficult to recommend in general, but it might suffice if the only code being tested has already been in use for years under PL/Java 1.5 and is well trusted, and if the purpose of testing is only to learn what permissions it uses that may need to be granted in the 1.6 policy.When
AllPermissionis too broad, there is the difficulty that Java's permission model does not have a subtractive mode; you can't say "grantAllPermissionexcept for this list of the ones I'd really rather not." So this PR adds a new permission:which is pretty much exactly a hard-coded version of "
AllPermissionexcept not anyFilePermission(so thejava/javaUdistinction stays meaningful) or a couple dozen other variousSecurityPermission/ReflectPermission/RuntimePermissioninstances in the "really rather not" category. If its hard-coded exclusion list excludes any permissions that some unusual code under test might need, those can be explicitly added to the trial policy too.So setting up the trial policy can be a bit of a balancing act: if you make it very generous, you minimize the chance of the app failing because of a denied permission, but increase your exposure. By making it more limited, you decrease exposure but increase the risk of the app falling over because it really did need some permission you weren't comfortable putting in the trial policy. The meta-permission
TrialPolicy$Permissiontries to come somewhere near the sweet spot.You can also use all of the normal policy features in the trial policy. If your apps are installed in several different jars, you can use
grant codebaseseparately to put different outer limits around different jars, and completely remove the grants for one jar after another as you are satisfied you have added the right things for each one in the regular policy. You could also set different limits forjavaandjavaUby granting to thePLPrincipal, just as you can in the regular policy.About false positives
One thing to be aware of is that the trial policy can give false alarms. It's not that uncommon for software to include configuration-dependent bits that tentatively try certain actions, catch exceptions, and proceed normally, having discovered what the configuration allows. The trial policy can log permission denials that happen in the course of that kind of activity, but where if you weren't using the trial policy you would never notice a problem from the code not being granted those permissions.
There may be no perfect way to tell which denials being logged by the trial policy are false alarms. One approach would be to collect a bunch of the log entries, figure out what functions of the code they were coming from, and then start a dedicated session without the
-Dorg.postgresql.pljava.policy.trialsetting (or with it pointing to a different, more restrictive version of the policy, not granting the permissions you're curious about), then exercise those functions of the code and see if anything breaks. Other users could still have the more generous trial setting in their sessions, so your experiments aren't affecting them.False positives, of course, are also affected by the choice of how generous to make the trial policy. Log entries are only produced for permissions that the regular policy denies but the trial policy allows. If the permissions being silently checked by benign code are not granted in the trial policy, they will be silently denied as in normal operation, and produce no log entries.
Format of the log entries
To avoid bloating logs too much,
TrialPolicyemits an abbreviated form of stack trace for each entry. The approach is to keep one stack frame above and one below each crossing of a module or protection-domain boundary, with...replacing intermediate frames within the same module/domain, and the code source/principals of the denied domain shown at the appropriate position in the trace. For the purpose of identifying the source of a permission request and the appropriate domain(s) to be granted the permission, this is probably more usable than the very long full traces output byjava.security.debug.The messages are sent through the PostgreSQL log if the thread making the permission check knows it can do so without blocking; otherwise they just go to
stderr(which should wind up in the PostgreSQL log anyway, iflogging_collectoris on, otherwise who knows where). There isn't really a reliable "can I do so without blocking?" check for every flavor ofpljava.java_thread_pg_entry. If it is set tothrow, the logging behavior will be more predictable; entries from the main thread will go through PostgreSQL's log facility always, and those from any other thread will go tostderr.