RFR: 8200559: Java agents doing instrumentation need a means to define auxiliary classes [v2]

Rafael Winterhalter winterhalter at openjdk.java.net
Mon Apr 19 21:20:06 UTC 2021

On Fri, 16 Apr 2021 20:30:15 GMT, Rafael Winterhalter <winterhalter at openjdk.org> wrote:

>> To allow agents the definition of auxiliary classes, an API is needed to allow this. Currently, this is often achieved by using `sun.misc.Unsafe` or `jdk.internal.misc.Unsafe` ever since the `defineClass` method was removed from `sun.misc.Unsafe`.
> Rafael Winterhalter has refreshed the contents of this pull request, and previous commits have been removed. The incremental views will show differences compared to the previous content of the PR. The pull request contains one new commit since the last revision:
>   8200559: Java agents doing instrumentation need a means to define auxiliary classes

At the moment, it is required for root to switch to the user that owns the
JVM process as the domain socket is only accessible to that user to avoid
that users without access to the JVM can inject themselves into a JVM. I am
not sure if operations teams would be thrilled to have a monitoring agent
required to run as root, even in these times of Kubernetes.

I mainly have two comments:

1. The problem is the possibility of self-attach. I think this is the
problem to solve, a library getting agent privileges without being an
agent. I think this should be prevented while dynamic attach should
continue to be possible in today's format. It has proven to be so useful,
it would be a shame if the current tooling convenience would disappear from
the JVM. As it's my understanding, JNI is supposed to be restricted in the
future, in line with Panama. Without this restriction, JNI already allows
for random class definition, for example, which similarly to an agent
offers surpassing the majority of JVM restrictions. The second restriction
would be a control to restrict how a JVM process starts new processes. I
think both are reasonable restrictions for a library to face which require
explicit enabling. Especially with the security manager on it's way out,
certain capabilities should be rethought to begin with. If both are no
longer freely available, self-attachment is no longer possible anyways and
dynamic agents could retain their capabilities.

2. The question of introducing an Instrumentation::defineClass method is
fully independent of that first question. If a dynamic agent was to be
restricted, the method could reject classloader/package combinations for
dynamically loaded agents the same way that
Instrumentation::retransformClasses would need to. At the same time,
introducing the method would allow agents to move to an official API with a
Java 17 baseline which will be the next long-standing base line. I fully
understand it needs a thorough discussion but it is a less complicated
problem then (1) and could therefore be decided prior to having found a
satisfactory solution for it.

Am Mo., 19. Apr. 2021 um 16:07 Uhr schrieb Peter Levart <

> an application or library can use the attach mechanism (directly or via
> the attach API in a child VM) to load an agent and leak the Instrumentation
> object. This is the genie that somehow needs to be put back in its bottle.
> One approach that I mentioned here to create is a less powerful
> Instrumentation object for untrusted agents. Trusted agents would continue
> to the full-power
> I hear Rafael that dynamic attach is important to support monitoring and
> instrumenting large numbers of JVMs with no preparations (i.e. without
> issueing special command-line options to enable it). As I understand,
> current attach mechanism is designed to allow a process running under the
> same UID as the JVM or under root to attach to the JVM.
> What if this dynamic attach mechanism was modified so that only a process
> running under root could dynamically attach to the JVM? Old behavior would
> be enabled by special command line option, so by default, dynamic attach
> would be limited to tools running under root. Rafael mentions discovery,
> monitoring and instrumenting large number of JVMs running on hosts, so if
> one such tool has to attach to different JVMs running under different UIDs,
> it has to run as root now anyway.
> With such default "secure" dynamic attach and when the JVM is not running
> as root (which is a recommended security practice anyway), a library in
> such JVM could not attach back to the same JVM even through spawning
> sub-processes.
> How to achieve such "secure" dynamic attach? One way that comes to mind is
> a modified handshake. Currently, I think at least on Linux, the tool that
> wishes to attach to the JVM searches for a special UNIX socket (
> $PWD/.java_pid<vmid>, /tmp/.java_pid<vmid>) and if not found, creates a
> special attach file ($PWD/.attach_pid<vmid>, /tmp/.attach_pid<vmid>) to
> signal the JVM to create a listening UNIX socket under mentioned special
> path, then it connects to the socket. The UNIX socket file has UID:GID set
> to effective UID:GID of the JVM process and permissions to 0600, so only a
> tool running under same UID or root can connect to such socket.
> In modified handshake, JVM not running as root could not create a UNIX
> socket file with permissions to allow only root user to connect to it, but
> a tool running under root could create a listening UNIX socket with
> permission to allow JVM to connect to it in a way that the JVM connecting
> to such socket would know that the listening process is running as root.
> Simply by checking the owner of the listening UNIX socket file. Such socket
> file would have to have permission 0666 in order to allow JVMs running
> under any UID to connect to it, but otherwise be "hidden". This can be
> achieved by the tool creating a special directory and a UNIX socket in this
> directory, say: /tmp/.attach_dir<tool pid>/<random string>, The directory
> UID:GID would be 0:0 and have permission 0711. This means, any user could
> connect to the socket as long as it knows the <random string>, but no
> user but root can list the content of the directory to discover the name of
> the socket file. The last piece of the puzzle is how to signal to the JVM
> about the name of the socket file. Well, creating a file with the content
> holding the name of the socket file would be OK, as long as only target JVM
> could read it. File permissions could be set such that any process running
> under the same UID as the JVM could read the file. This would give a rouge
> library a chance to connect to the tool and pretend to be the monitoring
> JVM, but it could not connect to back to the JVM though...
>> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/openjdk/jdk/pull/3546#issuecomment-822495459>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ABCIA4GPK73MWBRBICZS6Y3TJQ2LLANCNFSM43BSDEGQ>
> .


PR: https://git.openjdk.java.net/jdk/pull/3546

More information about the core-libs-dev mailing list