diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 506a3456b44..7e1a84f99f5 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -81,13 +81,13 @@ private module Frameworks { private import semmle.code.java.frameworks.apache.Lang private import semmle.code.java.frameworks.guava.Guava private import semmle.code.java.frameworks.jackson.JacksonSerializability + private import semmle.code.java.frameworks.spring.SpringBeans private import semmle.code.java.security.ResponseSplitting private import semmle.code.java.security.InformationLeak private import semmle.code.java.security.XSS private import semmle.code.java.security.LdapInjection private import semmle.code.java.security.XPath private import semmle.code.java.security.JexlInjection - private import semmle.code.java.frameworks.spring.Spring } private predicate sourceModelCsv(string row) { diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringBeans.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringBeans.qll index 6c3936ee772..ef4b32f5735 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringBeans.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringBeans.qll @@ -10,9 +10,10 @@ module SpringBeans { "org.springframework.beans;PropertyValue;false;PropertyValue;(String,Object);;Argument[1];MapValue of Argument[-1];value", "org.springframework.beans;PropertyValue;false;PropertyValue;(PropertyValue);;Argument[0];Argument[-1];value", "org.springframework.beans;PropertyValue;false;PropertyValue;(PropertyValue,Object);;MapKey of Argument[0];MapKey of Argument[-1];value", + "org.springframework.beans;PropertyValue;false;PropertyValue;(PropertyValue,Object);;Argument[1];MapValue of Argument[-1];value", "org.springframework.beans;PropertyValue;false;getName;;;MapKey of Argument[-1];ReturnValue;value", "org.springframework.beans;PropertyValue;false;getValue;;;MapValue of Argument[-1];ReturnValue;value", - "org.springframework.beans;PropertyValues;true;getPropertyValue;;;MapValue of Argument[-1];ReturnValue;value", + "org.springframework.beans;PropertyValues;true;getPropertyValue;;;MapValue of Element of Argument[-1];ReturnValue;value", "org.springframework.beans;PropertyValues;true;getPropertyValues;;;Element of Argument[-1];ArrayElement of ReturnValue;value", "org.springframework.beans;MutablePropertyValues;true;add;(String,Object);;Argument[0];MapKey of Element of Argument[-1];value", "org.springframework.beans;MutablePropertyValues;true;add;(String,Object);;Argument[0];MapKey of Element of ReturnValue;value", diff --git a/java/ql/test/library-tests/frameworks/spring/beans/Test.java b/java/ql/test/library-tests/frameworks/spring/beans/Test.java index 0075ea88cf9..6b33ba707ff 100644 --- a/java/ql/test/library-tests/frameworks/spring/beans/Test.java +++ b/java/ql/test/library-tests/frameworks/spring/beans/Test.java @@ -1,6 +1,11 @@ package generatedtest; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; +import org.springframework.beans.PropertyValues; public class Test { @@ -12,6 +17,14 @@ public class Test { return null; } + Object getElement(Object container) { + return null; + } + + Object getArrayElement(Object container) { + return null; + } + Object newWithMapKey(Object element) { return null; } @@ -20,6 +33,10 @@ public class Test { return null; } + Object newWithElement(Object element) { + return null; + } + Object source() { return null; } @@ -31,53 +48,250 @@ public class Test { // "org.springframework.beans;PropertyValue;false;;(String,Object);;Argument[0];MapKey of Argument[-1];value", { PropertyValue v = new PropertyValue((String) source(), null); - sink(newWithMapKey(v)); // $hasValueFlow - sink(newWithMapValue(v)); // Safe + sink(getMapKey(v)); // $hasValueFlow + sink(getMapValue(v)); // Safe } // "org.springframework.beans;PropertyValue;false;;(String,Object);;Argument[1];MapValue of Argument[-1];value", { PropertyValue v = new PropertyValue("", source()); - sink(newWithMapKey(v)); // Safe - sink(newWithMapValue(v)); // $hasValueFlow + sink(getMapKey(v)); // Safe + sink(getMapValue(v)); // $hasValueFlow } // "org.springframework.beans;PropertyValue;false;;(PropertyValue);;Argument[0];Argument[-1];value", { PropertyValue v1 = new PropertyValue((String) source(), null); PropertyValue v2 = new PropertyValue(v1); - sink(newWithMapKey(v2)); // $hasValueFlow - sink(newWithMapValue(v2)); // Safe - PropertyValue v3 = new PropertyValue("", source()); + sink(getMapKey(v2)); // $hasValueFlow + sink(getMapValue(v2)); // Safe + + PropertyValue v3 = new PropertyValue("safe", source()); PropertyValue v4 = new PropertyValue(v3); - sink(newWithMapKey(v4)); // Safe - sink(newWithMapValue(v4)); // $hasValueFlow + sink(getMapKey(v4)); // Safe + sink(getMapValue(v4)); // $hasValueFlow } // "org.springframework.beans;PropertyValue;false;;(PropertyValue,Object);;MapKey of Argument[0];MapKey of Argument[-1];value", + { + PropertyValue v1 = new PropertyValue((String) source(), source()); + PropertyValue v2 = new PropertyValue(v1, null); + sink(getMapKey(v2)); // $hasValueFlow + sink(getMapValue(v2)); // Safe + } + // "org.springframework.beans;PropertyValue;false;PropertyValue;(PropertyValue,Object);;Argument[1];MapValue of Argument[-1];value", + { + PropertyValue v1 = new PropertyValue("safe", null); + PropertyValue v2 = new PropertyValue(v1, source()); + sink(getMapKey(v2)); // Safe + sink(getMapValue(v2)); // $hasValueFlow + } // "org.springframework.beans;PropertyValue;false;getName;;;MapKey of Argument[-1];ReturnValue;value", + { + PropertyValue v = new PropertyValue((String) source(), null); + sink(v.getName()); // $hasValueFlow + sink(v.getValue()); // Safe + } // "org.springframework.beans;PropertyValue;false;getValue;;;MapValue of Argument[-1];ReturnValue;value", - // "org.springframework.beans;PropertyValues;true;getPropertyValue;;;MapValue of Argument[-1];ReturnValue;value", + { + PropertyValue v = new PropertyValue("safe", source()); + sink(v.getName()); // Safe + sink(v.getValue()); // $hasValueFlow + } + // "org.springframework.beans;PropertyValues;true;getPropertyValue;;;MapValue of Element of Argument[-1];ReturnValue;value", + { + PropertyValues pv = (PropertyValues) newWithElement(newWithMapValue(source())); + sink(pv.getPropertyValue("safe")); // $hasValueFlow + } // "org.springframework.beans;PropertyValues;true;getPropertyValues;;;Element of Argument[-1];ArrayElement of ReturnValue;value", + { + PropertyValues pv = (PropertyValues) newWithElement(newWithMapValue(source())); + PropertyValue[] vs = pv.getPropertyValues(); + sink(getMapKey(getArrayElement(vs))); // Safe + sink(getMapValue(getArrayElement(vs))); // $hasValueFlow + } // "org.springframework.beans;MutablePropertyValues;true;add;(String,Object);;Argument[0];MapKey of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + pv.add((String) source(), null); + sink(getMapKey(getElement(pv))); // $hasValueFlow + sink(getMapValue(getElement(pv))); // Safe + } // "org.springframework.beans;MutablePropertyValues;true;add;(String,Object);;Argument[0];MapKey of Element of ReturnValue;value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + sink(getMapKey(getElement(pv.add((String) source(), null)))); // $hasValueFlow + sink(getMapValue(getElement(pv.add((String) source(), null)))); // Safe + } // "org.springframework.beans;MutablePropertyValues;true;add;(String,Object);;Argument[1];MapValue of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + pv.add("safe", source()); + sink(getMapKey(getElement(pv))); // Safe + sink(getMapValue(getElement(pv))); // $hasValueFlow + } // "org.springframework.beans;MutablePropertyValues;true;add;(String,Object);;Argument[1];MapValue of Element of ReturnValue;value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + sink(getMapKey(getElement(pv.add("safe", source())))); // Safe + sink(getMapValue(getElement(pv.add("safe", source())))); // $hasValueFlow + } // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(PropertyValue);;Argument[0];Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(PropertyValue);;Argument[0];Element of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(String,Object);;Argument[0];MapKey of Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(String,Object);;Argument[1];MapValue of Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapKey of Argument[0];MapKey of Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapKey of Argument[0];MapKey of Element of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapValue of Argument[0];MapValue of Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapValue of Argument[0];MapValue of Element of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapKey of Element of Argument[0];MapKey of Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapKey of Element of Argument[0];MapKey of Element of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapValue of Element of Argument[0];MapValue of Element of Argument[-1];value", - // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapValue of Element of Argument[0];MapValue of Element of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;get;;;MapValue of Element of Argument[-1];ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;getPropertyValue;;;Element of Argument[-1];ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;getPropertyValueList;;;Element of Argument[-1];Element of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;getPropertyValues;;;Element of Argument[-1];ArrayElement of ReturnValue;value", - // "org.springframework.beans;MutablePropertyValues;true;setPropertyValueAt;;;Argument[0];Element of Argument[-1];value" - // @formatter:on + { + MutablePropertyValues pv1 = new MutablePropertyValues(); + PropertyValue v1 = (PropertyValue) newWithMapKey(source()); + pv1.addPropertyValue(v1); + sink(getMapKey(getElement(pv1))); // $hasValueFlow + sink(getMapValue(getElement(pv1))); // Safe + MutablePropertyValues pv2 = new MutablePropertyValues(); + PropertyValue v2 = (PropertyValue) newWithMapValue(source()); + pv2.addPropertyValue(v2); + sink(getMapKey(getElement(pv2))); // Safe + sink(getMapValue(getElement(pv2))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(PropertyValue);;Argument[0];Element of ReturnValue;value", + { + MutablePropertyValues pv1 = new MutablePropertyValues(); + PropertyValue v1 = (PropertyValue) newWithMapKey(source()); + PropertyValues pv2 = pv1.addPropertyValue(v1); + sink(getMapKey(getElement(pv2))); // $hasValueFlow + sink(getMapValue(getElement(pv2))); // Safe + + MutablePropertyValues pv3 = new MutablePropertyValues(); + PropertyValue v2 = (PropertyValue) newWithMapValue(source()); + PropertyValues pv4 = pv3.addPropertyValue(v2); + sink(getMapKey(getElement(pv4))); // Safe + sink(getMapValue(getElement(pv4))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(String,Object);;Argument[0];MapKey of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + pv.addPropertyValue((String)source(), null); + sink(getMapKey(getElement(pv))); // $hasValueFlow + sink(getMapValue(getElement(pv))); // Safe + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValue;(String,Object);;Argument[1];MapValue of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + pv.addPropertyValue("safe", source()); + sink(getMapKey(getElement(pv))); // Safe + sink(getMapValue(getElement(pv))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapKey of Argument[0];MapKey of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + Map values = (Map) newWithMapKey(source()); + pv.addPropertyValues(values); + sink(getMapKey(getElement(pv))); // $hasValueFlow + sink(getMapValue(getElement(pv))); // Safe + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapKey of Argument[0];MapKey of Element of ReturnValue;value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + Map values = (Map) newWithMapKey(source()); + PropertyValues pv2 = pv.addPropertyValues(values); + sink(getMapKey(getElement(pv2))); // $hasValueFlow + sink(getMapValue(getElement(pv2))); // Safe + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapValue of Argument[0];MapValue of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + Map values = (Map) newWithMapValue(source()); + pv.addPropertyValues(values); + sink(getMapKey(getElement(pv))); // Safe + sink(getMapValue(getElement(pv))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(Map);;MapValue of Argument[0];MapValue of Element of ReturnValue;value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + Map values = (Map) newWithMapValue(source()); + PropertyValues pv2 = pv.addPropertyValues(values); + sink(getMapKey(getElement(pv2))); // Safe + sink(getMapValue(getElement(pv2))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapKey of Element of Argument[0];MapKey of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + PropertyValues values = (PropertyValues) newWithElement(newWithMapKey(source())); + pv.addPropertyValues(values); + sink(getMapKey(getElement(pv))); // $hasValueFlow + sink(getMapValue(getElement(pv))); // Safe + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapKey of Element of Argument[0];MapKey of Element of ReturnValue;value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + PropertyValues values = (PropertyValues) newWithElement(newWithMapKey(source())); + PropertyValues pv2 = pv.addPropertyValues(values); + sink(getMapKey(getElement(pv2))); // $hasValueFlow + sink(getMapValue(getElement(pv2))); // Safe + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapValue of Element of Argument[0];MapValue of Element of Argument[-1];value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + PropertyValues values = (PropertyValues) newWithElement(newWithMapValue(source())); + pv.addPropertyValues(values); + sink(getMapKey(getElement(pv))); // Safe + sink(getMapValue(getElement(pv))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;addPropertyValues;(PropertyValues);;MapValue of Element of Argument[0];MapValue of Element of ReturnValue;value", + { + MutablePropertyValues pv = new MutablePropertyValues(); + PropertyValues values = (PropertyValues) newWithElement(newWithMapValue(source())); + PropertyValues pv2 = pv.addPropertyValues(values); + sink(getMapKey(getElement(pv2))); // Safe + sink(getMapValue(getElement(pv2))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;get;;;MapValue of Element of Argument[-1];ReturnValue;value", + { + MutablePropertyValues pv = (MutablePropertyValues) newWithElement(newWithMapValue(source())); + sink(pv.get("something")); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;getPropertyValue;;;Element of Argument[-1];ReturnValue;value", + { + MutablePropertyValues pv1 = (MutablePropertyValues) newWithElement(newWithMapKey(source())); + sink(pv1.getPropertyValue("something").getName()); // $hasValueFlow + sink(pv1.getPropertyValue("something").getValue()); // Safe + + MutablePropertyValues pv2 = (MutablePropertyValues) newWithElement(newWithMapValue(source())); + sink(pv2.getPropertyValue("something").getName()); // Safe + sink(pv2.getPropertyValue("something").getValue()); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;getPropertyValueList;;;Element of Argument[-1];Element of ReturnValue;value", + { + MutablePropertyValues pv1 = (MutablePropertyValues) newWithElement(newWithMapKey(source())); + List pvl1 = pv1.getPropertyValueList(); + sink(getMapKey(getElement(pvl1))); // $hasValueFlow + sink(getMapValue(getElement(pvl1))); // Safe + + MutablePropertyValues pv2 = (MutablePropertyValues) newWithElement(newWithMapValue(source())); + List pvl2 = pv2.getPropertyValueList(); + sink(getMapKey(getElement(pvl2))); // Safe + sink(getMapValue(getElement(pvl2))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;getPropertyValues;;;Element of Argument[-1];ArrayElement of ReturnValue;value", + { + MutablePropertyValues pv1 = (MutablePropertyValues) newWithElement(newWithMapKey(source())); + PropertyValue[] pvl1 = pv1.getPropertyValues(); + sink(getMapKey(getArrayElement(pvl1))); // $hasValueFlow + sink(getMapValue(getArrayElement(pvl1))); // Safe + + MutablePropertyValues pv2 = (MutablePropertyValues) newWithElement(newWithMapValue(source())); + PropertyValue[] pvl2 = pv2.getPropertyValues(); + sink(getMapKey(getArrayElement(pvl2))); // Safe + sink(getMapValue(getArrayElement(pvl2))); // $hasValueFlow + } + // "org.springframework.beans;MutablePropertyValues;true;setPropertyValueAt;;;Argument[0];Element of Argument[-1];value" + { + MutablePropertyValues pv1 = new MutablePropertyValues(); + PropertyValue v1 = (PropertyValue) newWithMapKey(source()); + pv1.setPropertyValueAt(v1, 0); + sink(getMapKey(getElement(pv1))); // $hasValueFlow + sink(getMapValue(getElement(pv1))); // Safe + + MutablePropertyValues pv2 = new MutablePropertyValues(); + PropertyValue v2 = (PropertyValue) newWithMapValue(source()); + pv2.setPropertyValueAt(v2, 0); + sink(getMapKey(getElement(pv2))); // Safe + sink(getMapValue(getElement(pv2))); // $hasValueFlow + } + // @formatter:on } } diff --git a/java/ql/test/library-tests/frameworks/spring/beans/test.ql b/java/ql/test/library-tests/frameworks/spring/beans/test.ql index 610228239e3..05800dbc1f2 100644 --- a/java/ql/test/library-tests/frameworks/spring/beans/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/beans/test.ql @@ -2,7 +2,6 @@ import java import semmle.code.java.dataflow.ExternalFlow import semmle.code.java.dataflow.TaintTracking import TestUtilities.InlineExpectationsTest -import semmle.code.java.dataflow.internal.FlowSummaryImpl class SummaryModelTest extends SummaryModelCsv { override predicate row(string row) { @@ -11,6 +10,8 @@ class SummaryModelTest extends SummaryModelCsv { //"package;type;overrides;name;signature;ext;inputspec;outputspec;kind", "generatedtest;Test;false;getMapKey;;;MapKey of Argument[0];ReturnValue;value", "generatedtest;Test;false;getMapValue;;;MapValue of Argument[0];ReturnValue;value", + "generatedtest;Test;false;getElement;;;Element of Argument[0];ReturnValue;value", + "generatedtest;Test;false;getArrayElement;;;ArrayElement of Argument[0];ReturnValue;value", "generatedtest;Test;false;newWithElement;;;Argument[0];Element of ReturnValue;value", "generatedtest;Test;false;newWithMapKey;;;Argument[0];MapKey of ReturnValue;value", "generatedtest;Test;false;newWithMapValue;;;Argument[0];MapValue of ReturnValue;value"