Block instances of a class at the JVM level? - java

Is there a way to configure the JVM to block instances of a class being created?
I'd like to do this to ensure no service running in the JVM is allowed to create instances of a class that has been identified as a security risk in a CVE, lets call that class BadClass.
NOTE: I'm looking for a general solution, so the following is purely additional information. I would normally address this by switching the library out, or upgrading it to a version that doesn't have the exploit, but it's part of a larger library that wont be addressing the issue for some time. So I'm not even using BadClass anywhere, but want to completely block it.

I do not know a JVM parameter, but here's some alternatives that might pout you in a position that solve your requirements:
You can write a CustomClassLoader that gives you fine control on what to do. Normal use cases would be plugin loading etc. In your case this is more security governance on devops level.
If you have a CICD pipeline with integration tests you could also start the JVM with -verbose:class parameter and see which classes are loaded when running your tests. Seem a bit hacky, but maybe suits your use case. Just throwing everything into the game, it's up to you judging about the best fit.
Depending on your build system (Maven?) you could restrict building applications just on your private cached libs. So you should have full control on it and put a library - review layer in between. This would also share responsibility between devs and the repository admins.

A distinct non-answer: Do not even try!
What if that larger library that has this dependency wants to call that method? What should happen then?
In other words, what is your blocking supposed to do?
Throw some Error instance, that leads to a teardown of the JVM?
Return null, so that (maybe much later) other code runs into a NPE?
Remember: that class doesn't exist in a void. There is other code invoking it. That code isn't prepared for you coming in, and well, doing what again?!
I think there are no good answers to these questions.
So, if you really want to "manipulate" things:
Try sneaking in a different version of that specific class into your classpath instead. Either an official one, that doesn't have the security issue, or something that complies to the required interface and that does something less harmful. Or, if you dare going down that path, do as the other answer suggests and get into "my own classloader" business.
In any case, your first objective: get clean on your requirements here. What does blocking mean?!

Have you considered using Java Agent?
It can intercept class loading in any classloader, and manipulate it's content before the class is actually loaded. Then, you may either modify the class to remove/fix it's bugs, or return dummy class that would throw error in static initializer.

Related

Dynamically loading jar from arbitrary url

Recently AWS Lambda added support for Java.
While this is great news, this come with a pretty severe limitation to the size of the code (50MB compressed). While this may be fine for other languages, Java uberjars can easily beat that.
So I've been toying with the idea of having a small loader that pull in, at runtime, a bigger jar from somewhere else. (set aside if this is a good idea or not for a moment).
From my initial research seems that a Custom Class Loader is the way to go. This is probably a no go for AWS Lambda.
Is there any other creative way this could be achieved?
I think ClassLoader, and more precisely URLClassLoader, is the way to go, and I don't know of any other solution to load code at runtime.
The class loader does not even have to be custom. It works with just a few lines of code, as demonstrated in this post.
If the jar files you will load fulfill a particular service for your application, also consider the handy ServiceLoader. It works on the same principle (in fact, you can pass it directly a ClassLoader), but makes it transparent to instantiate objects from the dynamically loaded library. Otherwise, you would have to get your hands a bit dirty, using something like:
Object main = loader.loadClass("Main", true).newInstance();

Deprecating an java JRE method

I would like to mark usage of certain methods provide by the JRE as deprecated. How do I do this?
You can't. Only code within your control can have the #Deprecated annotation added. Any attempt to reverse engineer the bytecode will result in a non-portable JRE. This is contrary to Java's write once, run anywhere methodology.
you can't deprecate JRE methods, but you can add warnings or even compile errors to your build system i.e. using AspectJ or forbid the use of given methods in the IDE.
For example in Eclipse:
Go to Project properties -->Java Compiler --> Errors Warnings, Then enable project specific settings, Expand Deprecated and restrited APIs category
"Forbidden reference (acess rule)"
Obviously you could instrument or override the class adding #Deprecated annotation, but it's not a clean solution.
Add such restrictions to your coding guidelines, and enforce as part of your code review process.
You only can do it, if and only if you are building your own JRE! In that case just add #Deprecated above the corresponding code block! But if you are using Oracle's JRE, you are no where to do so!
In what context? Do you mean you want to be able to easily configure your IDE to inhibit use of certain API? Or are you trying to dictate to the world what APIs you prohibit? Or are you trying to do something at runtime?
If the first case, Eclipse, and I assume other IDEs, allow you to mark any API as forbidden, discouraged, or accessible at the package or class level.
If you mean the second, you can't, of course. That would be silly.
If you are trying to prohibit certain methods from being called at runtime, you can configure a security policy to prevent code loaded from specified locations from being able to call specific methods that check with the SecurityManager, if one is installed.
You can compile your own version of the class and add it to the boot class path or lib/ext directory. http://docs.oracle.com/javase/tutorial/ext/basics/install.html This will change the JDK and the JRE.
In fact you can remove it for compiling and your program won't compile if it is used.
Snihalani: Just so that I get this straight ...
You want to 'deprecate methods in the JRE' in order to 'Making sure people don't use java's implementation and use my implementation from now on.' ?
First of all: you can't change anything in the JRE, neither are you allowed to, it's property of Oracle. Uou might be able to change something locally if you want to go through the trouble, but that 'll just be in your local JRE, not in the ones that can be downloaded from the Oracle webpage.
Next to that, nobody has your implementation, so how would we be able to use it anyway? The implementations provided by Oracle do exactly what they should do, and when a flaw/bug/... is found it'll be corrected or replaced by a new method (at which point the original method becomes deprecated).
But, what mostly worries me, is that you would go and change implementations with something you came up with. Reminds me quite lot of phishing and such techniques, having us run your code, without knowing what it does, without even knowing we are running your code. After all, if you would have access to the original code and "build" the JRE, what's to stop you from altering the code in the original method?
Deprecated is a way for the author to say:
"Yup ... I did this in the past, but it seems that there are problems with the method.
just in order not to change the behaviour of existing applications using this method, I will not change this method, rather mark it as deprecated, and add a method that solves this problem".
You are not the author, so it isn't up to you to decide whether or not the methods work the way they should anyway.

How can I unit test GC?

For a project, we need a way to run user scripts that can come with attached JAR files with additional classes.
What are my options when I want to write a couple of tests to make sure normal script don't leave anything dangling behind?
I specifically need to know: Are all classes from the attached JARs "unloaded"?
Note: I'm not looking for the 100% super-watertight solution that works across all versions of Java from 1.0 to 7. Right now, I just need to be better than "I have no idea".
The likely best option is to ensure your loaded jars are loaded by a specific class loader, and then to discard that class loader (after discarding all the objects).
As far as unit testing the unloading, if you go with this option, you need to extend your testing framework and customized class loaders to have a "create class loader on demand" flag. Then you load the class once with the flag on, discard the class loader, and attempt to load the class again with the flag off. If the class is truly not reachable, the second attempt should throw a class not found exception. You then wrap your unit tests to pass if they fall into the exception, and fail if they succeed in hitting the line after the second load attempt.
If you are disposed to use more than pure-Java tools, an OSGi container might be a consideration. Most of the established OSGi container implementations explicitly test class unloading.
I wouldn't try to unit test this. Instead, I'd run the JVM with -XX:-TraceClassUnloading and look to see if the classes in question show up in the trace output.
It looks like what you want to test is that hose scripts don't have a classloader leak.
To do that, I'd create a WeakReference to the ClassLoader used to load that JAR, then run the script, then call System.gc() and afterwards assertNull(reference.get())
This depends entirely on the way you allow the scripts to run. Do they have access to the classes of the rest of the application?
The typical way to leak memory in Java is to have a static reference. A static reference is only static within the ClassLoader of the class that contains it. So, if you load your user scripts using a ClassLoader you manage yourself (and you should do this anyway), then the references (static or not) inside will be eligable for GC as soon as your classloader itself it.
The only way they could work around this, is to add a reference to one of their objects into one of yours. So you have to be very careful with the API you expose. Another way is if they would make a static reference to their class in a class from another ClassLoader.
I don't see a way to fully automate testing for this. But I suppose you could trace the class unloading with any decent profiler.

How do I catch the read and writes in a java program?

I am trying to create a tool that can capture all the read and writes made by a java program. Also, I would like to know what fields of what object is access/modified.
I currently looked at:-
1) java.lang.instrument
I could not do much with that. I could not understand how to write an agent that can get access to the a running program and create a watch on different objects/fields and anything related. I would appreciated if you have any idea or information on that.
2) jvmti
I looked at jvmti and tried to create a jvmti tool, but I figured out that to get the objects, I would need the JVMTI_EVENT_OBJECT_ALLOC be a potential capability. But, I figured that, it is not. Moreover, I read that this event is not called for new command. Hence, at the moment, even this does not seem applicable.
So, I would like to know if you guys know any way to do what I want to do, either using the above mentioned methods or any other technique/tool that you may be aware of?
NOTE: I do not have access to the source code of the application. All, I have are the class files.
Check these out:
http://download.oracle.com/javase/6/docs/technotes/guides/management/jconsole.html
http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html
http://jamonapi.sourceforge.net/
http://www.manageengine.com/products/applications_manager/java-runtime-monitoring.html
It's very easy to do with the ASM lib. Create a new Class Loader that instruments all classes before loading them and use it for loading the target classes. Create a new MethodAdapter and override the visitFieldInsn method. Then look for the PUTFIELD, PUTSTATIC, GETFIELD and GETSTATIC opcodes. Although this might look scary (as my explation is most likely gibberish), it's in fact pretty easy. Just download the ASM manual and you'll know how to do it in no time.
Edit: I was forgetting to tell that in order to be able to intercept the reads and writes of done by the JDK code you have to instrument those classes, save them to files and run the JVM with a modified bootstrap classpath, through command line argument -Xbootclasspath (java.* and some other packages; I believe that at least sun.* and javax.* also need this).
This may also be doable with AspectJ... but I'm not sure.

How to manage multiple versions of same class file for different SDK targets?

This is for an Android application but I'm broadening the question to Java as I don't know how this is usually implemented.
Assuming you have a project that targets a specific SDK version. A new release of the SDK is backward incompatible and requires changing three lines in one class.
How is this managed in Java without duplicating any code(or by duplicating the least amount)?
I don't want to create two projects for only 3 lines that are different.
What I'm trying to achieve in the end is a single executable that'll work for both versions. In C/C++, you'd have a #define based on the version. How do I achieve the same thing in Java?
Edit: after reading the comments about the #define, I realized there were two issues I was merging into one:
So first issue is, how do I not
duplicate code ? What construct is there that is the equivalent of a
#define in C.
The second one is: is it possible
to bundle everything in the same
executable? (this is less of a
concern as the first one).
It depends heavily on the incompatibility. If it is simply behavior, you can check the java.version system property and branch the code accordingly (for three lines, something as simple as an if statement).
If, however, it is a lack of a class or something similar that will throw an error when the class is loaded or when the code gets closer to execution (not necessarily something you can void reasonably by checking before calling), then the solution gets a lot harder. The notion of having a separate version is the cleanest from a code point of view, but it does mean you have to distribute two versions.
Another solution is reflection. Don't reference the class directly, call it via reflection (test for the methods or classes to determine what environment you are currently running in and execute the methods). This is probably the "official" approach in that reflection exists to deal with classes that you don't have or don't know you will have at compile time. It is just being applied to libraries within the JDK. It gets very ugly very fast, however. For three lines of code, it's ok, but doing anything extensive is going to get bad.
The last thing I can think of is to write common denominator code - that is code that gets the job done in both, finding another way to do it that doesn't trigger the problematic class or method.
I would isolate the code that needs to be different in a separate class (or multiple classes if necessary), and include / exclude them when building the project for the different versions.
So i would have like src/java/org/myproj/Foo.java which is the common stuff, and then oldversion/java/org/myproj/Bar.java and newversion/java/org/myproj/Bar.java which is the different implementations of the class that uses changed api.
Then I either compile "src/java and oldversion/java" or "src/java and newversion/java".
Possibly a similar situation, I had a method which wasn't available in the previous version of the JDK but if it was there I wanted to call it, I didn't want to force people to use the more recent version though. I used reflection to look for the method, if it was there I called it, if it wasn't I didn't.
Pretty hacky but might give you what you want.
Addressing Java in general, I see two primary approaches.
1). Refactor the specific code to its own library. Have different versions of that library. Effectively your app is creating an abstaction above the different SDKs. Heavyweight for 3 lines of code, but perhaps quite reasonable for larger scale problems.
2). Injection using annotation. Write your own annotation processor to manage the appropriate injection. More work, but maybe more fun.
Separate changing code in different classes with the same interface. Place classes in the same jar. Use factory design pattern to instantiate one or another class depending on SDK version.

Categories