Disallowing the dynamic loading of agents by default
Andrew Dinn
adinn at redhat.com
Tue Apr 4 10:45:02 UTC 2017
Hi Mark,
Thanks again for another thoughtful and well-reasoned response.
On 03/04/17 23:36, mark.reinhold at oracle.com wrote:
> 2017/4/3 9:44:43 -0700, Andrew Dinn <adinn at redhat.com>:
>> One thing I am not clear on as regards that 'really nice' is whether
>> anything in the JVM wants -- or even hopes -- to rely on module
>> encapsulation never being broken in order to provide 'semantic'
>> guarantees. . . .
>
> That's exactly the kind of thing we want to enable, long-term, and one
> reason why integrity is worth improving aside from any considerations
> of security -- and why suggestions by others to "just use a security
> manager" if you care about such things are beside the point.
> . . .
Well, I am all for that sort of opportunity and I accept that it very
much changes the balance of costs at play here that such opportunities
exist.
> <snip>
> In addition to future performance improvements, let's not forget about
> maintainability. Improved integrity allows those of us who maintain the
> JDK to change internal implementation details without having to worry
> about breaking user code. It allows users of the JDK to be confident
> that their code depends only on supported interfaces, so that they can
> more easily upgrade from one release to the next. We've all too often,
> over the last twenty years, had to back out internal changes because
> some popular library depended upon those internals.
I also appreciate this argument but I would doubt that this applies to
most (perhaps all) agents that break encapsulation barriers. Certainly,
most users of Byteman normally must know that they are only doing so
temporarily and contingently.
Breaking encapsulation is frequently used during unit and integration
testing to prove that an implementation satisfies certain invariants
expected from the design (whether by tracing or injecting assertions).
Of course, such a proof is only available via injected behaviour since
the only other option to allow such validation a test time requires not
encapsulating state and/or behaviour. However, it is equally clear that
the presumed applicability of such invariants cannot extend beyond the
point where redesign and re-implementation necessarily bring it into
question. A similar story applies for tests relying on injection of faults.
Breaking encapsulation at (sand-boxed or live) deployment time is used
to investigate application and JDK runtime state. However, that is also,
by its nature, an ad hoc and temporary process. The important thing is
to understand what is happening in the code now deployed. Considerations
as to what might change in future versions of the platform are hardly
relevant.
> <snip>
> Anyway ... at the highest level, improving platform integrity is not just
> about improving security. It's also about improving performance, in the
> long term, and about improving the maintainability of everybody's code,
> even in the short term.
Ok, point taken.
> <snip>
>> Are you perhaps concerned that users might have their hand forced by
>> providers of library jars or middleware who hoist an agent into the JVM
>> behind their backs? . . .
>
> I wish I could share your optimism in this regard, but it's contrary to
> my experience. That a library does questionable things does not always
> dissuade people from using it. An instance of the scenario I described
> above, where you can read "popular applications" as "every major Java EE
> application server", occurred late in the development of JDK 5. Some
> obscure library was reaching into JDK internals. The fact that it did so
> was well-documented and (presumably) clear to its immediate users but did
> not prevent it from becoming widely used. It was apparent at the time
> that the true nature of this library surprised some of those responsible
> for higher-level components that depended indirectly upon it.
I may indeed be over-optimistic or simply swayed by a rather deluded
democratic spirit but thank you for elucidating the sort of case you are
considering.
> So, yes, call it patronising if you like but we are concerned about
> enabling a library to self-attach and inject an agent which it uses to
> subvert strong encapsulation without the developer (or the deployer)
> knowing about it. I fully agree that sophisticated late-binding agents
> can have legitimate needs to break strong encapsulation, and that they
> should be permitted to do so in the full sight of their users. What I
> don't yet see is a way to enable those by default while at the same
> time disabling sneaky encapsulation-busting libraries whose inevitable
> inadvertent use will lead to maintenance headaches down the line.
I appreciate the dilemma and indeed understand why it forms part of your
rationale for the current proposal.
> <snip>
>> I'm very happy to consider all sorts of half-way houses or even -- in
>> time -- the full change recommended in the original JIRA. For example,
>> rejecting instrumentation in some specific set of bootstrap/JDK module
>> classes (like, say, java.base) from an agent which has been dynamically
>> loaded might well be a workable compromise -- that at least allows users
>> to employ an agent to tweak any code that is in the classpath through
>> their choice.
>
> That's an interesting option, and worth exploring further. It could,
> though, be troublesome for legitimate late-binding agents that instrument
> JDK internals. Is Byteman typically used in that way?
Well, if it helps to provide the guarantees that the JDK runtime or core
runtime wants in order to enable performance improvements then I'd
certainly be /interested/ in a restriction that merely put certain
classes out of reach of dynamic agents (assuming it also comes with an
option to remove that restriction).
Of course,-- to answer your question -- that would still present a
problem for Byteman; it is often used to inject into core (java.base)
classes.
There are quite a few unit/integration testing scenarios where the
ability to tweak the operation of core JDK runtime code is really
useful. For example, injecting a THROW rule into class File to simulate
an IOException is probably the poster-child for Byteman fault injection.
The same also applies when using Byteman for runtime diagnosis. A very
good example of that was when one of our customers kept finding that the
first connection obtained from a connection pool would always fail with
a connection error. Trace code injected into Thread.isInterrupted
revealed the reason for the failure -- the application thread's
interrupt state was already set before the open attempt. A stack
backtrace call injected into Thread.setInterrupted showed that a 3rd
party library was invalidly setting (and then not clearing) the
interrupted state as part of application thread initialization.
So, in summary:
I'm interested in the option for a default setting to provide limited
access to runtime and/or application classes from dynamically loaded
agents -- it's an improvement on no access at all.
However, on Byteman's account, I'd still really prefer the ability to
support full access in the JDK9 time frame with a move to whatever more
limited access is determined appropriate in JDK10 (for the reasons
already mentioned).
regards,
Andrew Dinn
-----------
Senior Principal Software Engineer
Red Hat UK Ltd
Registered in England and Wales under Company Registration No. 03798903
Directors: Michael Cunningham, Michael ("Mike") O'Neill, Eric Shander
More information about the jigsaw-dev
mailing list