Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Secure Debugging for Production JVMs

Tags:

We have some applications that sometimes get into a bad state, but only in production (of course!). While taking a heap dump can help to gather state information, it's often easier to use a remote debugger. Setting this up is easy -- one need only add this to his command line:

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=PORT

There seems to be no available security mechanism, so turning on debugging in production would effectively allow arbitrary code execution (via hotswap).

We have a mix of 1.4.2 and 1.5 Sun JVMs running on Solaris 9 and Linux (Redhat Enterprise 4). How can we enable secure debugging? Any other ways to achieve our goal of production server inspection?

Update: For JDK 1.5+ JVMs, one can specify an interface and port to which the debugger should bind. So, KarlP's suggestion of binding to loopback and just using a SSH tunnel to a local developer box should work given SSH is set up properly on the servers.

However, it seems that JDK1.4x does not allow an interface to be specified for the debug port. So, we can either block access to the debug port somewhere in the network or do some system-specific blocking in the OS itself (IPChains as Jared suggested, etc.)?

Update #2: This is a hack that will let us limit our risk, even on 1.4.2 JVMs:

Command line params:

-Xdebug
-Xrunjdwp:
    transport=dt_socket,
    server=y,
    suspend=n,
    address=9001,
    onthrow=com.whatever.TurnOnDebuggerException,
    launch=nothing

Java Code to turn on debugger:

try {
    throw new TurnOnDebuggerException();
} catch (TurnOnDebugger td) {
   //Nothing
}

TurnOnDebuggerException can be any exception guaranteed not to be thrown anywhere else.

I tested this on a Windows box to prove that (1) the debugger port does not receive connections initially, and (2) throwing the TurnOnDebugger exception as shown above causes the debugger to come alive. The launch parameter was required (at least on JDK1.4.2), but a garbage value was handled gracefully by the JVM.

We're planning on making a small servlet that, behind appropriate security, can allow us to turn on the debugger. Of course, one can't turn it off afterward, and the debugger still listens promiscuously once its on. But, these are limitations we're willing to accept as debugging of a production system will always result in a restart afterward.

Update #3: I ended up writing three classes: (1) TurnOnDebuggerException, a plain 'ol Java exception, (2) DebuggerPoller, a background thread the checks for the existence of a specified file on the filesystem, and (3) DebuggerMainWrapper, a class that kicks off the polling thread and then reflectively calls the main method of another specified class.

This is how its used:

  1. Replace your "main" class with DebuggerMainWrapper in your start-up scripts
  2. Add two system (-D) params, one specifying the real main class, and the other specifying a file on the filesystem.
  3. Configure the debugger on the command line with the onthrow=com.whatever.TurnOnDebuggerException part added
  4. Add a jar with the three classes mentioned above to the classpath.

Now, when you start up your JVM everything is the same except that a background poller thread is started. Presuming that the file (ours is called TurnOnDebugger) doesn't initially exist, the poller checks for it every N seconds. When the poller first notices it, it throws and immediately catches the TurnOnDebuggerException. Then, the agent is kicked off.

You can't turn it back off, and the machine is not terribly secure when its on. On the upside, I don't think the debugger allows for multiple simultaneous connections, so maintaining a debugging connection is your best defense. We chose the file notification method because it allowed us to piggyback off of our existing Unix authen/author by specifying the trigger file in a directory where only the proper uses have rights. You could easily build a little war file that achieved the same purpose via a socket connection. Of course, since we can't turn off the debugger, we'll only use it to gather data before killing off a sick application. If anyone wants this code, please let me know. However, it will only take you a few minutes to throw it together yourself.

like image 963
ShabbyDoo Avatar asked May 28 '09 19:05

ShabbyDoo


People also ask

How does JVM debugging work?

Since in the JVM architecture, the debugging functionality is not found within the JVM itself but is abstracted away into external tools (that are aptly referred to as debuggers), these tools can either reside on the local machine running the JVM being debugged or be run from am external machine.

How do I start JVM in debug mode?

Enable JVM DebuggingClick Java > JVM Settings tab. Under Debug Java Settings, select the Enable Debug checkbox. Provide JVM options as necessary by clicking the New button. If you substitute suspend=y, the JVM starts in suspended mode and stays suspended until a debugger attaches to it.


1 Answers

If you use SSH you can allow tunneling and tunnel a port to your local host. No development required, all done using sshd, ssh and/or putty.

The debug socket on your java server can be set up on the local interface 127.0.0.1.

like image 85
KarlP Avatar answered Sep 22 '22 12:09

KarlP