[External] : Re: Reflective access to bytes[] of loaded class

Brian Goetz brian.goetz at oracle.com
Thu Mar 9 19:30:42 UTC 2023


Doing `javap -p -c <classfiles>` assumes file-system access to the 
entire application.  Indeed, defending against "has write access to the 
application files" is more difficult.  But malicious libraries may be 
invoked by application code, and while they may not have access to the 
file system, they have access to reflection.  So leaking this 
information through reflection makes it available to more attackers than 
simply having it on the file system.

On 2/10/2023 8:54 AM, Gary Frost wrote:
> Brian
>
> I am not sure how  having a reflective method to access bytecode opens 
> up any more security issues than having access to  javap -p -c 
> <classfile>?
>
> Unless the password itself (in your example) was injected by a 
> transformation of the code by ClassLoader/JVMTI/Java agent.
>
> Maybe I am missing something.
> ------------------------------------------------------------------------
> *From:* Brian Goetz <brian.goetz at oracle.com>
> *Sent:* Thursday, February 9, 2023 6:52 PM
> *To:* Dan Heidinga <heidinga at redhat.com>; Gary Frost 
> <gary.frost at oracle.com>
> *Cc:* classfile-api-dev at openjdk.org <classfile-api-dev at openjdk.org>
> *Subject:* Re: [External] : Re: Reflective access to bytes[] of loaded 
> class
> One concern that we have is that unrestricted access to bytecode of 
> loaded classes may constitute an attack vector for malicious code.
>
> While we don't recommend people program like this:
>
>     boolean checkPassword(String pw) {
>         return "s00perSeekrit".equals(pw);
>     }
>
> arbitrary access to bytecode will compromise the "security" of this 
> code in ways that the author might not have reasonably forseen.
>
>
>
> On 2/9/2023 1:24 PM, Dan Heidinga wrote:
>> Thanks for confirming, Gary.
>>
>> On Thu, Feb 9, 2023 at 11:59 AM Gary Frost <gary.frost at oracle.com 
>> <mailto:gary.frost at oracle.com>> wrote:
>>
>>     Dan
>>
>>     I have indeed used JVMTI (and Java) agents for this. In the case
>>     of JVMTI by keeping a std::map<std::string,byte[]>, and providing
>>     a JNI call to get the bytes.
>>
>>     It works well for cases where we know the set of classes we want
>>     bytes for at JVM 'launch time' , or there is something in the
>>     class (name match? constant pool entry?) that we can trigger to
>>     prune the size of the map.    Otherwise we are forced to retain a
>>     map for all classes, just in case.
>>
>>     And of course who knew whether our JVMTI agent was the last
>>     'actor' in the chain of possible mutators to play with the bytes.
>>
>>
>> Can you expand on the use case for getting the current bytes from the 
>> runtime?  As I said in the previous email, they aren't a good 
>> candidate for feeding back into the runtime due to the existing JVMTI 
>> agent process.  Is this mostly for testing purposes?
>>
>> --Dan
>>
>>
>>
>>     Hence the desire for runtime help
>>
>>
>>     ------------------------------------------------------------------------
>>     *From:* Dan Heidinga <heidinga at redhat.com
>>     <mailto:heidinga at redhat.com>>
>>     *Sent:* Thursday, February 9, 2023 4:35 PM
>>     *To:* Gary Frost <gary.frost at oracle.com
>>     <mailto:gary.frost at oracle.com>>
>>     *Cc:* classfile-api-dev at openjdk.org
>>     <mailto:classfile-api-dev at openjdk.org>
>>     <classfile-api-dev at openjdk.org
>>     <mailto:classfile-api-dev at openjdk.org>>
>>     *Subject:* [External] : Re: Reflective access to bytes[] of
>>     loaded class
>>
>>
>>     On Thu, Feb 9, 2023 at 11:03 AM Gary Frost <gary.frost at oracle.com
>>     <mailto:gary.frost at oracle.com>> wrote:
>>
>>         I would like to make a case for adding a reflection API for
>>         getting the bytes for class loaded by the VM as part of this
>>         Classfile API.
>>
>>         Something akin to
>>
>>         byte[] Class.getClassfileBytes();
>>
>>
>>     I've often wanted the same kind of API when doing one off tests
>>     and minor modifications so I'm very sympathetic to the request. 
>>     Typically when doing more "serious" class modification, I've used
>>     the Instrumentation::retransform API [0] or written a native
>>     JVMTI agent [1] and then such an api to get the current classfile
>>     bytes isn't required.  Does this match your typical use cases as
>>     well?
>>
>>     The JVM does some interesting handling of classfile bytes in
>>     these cases - it allows non-retransform-capable agents to do a 1
>>     time modification of the original classfile bytes and then saves
>>     those bytes away before passing them on to the
>>     retransform-capable agents.  One subsequent retransform events,
>>     those saved bytes are reused and only the retransform-capable
>>     agents get a chance to modify the bytes.
>>
>>     The reason this matters is that existing retransform-capable
>>     agents aren't expecting to see the modifications they've made
>>     present in the classfile bytes they get passed.  Providing an
>>     easy api to get the currently executing bytecodes will mean that
>>     these agents will now "see" their own modifications which may
>>     result in incompatibilities.
>>
>>     I'd be interested in feedback from existing major agent providers
>>     to see how much of a problem such a change would cause them
>>     before pursuing it unless there's a more common pattern of use
>>     I'm unaware of.
>>
>>     [0]
>>     https://cr.openjdk.java.net/~iris/se/17/latestSpec/api/java.instrument/java/lang/instrument/Instrumentation.html#retransformClasses(java.lang.Class..
>>     <https://cr.openjdk.java.net/~iris/se/17/latestSpec/api/java.instrument/java/lang/instrument/Instrumentation.html#retransformClasses(java.lang.Class..>.)
>>
>>     [1]
>>     https://cr.openjdk.java.net/~iris/se/17/latestSpec/specs/jvmti.html#RetransformClasses
>>     <https://cr.openjdk.java.net/~iris/se/17/latestSpec/specs/jvmti.html#RetransformClasses>
>>
>>
>>
>>
>>         At present developers usually resort to something like
>>
>>         clazz.getClassLoader().getResourceAsStream(
>>             clazz.getName().replace(".", "/") + ".class")
>>
>>         Ignoring the fact that we may have just forced an expensive
>>         network fetch, to bytes that the JVM clearly already has
>>         'squirrelled away' somewhere...
>>
>>         For me this is hugely problematic as there is no guarentee
>>         that the bytes fetched from such a stream will match the
>>         bytes that the JVM is using for the class in question....
>>
>>         Java offers all sorts of opportunities (JVMTI agents, Java
>>         agents, even custom ClassLoaders) for mutating the incoming
>>         classfile's bytes. All of which the stream fetched via
>>         getResourceAsStream() completely sidesteps.
>>
>>
>>     See above (or the JVMTI spec) for which bytes get passed through
>>     to agents.  The story is more complex than it first appears.
>>
>>     --Dan
>>
>>
>>         This may well be considered 'out of bounds' for the Classfile
>>         API, but I think we should consider it, as it seems to be
>>         something that users of the Classfile API will need going
>>         forward.
>>
>>         Gary
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20230309/d7729af6/attachment-0001.htm>


More information about the classfile-api-dev mailing list