secure-software-engineering / FlowDroid

FlowDroid Static Data Flow Tracker
GNU Lesser General Public License v2.1
1.05k stars 298 forks source link

A possible bug: a field is wrongly tainted in backward data-flow mode #477

Closed RichardHoOoOo closed 2 years ago

RichardHoOoOo commented 2 years ago

I am trying the backward data-flow mode of FlowDroid and I guess the following example manifest a bug because one field is wrongly tainted.

In the example, I set getTitle and getUrl as sources, loadUrl as a sink

public class MainActivity2 extends Activity {
    WebView wv;
    Button btn;
    private String str1;
    private String str2;
    protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main2);
          wv = (WebView) findViewById(R.id.webView2);
          btn = (Button) findViewById(R.id.button2);
          str1 = wv.getTitle();
          str2 = wv.getUrl();
          btn.setOnClickListener(...);
          wv.loadUrl(str1 + str2);
    }
}

SourcesAndSinks.txt

<android.webkit.WebView: void loadUrl(java.lang.String)> -> _SINK_
<android.webkit.WebView: java.lang.String getTitle()> -> _SOURCE_
<android.webkit.WebView: java.lang.String getUrl()> -> _SOURCE_

I set DataFlowDirection as Backwards, CallgraphAlgorithm as CHA (using SPARK can also trigger the bug), and TaintWrapper as SummaryTaintWrapper

config.setDataFlowDirection(DataFlowDirection.Backwards);
config.setCallgraphAlgorithm(InfoflowConfiguration.CallgraphAlgorithm.CHA);
app.setTaintWrapper(new SummaryTaintWrapper(new LazySummaryProvider("summariesManual")));

The leak can be successfully detected. But I found that one field is wrongly tainted by monitoring the output of a TaintPropagationHandler

public Set<Abstraction> notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set<Abstraction> outgoing, InfoflowManager manager, FlowFunctionType type) {
   synchronized(...) {
     ....
     System.out.println("Stmt: " + stmt);
     for(Abstraction abs: outgoing) System.out.println("Taint: " + abs.getAccessPath());
     ...
   }
   return outgoing;
}

From the output by notifyFlowOut, I can see MainActivity2.btn is tainted, which is obviously wrong.

Stmt: $r4 = r0.<com.example.myapplication.MainActivity2: android.widget.Button btn>
Taint: r0(com.example.myapplication.MainActivity2) <com.example.myapplication.MainActivity2: android.widget.Button btn> * <+length>

Is it a FlowDroid bug (e.g., wv and btn are treated as aliases as they all come from findViewById?) or do I misconfig something?

I attach the Jimple code of onCreate for your references

protected void onCreate(android.os.Bundle)
    {
        android.os.Bundle $r1;
        com.example.myapplication.MainActivity2$1 $r6;
        android.view.View $r2;
        android.widget.Button $r4;
        java.lang.StringBuilder $r7;
        java.lang.String $r5;
        android.webkit.WebView $r3;
        com.example.myapplication.MainActivity2 r0;

        r0 := @this: com.example.myapplication.MainActivity2;

        $r1 := @parameter0: android.os.Bundle;

        specialinvoke r0.<android.app.Activity: void onCreate(android.os.Bundle)>($r1);

        virtualinvoke r0.<com.example.myapplication.MainActivity2: void setContentView(int)>(2131427357);

        $r2 = virtualinvoke r0.<com.example.myapplication.MainActivity2: android.view.View findViewById(int)>(2131231137);

        $r3 = (android.webkit.WebView) $r2;

        r0.<com.example.myapplication.MainActivity2: android.webkit.WebView wv> = $r3;

        $r2 = virtualinvoke r0.<com.example.myapplication.MainActivity2: android.view.View findViewById(int)>(2131230809);

        $r4 = (android.widget.Button) $r2;

        r0.<com.example.myapplication.MainActivity2: android.widget.Button btn> = $r4;

        $r3 = r0.<com.example.myapplication.MainActivity2: android.webkit.WebView wv>;

        $r5 = virtualinvoke $r3.<android.webkit.WebView: java.lang.String getTitle()>();

        r0.<com.example.myapplication.MainActivity2: java.lang.String str1> = $r5;

        $r3 = r0.<com.example.myapplication.MainActivity2: android.webkit.WebView wv>;

        $r5 = virtualinvoke $r3.<android.webkit.WebView: java.lang.String getUrl()>();

        r0.<com.example.myapplication.MainActivity2: java.lang.String str2> = $r5;

        $r4 = r0.<com.example.myapplication.MainActivity2: android.widget.Button btn>;

        $r6 = new com.example.myapplication.MainActivity2$1;

        specialinvoke $r6.<com.example.myapplication.MainActivity2$1: void <init>(com.example.myapplication.MainActivity2)>(r0);

        virtualinvoke $r4.<android.widget.Button: void setOnClickListener(android.view.View$OnClickListener)>($r6);

        $r3 = r0.<com.example.myapplication.MainActivity2: android.webkit.WebView wv>;

        $r7 = new java.lang.StringBuilder;

        specialinvoke $r7.<java.lang.StringBuilder: void <init>()>();

        $r5 = r0.<com.example.myapplication.MainActivity2: java.lang.String str1>;

        virtualinvoke $r7.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($r5);

        $r5 = r0.<com.example.myapplication.MainActivity2: java.lang.String str2>;

        virtualinvoke $r7.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($r5);

        $r5 = virtualinvoke $r7.<java.lang.StringBuilder: java.lang.String toString()>();

        virtualinvoke $r3.<android.webkit.WebView: void loadUrl(java.lang.String)>($r5);

        return;
    }
RichardHoOoOo commented 2 years ago

Hi @StevenArzt I am sorry to disturb you again. Would you be able to give me some hints on this issue if you are available?

Thanks in advance.