/*
* 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 java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
final class XssContextAdapter extends ClassAdapter implements Opcodes
{
public static final List outputStreamMethods;
public static final List servletOutputStreamMethods;
public static final List printWriterMethods;
static {
ArrayList l = new ArrayList();
/* java.io.OutputStream */
l.add(new MethodDecl(ACC_PUBLIC, "write", "([B)V"));
l.add(new MethodDecl(ACC_PUBLIC, "write", "([BII)V"));
l.trimToSize();
outputStreamMethods = l;
/* javax.servlet.ServletOutputStream */
l = new ArrayList();
l.addAll(outputStreamMethods);
/* This method is abstract in java.io.OutputStream -- it's first
* non-abstract definition is in javax.servlet.ServletOutputStream */
l.add(new MethodDecl(ACC_PUBLIC, "write", "(I)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(Z)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(D)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(F)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(I)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(J)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(Ljava/lang/String;)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "()V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(Z)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(D)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(F)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(I)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(J)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(Ljava/lang/String;)V"));
l.trimToSize();
servletOutputStreamMethods = l;
/* java.io.PrintWriter */
l = new ArrayList();
if (VmInfo.version() >= VmInfo.VERSION1_5) {
l.add(new MethodDecl(ACC_PUBLIC, "append",
"(C)Ljava/io/PrintWriter;"));
l.add(new MethodDecl(ACC_PUBLIC, "append",
"(Ljava/lang/CharSequence;)Ljava/io/PrintWriter;"));
l.add(new MethodDecl(ACC_PUBLIC, "append",
"(Ljava/lang/CharSequence;II)Ljava/io/PrintWriter;"));
}
l.add(new MethodDecl(ACC_PUBLIC, "print", "(Z)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "([C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(D)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(F)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(I)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(J)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(Ljava/lang/Object;)V"));
l.add(new MethodDecl(ACC_PUBLIC, "print", "(Ljava/lang/String;)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "()V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(Z)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "([C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(D)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(F)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(I)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(J)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(Ljava/lang/Object;)V"));
l.add(new MethodDecl(ACC_PUBLIC, "println", "(Ljava/lang/String;)V"));
if (VmInfo.version() >= VmInfo.VERSION1_5) {
l.add(new MethodDecl(ACC_PUBLIC, "format",
"(Ljava/util/Locale;Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintWriter;"));
l.add(new MethodDecl(ACC_PUBLIC, "format",
"(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintWriter;"));
l.add(new MethodDecl(ACC_PUBLIC, "printf",
"(Ljava/util/Locale;Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintWriter;"));
l.add(new MethodDecl(ACC_PUBLIC, "printf",
"(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintWriter;"));
}
l.add(new MethodDecl(ACC_PUBLIC, "write", "([C)V"));
l.add(new MethodDecl(ACC_PUBLIC, "write", "([CII)V"));
l.add(new MethodDecl(ACC_PUBLIC, "write", "(I)V"));
l.add(new MethodDecl(ACC_PUBLIC, "write", "(Ljava/lang/String;)V"));
l.add(new MethodDecl(ACC_PUBLIC, "write", "(Ljava/lang/String;II)V"));
l.trimToSize();
printWriterMethods = l;
}
private boolean skip;
private List instrumentedMethods;
public XssContextAdapter(ClassVisitor cv) {
super(cv);
}
public void visit(int version, int access, String name,
String signature, String superName,
String[] interfaces)
{
/* We cannot insert instrumentation into class that have no method
* bodies. We also do not instrument any Enums
*/
skip = (access & (ACC_INTERFACE|ACC_ANNOTATION|ACC_ENUM)) != 0;
cv.visit(version, access, name, signature, superName, interfaces);
}
public MethodVisitor visitMethod(final int access, final String name,
final String desc, String signature,
String[] exceptions)
{
final MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
if (skip) return mv;
MethodDecl md = new MethodDecl(access, name, desc);
if (servletOutputStreamMethods.contains(md) ||
printWriterMethods.contains(md))
{
if (instrumentedMethods == null)
instrumentedMethods = new ArrayList();
instrumentedMethods.add(md);
}
return mv;
}
public List instrumentedMethods() { return instrumentedMethods; }
public boolean instrumented() { return instrumentedMethods != null; }
}