/*
* Copyright 2009-2012 Michael Dalton
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jtaint;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.util.CheckClassAdapter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
public class Bootstrap
{
private static Map classMap = new HashMap();
private static boolean debug;
private static void addInstrumentation(String className,
InstrumentationBuilder b)
throws IOException
{
ClassReader cr = new ClassReader(className);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv;
if (debug)
cv = b.build(new CheckClassAdapter(cw));
else
cv = b.build(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
classMap.put(className.replace('.','/') + ".class", cw.toByteArray());
if (debug) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false,
pw);
pw.flush();
if (sw.toString().length() > 0)
throw new IllegalArgumentException(sw.toString());
}
}
private static void addAnalysis(String className, AnalysisBuilder b)
throws IOException
{
ClassReader cr = new ClassReader(className);
ClassVisitor cv = b.build();
cr.accept(cv, ClassReader.EXPAND_FRAMES + ClassReader.SKIP_DEBUG
+ ClassReader.SKIP_FRAMES);
}
private static void writeJarFile(String rtJar, String outputJar,
String installPath)
throws IOException, FileNotFoundException
{
FileOutputStream fos = new FileOutputStream(outputJar);
JarOutputStream out = null;
if (rtJar != null) {
JarInputStream in = new JarInputStream(new FileInputStream(rtJar));
byte[] buf = new byte[4096];
if (in.getManifest() != null)
out = new JarOutputStream(fos, in.getManifest());
else
out = new JarOutputStream(fos);
JarEntry entry;
while ((entry = in.getNextJarEntry()) != null) {
out.putNextEntry(entry);
int r;
while ((r = in.read(buf)) != -1)
out.write(buf, 0, r);
out.closeEntry();
}
}
if (out == null)
out = new JarOutputStream(fos);
for (Iterator i = classMap.keySet().iterator(); i.hasNext();) {
String className = (String) i.next();
byte[] b = (byte[]) classMap.get(className);
out.putNextEntry(new JarEntry(className));
out.write(b);
out.closeEntry();
}
if (installPath != null) {
out.putNextEntry(new JarEntry("jtaint/InstallPath"));
out.write(installPath.getBytes());
out.closeEntry();
}
out.flush();
out.close();
}
private static void usage() {
System.err.println("Usage: jt-bootstrap [-i <installation path>] [-d]"
+ "[-r14 <runtime jre 1.4 jar filename>] "
+ "[-r15 <runtime jre 1.5+ jar filename>] "
+ "[-j <output jar filename>] ");
System.err.print("Options:");
System.err.println("-d\tEnable extra debugging checks");
System.err.println("-i\tSpecify installation directory pathname");
System.err.println("-r[14|15]\tSpecify name of runtime jar library to "
+ "include in the output jar file.\nIf either "
+ "of -r14 or -r15 is specified, both must be "
+ "provided.\nJRE 1.4 systems use -r14 libraries "
+ "while JRE 1.5 (or above) use -r15 libraries.");
System.err.println("-j <file>\tSpecify name of output jar file");
System.err.println("\t(Default: jt-bootlib.jar)");
System.err.println("see Reference documentation for more information");
System.exit(-1);
}
public static void main(String[] args) {
String rt14Jar = null,
rt15Jar = null,
installPath = null,
outputJar = "jt-bootlib.jar";
for (int i = 0; i < args.length; i++) {
if ("-r14".equals(args[i]) && i != args.length - 1)
rt14Jar = args[++i];
else if ("-r15".equals(args[i]) && i != args.length - 1)
rt15Jar = args[++i];
else if ("-j".equals(args[i]) && i != args.length - 1)
outputJar = args[++i];
else if ("-i".equals(args[i]) && i != args.length - 1)
installPath = args[++i];
else if ("-d".equals(args[i]))
debug = true;
else
usage();
}
if ((rt14Jar != null && rt15Jar == null) ||
(rt14Jar == null && rt15Jar != null))
usage();
if (VmInfo.version() == VmInfo.VERSION_UNKNOWN
|| VmInfo.vendor() == VmInfo.VENDOR_UNKNOWN) {
System.err.println("Unknown java configuration:");
System.err.println("vendor: " + System.getProperty("java.vendor"));
System.err.println("vm name: " +
System.getProperty("java.vm.name"));
System.err.println("version: " +
System.getProperty("java.specification.version"));
System.err.println("Please report this error to JavaTaint");
System.exit(-1);
}
try {
addInstrumentation("java.lang.String", StringAdapter.builder());
addInstrumentation("java.lang.StringBuffer",
StringBufferAdapter.builder());
addInstrumentation("java.lang.ClassLoader",
ClassLoaderAdapter.builder());
addInstrumentation("java.io.OutputStream",
XssAdapter.builder("java/io/OutputStream"));
addInstrumentation("java.io.PrintWriter",
XssAdapter.builder("java/io/PrintWriter"));
addInstrumentation("java.lang.Runtime", RuntimeAdapter.builder());
addInstrumentation("java.lang.Thread", ThreadAdapter.builder());
addInstrumentation("java.sql.Connection",
ConnectionAdapter.builder());
addAnalysis("java.io.File", FileAdapter.CloneOptimizer.builder());
addInstrumentation("java.io.File", FileAdapter.builder());
if (VmInfo.vendor() == VmInfo.VENDOR_BEA)
addInstrumentation("jrockit.vm.StringMaker",
StringMakerAdapter.builder());
if (VmInfo.version() >= VmInfo.VERSION1_5) {
addInstrumentation("java.lang.StringBuilder",
StringBuilderAdapter.builder());
addInstrumentation("java.lang.ProcessBuilder",
ProcessBuilderAdapter.builder());
writeJarFile(rt15Jar, outputJar, installPath);
} else {
writeJarFile(rt14Jar, outputJar, installPath);
}
} catch (Exception e) {
System.err.println("Bootstrap error: " + e);
e.printStackTrace();
System.exit(-1);
}
}
}