diff --git a/java/change-notes/2021-03-18-commons-tostring-builder.md b/java/change-notes/2021-03-18-commons-tostring-builder.md new file mode 100644 index 000000000000..41ccfb95237b --- /dev/null +++ b/java/change-notes/2021-03-18-commons-tostring-builder.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added models for Apache Commons Lang's `ToStringBuilder` class. This may lead to more results from any data-flow query where ToStringBuilder operations fall between the relevant untrusted source and vulnerable sink. diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index 670014e0f8fb..516b3c5588ed 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -637,3 +637,29 @@ private class ApacheObjectUtilsModel extends SummaryModelCsv { ] } } + +private class ApacheToStringBuilderModel extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.commons.lang3.builder;ToStringBuilder;false;toString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.Object[]);;ArrayElement of Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.String,java.lang.Object[]);;ArrayElement of Argument[1];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.String,boolean);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.String,java.lang.Object);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.String,java.lang.Object[],boolean);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;(java.lang.String,java.lang.Object[],boolean);;ArrayElement of Argument[1];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;build;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;getStringBuffer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;appendToString;;;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.builder;ToStringBuilder;false;appendSuper;;;Argument[0];Argument[-1];taint", + // The following are value-preserving steps for fluent methods: + "org.apache.commons.lang3.builder;ToStringBuilder;false;append;;;Argument[-1];ReturnValue;value", + "org.apache.commons.lang3.builder;ToStringBuilder;false;appendAsObjectToString;;;Argument[-1];ReturnValue;value", + "org.apache.commons.lang3.builder;ToStringBuilder;false;appendSuper;;;Argument[-1];ReturnValue;value", + "org.apache.commons.lang3.builder;ToStringBuilder;false;appendToString;;;Argument[-1];ReturnValue;value" + ] + } +} diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/ToStringBuilderTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/ToStringBuilderTest.java new file mode 100644 index 000000000000..ed2e4400dd7c --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/ToStringBuilderTest.java @@ -0,0 +1,37 @@ +import org.apache.commons.lang3.builder.ToStringBuilder; + +class ToStringBuilderTest { + String taint() { return "tainted"; } + + void sink(Object o) {} + + void test() throws Exception { + + ToStringBuilder sb1 = new ToStringBuilder(null); sb1.append((Object)taint()); sink(sb1.toString()); // $hasTaintFlow + ToStringBuilder sb2 = new ToStringBuilder(null); sb2.append(new Object[] { taint() }); sink(sb2.toString()); // $hasTaintFlow + ToStringBuilder sb3 = new ToStringBuilder(null); sb3.append(taint(), true); sink(sb3.toString()); // $hasTaintFlow + ToStringBuilder sb4 = new ToStringBuilder(null); sb4.append("fieldname", taint()); sink(sb4.toString()); // $hasTaintFlow + ToStringBuilder sb5 = new ToStringBuilder(null); sb5.append("fieldname", new Object[] { taint() }); sink(sb5.toString()); // $hasTaintFlow + ToStringBuilder sb6 = new ToStringBuilder(null); sb6.append("fieldname", new Object[] { taint() }, true); sink(sb6.toString()); // $hasTaintFlow + // GOOD: this appends an Object using the Object.toString style, which does not expose fields or String content. + ToStringBuilder sb7 = new ToStringBuilder(null); sb7.appendAsObjectToString(taint()); sink(sb7.toString()); + ToStringBuilder sb8 = new ToStringBuilder(null); sb8.appendSuper(taint()); sink(sb8.toString()); // $hasTaintFlow + ToStringBuilder sb9 = new ToStringBuilder(null); sb9.appendToString(taint()); sink(sb9.toString()); // $hasTaintFlow + ToStringBuilder sb10 = new ToStringBuilder(null); sb10.append((Object)taint()); sink(sb10.build()); // $hasTaintFlow + ToStringBuilder sb11 = new ToStringBuilder(null); sb11.append((Object)taint()); sink(sb11.getStringBuffer().toString()); // $hasTaintFlow + + // Test fluent methods: + ToStringBuilder fluentTest = new ToStringBuilder(null); + sink(fluentTest.append("Harmless").append(taint()).append("Also harmless").toString()); // $hasTaintFlow + + ToStringBuilder fluentBackflowTest = new ToStringBuilder(null); + fluentBackflowTest.append("Harmless").append(taint()).append("Also harmless"); + sink(fluentBackflowTest.toString()); // $hasTaintFlow + + // Test the case where the fluent method contributing taint is at the end of a statement: + ToStringBuilder fluentBackflowTest2 = new ToStringBuilder(null); + fluentBackflowTest2.append("Harmless").append(taint()); + sink(fluentBackflowTest2.toString()); // $hasTaintFlow + + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/builder/ToStringBuilder.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/builder/ToStringBuilder.java new file mode 100644 index 000000000000..886d59637f03 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/builder/ToStringBuilder.java @@ -0,0 +1,275 @@ +/* + * 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 + * + * 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 org.apache.commons.lang3.builder; + + +public class ToStringBuilder implements Builder { + public static ToStringStyle getDefaultStyle() { + return null; + } + + public static void setDefaultStyle(final ToStringStyle style) { + } + + public static String reflectionToString(final Object object) { + return null; + } + + public static String reflectionToString(final Object object, final ToStringStyle style) { + return null; + } + + public static String reflectionToString(final Object object, final ToStringStyle style, final boolean outputTransients) { + return null; + } + + public static String reflectionToString( + final T object, + final ToStringStyle style, + final boolean outputTransients, + final Class reflectUpToClass) { + return null; + } + + public ToStringBuilder(final Object object) { + } + + public ToStringBuilder(final Object object, final ToStringStyle style) { + } + + public ToStringBuilder(final Object object, ToStringStyle style, StringBuffer buffer) { + } + + public ToStringBuilder append(final boolean value) { + return null; + } + + public ToStringBuilder append(final boolean[] array) { + return null; + } + + public ToStringBuilder append(final byte value) { + return null; + } + + public ToStringBuilder append(final byte[] array) { + return null; + } + + public ToStringBuilder append(final char value) { + return null; + } + + public ToStringBuilder append(final char[] array) { + return null; + } + + public ToStringBuilder append(final double value) { + return null; + } + + public ToStringBuilder append(final double[] array) { + return null; + } + + public ToStringBuilder append(final float value) { + return null; + } + + public ToStringBuilder append(final float[] array) { + return null; + } + + public ToStringBuilder append(final int value) { + return null; + } + + public ToStringBuilder append(final int[] array) { + return null; + } + + public ToStringBuilder append(final long value) { + return null; + } + + public ToStringBuilder append(final long[] array) { + return null; + } + + public ToStringBuilder append(final Object obj) { + return null; + } + + public ToStringBuilder append(final Object[] array) { + return null; + } + + public ToStringBuilder append(final short value) { + return null; + } + + public ToStringBuilder append(final short[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final boolean value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final boolean[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final boolean[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final byte value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final byte[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final byte[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final char value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final char[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final char[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final double value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final double[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final double[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final float value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final float[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final float[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final int value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final int[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final int[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final long value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final long[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final long[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final Object obj) { + return null; + } + + public ToStringBuilder append(final String fieldName, final Object obj, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final Object[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final Object[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder append(final String fieldName, final short value) { + return null; + } + + public ToStringBuilder append(final String fieldName, final short[] array) { + return null; + } + + public ToStringBuilder append(final String fieldName, final short[] array, final boolean fullDetail) { + return null; + } + + public ToStringBuilder appendAsObjectToString(final Object srcObject) { + return null; + } + + public ToStringBuilder appendSuper(final String superToString) { + return null; + } + + public ToStringBuilder appendToString(final String toString) { + return null; + } + + public Object getObject() { + return null; + } + + public StringBuffer getStringBuffer() { + return null; + } + + public ToStringStyle getStyle() { + return null; + } + + @Override + public String toString() { + return null; + } + + @Override + public String build() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/builder/ToStringStyle.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/builder/ToStringStyle.java new file mode 100644 index 000000000000..eef4db088044 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/builder/ToStringStyle.java @@ -0,0 +1,102 @@ +/* + * 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 + * + * 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 org.apache.commons.lang3.builder; + +import java.io.Serializable; + +public abstract class ToStringStyle implements Serializable { + public static final ToStringStyle DEFAULT_STYLE = null; + + public static final ToStringStyle MULTI_LINE_STYLE = null; + + public static final ToStringStyle NO_FIELD_NAMES_STYLE = null; + + public static final ToStringStyle SHORT_PREFIX_STYLE = null; + + public static final ToStringStyle SIMPLE_STYLE = null; + + public static final ToStringStyle NO_CLASS_NAME_STYLE = null; + + public static final ToStringStyle JSON_STYLE = null; + + public void appendSuper(final StringBuffer buffer, final String superToString) { + } + + public void appendToString(final StringBuffer buffer, final String toString) { + } + + public void appendStart(final StringBuffer buffer, final Object object) { + } + + public void appendEnd(final StringBuffer buffer, final Object object) { + } + + public void append(final StringBuffer buffer, final String fieldName, final Object value, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final long value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final int value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final short value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final byte value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final char value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final double value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final float value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final boolean value) { + } + + public void append(final StringBuffer buffer, final String fieldName, final Object[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final long[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final short[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final byte[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final char[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final double[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final float[] array, final Boolean fullDetail) { + } + + public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, final Boolean fullDetail) { + } + +}