Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/org/apache/bcel/util/AttributeHTML.java
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ void writeAttribute(final Attribute attribute, final String anchor, final int me
signature = Utility.signatureToString(signature, false);
final int start = var.getStartPC();
final int end = start + var.getLength();
printWriter.println("<LI>" + Class2HTML.referenceType(signature) + "&nbsp;<B>" + var.getName() + "</B> in slot %" + var.getIndex()
printWriter.println("<LI>" + Class2HTML.referenceType(signature) + "&nbsp;<B>" + Class2HTML.toHTML(var.getName()) + "</B> in slot %" + var.getIndex()
+ "<BR>Valid from lines <A HREF=\"" + className + "_code.html#code" + methodNumber + "@" + start + "\" TARGET=Code>" + start
+ "</A> to <A HREF=\"" + className + "_code.html#code" + methodNumber + "@" + end + "\" TARGET=Code>" + end + "</A></LI>");
});
Expand All @@ -173,7 +173,7 @@ void writeAttribute(final Attribute attribute, final String anchor, final int me
final String access;
index = clazz.getInnerNameIndex();
if (index > 0) {
name = constantPool.getConstantUtf8(index).getBytes();
name = Class2HTML.toHTML(constantPool.getConstantUtf8(index).getBytes());
} else {
name = "&lt;anonymous&gt;";
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/apache/bcel/util/Class2HTML.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ static String referenceClass(final int index) {
String str = constantPool.getConstantString(index, Const.CONSTANT_Class);
str = Utility.compactClassName(str);
str = Utility.compactClassName(str, classPackage + ".", true);
return "<A HREF=\"" + className + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + str + "</A>";
return "<A HREF=\"" + className + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + toHTML(str) + "</A>";
}

static String referenceType(final String type) {
Expand All @@ -150,7 +150,7 @@ static String referenceType(final String type) {
if (basicTypes.contains(baseType)) {
return "<FONT COLOR=\"#00FF00\">" + type + "</FONT>";
}
return "<A HREF=\"" + baseType + ".html\" TARGET=_top>" + shortType + "</A>";
return "<A HREF=\"" + baseType + ".html\" TARGET=_top>" + toHTML(shortType) + "</A>";
}

static String toHTML(final String str) {
Expand Down Expand Up @@ -221,7 +221,7 @@ private void writeMainHTML(final AttributeHTML attributeHtml, final Charset char
try (PrintWriter file = new PrintWriter(dir + className + ".html", charset.name())) {
// @formatter:off
file.println("<HTML>\n"
+ "<HEAD><TITLE>Documentation for " + className + "</TITLE></HEAD>\n"
+ "<HEAD><TITLE>Documentation for " + toHTML(className) + "</TITLE></HEAD>\n"
+ "<FRAMESET BORDER=1 cols=\"30%,*\">\n"
+ "<FRAMESET BORDER=1 rows=\"80%,*\">\n"
+ "<FRAME NAME=\"ConstantPool\" SRC=\"" + className + "_cp.html" + "\"\n"
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/apache/bcel/util/CodeHTML.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,10 @@ private String codeToHTML(final ByteSequence bytes, final int methodNumber) thro
index = c1.getNameAndTypeIndex();
final String fieldName = constantPool.constantToString(index, Const.CONSTANT_NameAndType);
if (name.equals(className)) { // Local field
buf.append("<A HREF=\"").append(className).append("_methods.html#field").append(fieldName).append("\" TARGET=Methods>").append(fieldName)
.append("</A>\n");
buf.append("<A HREF=\"").append(className).append("_methods.html#field").append(fieldName).append("\" TARGET=Methods>")
.append(Class2HTML.toHTML(fieldName)).append("</A>\n");
} else {
buf.append(constantHtml.referenceConstant(classIndex)).append(".").append(fieldName);
buf.append(constantHtml.referenceConstant(classIndex)).append(".").append(Class2HTML.toHTML(fieldName));
}
break;
/*
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/org/apache/bcel/util/ConstantHTML.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ private void writeConstant(final int index) {
final String methodClass = constantPool.constantToString(classIndex, Const.CONSTANT_Class);
String shortMethodClass = Utility.compactClassName(methodClass); // I.e., remove java.lang.
shortMethodClass = Utility.compactClassName(shortMethodClass, classPackage + ".", true); // Remove class package prefix
shortMethodClass = Class2HTML.toHTML(shortMethodClass);
// Get method signature
final ConstantNameAndType c2 = constantPool.getConstant(nameIndex, Const.CONSTANT_NameAndType, ConstantNameAndType.class);
final String signature = constantPool.constantToString(c2.getSignatureIndex(), Const.CONSTANT_Utf8);
Expand Down Expand Up @@ -159,14 +160,16 @@ private void writeConstant(final int index) {
final String fieldClass = constantPool.constantToString(classIndex, Const.CONSTANT_Class);
String shortFieldClass = Utility.compactClassName(fieldClass); // I.e., remove java.lang.
shortFieldClass = Utility.compactClassName(shortFieldClass, classPackage + ".", true); // Remove class package prefix
shortFieldClass = Class2HTML.toHTML(shortFieldClass);
final String fieldName = constantPool.constantToString(nameIndex, Const.CONSTANT_NameAndType);
final String htmlFieldName = Class2HTML.toHTML(fieldName);
if (fieldClass.equals(className)) {
ref = "<A HREF=\"" + fieldClass + "_methods.html#field" + fieldName + "\" TARGET=Methods>" + fieldName + "</A>";
ref = "<A HREF=\"" + fieldClass + "_methods.html#field" + fieldName + "\" TARGET=Methods>" + htmlFieldName + "</A>";
} else {
ref = "<A HREF=\"" + fieldClass + ".html\" TARGET=_top>" + shortFieldClass + "</A>." + fieldName + "\n";
ref = "<A HREF=\"" + fieldClass + ".html\" TARGET=_top>" + shortFieldClass + "</A>." + htmlFieldName + "\n";
}
constantRef[index] = "<A HREF=\"" + className + "_cp.html#cp" + classIndex + "\" TARGET=Constants>" + shortFieldClass + "</A>.<A HREF=\""
+ className + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + fieldName + "</A>";
+ className + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + htmlFieldName + "</A>";
printWriter.println("<P><TT>" + ref + "</TT><BR>\n" + "<UL>" + "<LI><A HREF=\"#cp" + classIndex + "\">Class(" + classIndex + ")</A><BR>\n"
+ "<LI><A HREF=\"#cp" + nameIndex + "\">NameAndType(" + nameIndex + ")</A></UL>");
break;
Expand All @@ -176,6 +179,7 @@ private void writeConstant(final int index) {
final String className2 = constantPool.constantToString(index, tag); // / -> .
String shortClassName = Utility.compactClassName(className2); // I.e., remove java.lang.
shortClassName = Utility.compactClassName(shortClassName, classPackage + ".", true); // Remove class package prefix
shortClassName = Class2HTML.toHTML(shortClassName);
ref = "<A HREF=\"" + className2 + ".html\" TARGET=_top>" + shortClassName + "</A>";
constantRef[index] = "<A HREF=\"" + className + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + shortClassName + "</A>";
printWriter.println("<P><TT>" + ref + "</TT><UL>" + "<LI><A HREF=\"#cp" + nameIndex + "\">Name index(" + nameIndex + ")</A></UL>\n");
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/apache/bcel/util/MethodHTML.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private void writeField(final Field field) {
final Attribute[] attributes;
access = Utility.replace(access, " ", "&nbsp;");
printWriter.print("<TR><TD><FONT COLOR=\"#FF0000\">" + access + "</FONT></TD>\n<TD>" + Class2HTML.referenceType(type) + "</TD><TD><A NAME=\"field"
+ name + "\">" + name + "</A></TD>");
+ name + "\">" + Class2HTML.toHTML(name) + "</A></TD>");
attributes = field.getAttributes();
// Write them to the Attributes.html file with anchor "<name>[<i>]"
for (int i = 0; i < attributes.length; i++) {
Expand Down
59 changes: 59 additions & 0 deletions src/test/java/org/apache/bcel/util/Class2HTMLXSSTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* https://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 org.apache.bcel.util;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import org.apache.bcel.Const;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.Type;
import org.junit.jupiter.api.Test;

class Class2HTMLXSSTest {

/**
* A field name in the constant pool is attacker controlled and may contain HTML metacharacters; the generated
* documentation must escape it in text context rather than emit it raw.
*/
@Test
void testFieldNameIsEscaped() throws Exception {
final ClassGen cg = new ClassGen("Evil", "java.lang.Object", "Evil.java", Const.ACC_PUBLIC, null);
cg.addField(new FieldGen(Const.ACC_PUBLIC, Type.INT, "x<script>alert(1)</script>", cg.getConstantPool()).getField());
final JavaClass jc = cg.getJavaClass();

final File outputDir = new File("target/test-output/html-xss");
if (!outputDir.mkdirs()) {
assertTrue(outputDir.isDirectory());
}
new Class2HTML(jc, outputDir.getAbsolutePath() + File.separator);

final String methods = new String(Files.readAllBytes(new File(outputDir, "Evil_methods.html").toPath()), StandardCharsets.UTF_8);
// The field name rendered as link text must be escaped, not emitted as a live tag.
assertFalse(methods.contains("\">x<script>"), "field name was emitted unescaped in text context");
assertTrue(methods.contains("&lt;script&gt;"), "expected the field name to be HTML-escaped");
}
}
Loading