You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
11 KiB

/*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package codetoanalyze.java.quandary;
import com.facebook.infer.builtins.InferTaint;
class Interprocedural {
Object f;
static Object sGlobal;
static class Obj {
Object f;
}
public static Object id(Object param) {
return param;
}
/** source tests */
public static Object returnSourceDirect() {
return InferTaint.inferSecretSource();
}
public static Object returnSourceIndirect() {
return returnSourceDirect();
}
public static void returnSourceDirectBad() {
InferTaint.inferSensitiveSink(returnSourceDirect());
}
public static void returnSourceDirectViaVarBad() {
Object source = returnSourceDirect();
InferTaint.inferSensitiveSink(source);
}
public static void returnSourceIndirectBad() {
InferTaint.inferSensitiveSink(returnSourceIndirect());
}
public static Obj returnSourceViaField() {
Obj o = new Obj();
o.f = InferTaint.inferSecretSource();
return o;
}
public static void returnSourceViaFieldBad() {
InferTaint.inferSensitiveSink(returnSourceViaField().f);
}
public static void returnSourceViaParameter1(Obj o) {
o.f = InferTaint.inferSecretSource();
}
public static void returnSourceViaParameter1Bad(Obj o) {
returnSourceViaParameter1(o);
InferTaint.inferSensitiveSink(o.f);
}
public static void returnSourceViaParameter2(Obj o1, Obj o2) {
o2.f = o1.f;
}
public static void returnSourceViaParameter2Bad(Obj o1, Obj o2) {
o1.f = InferTaint.inferSecretSource();
returnSourceViaParameter2(o1, o2);
InferTaint.inferSensitiveSink(o2.f);
}
public static void returnSourceViaParameterOk(Obj o1, Obj o2) {
o1.f = InferTaint.inferSecretSource();
returnSourceViaParameter2(o2, o1);
InferTaint.inferSensitiveSink(o2.f);
}
public static void returnSourceViaGlobal() {
sGlobal = InferTaint.inferSecretSource();
}
public void returnSourceViaGlobalBad() {
returnSourceViaGlobal();
InferTaint.inferSensitiveSink(sGlobal);
}
public void returnSourceViaGlobalOk() {
returnSourceViaGlobal();
sGlobal = null;
InferTaint.inferSensitiveSink(sGlobal);
}
/** sink tests */
public static void callSinkParam1(Object param1, Object param2) {
InferTaint.inferSensitiveSink(param1);
}
public static void callSinkParam1Bad() {
callSinkParam1(InferTaint.inferSecretSource(), null);
}
public static void callSinkParam1Ok() {
callSinkParam1(null, InferTaint.inferSecretSource());
}
public static void callSinkParam2(Object param1, Object param2) {
InferTaint.inferSensitiveSink(param2);
}
public static void callSinkParam2Bad() {
callSinkParam2(null, InferTaint.inferSecretSource());
}
public static void callSinkParam2Ok() {
callSinkParam2(InferTaint.inferSecretSource(), null);
}
public void callSinkOnFieldDirect() {
InferTaint.inferSensitiveSink(this.f);
}
public void callSinkOnFieldDirectBad() {
this.f = InferTaint.inferSecretSource();
callSinkOnFieldDirect();
}
public static void callSinkOnFieldIndirect(Obj param) {
InferTaint.inferSensitiveSink(param.f);
}
public static void callSinkOnFieldIndirectBad() {
Obj obj = new Obj();
obj.f = InferTaint.inferSecretSource();
callSinkOnFieldIndirect(obj);
}
public Object getF() {
return f;
}
void callSinkOnLocal() {
Object local = this.getF();
InferTaint.inferSensitiveSink(local);
}
void callSinkOnLocalBad() {
this.f = InferTaint.inferSecretSource();
callSinkOnLocal();
}
public static void callSinkOnGlobal() {
InferTaint.inferSensitiveSink(sGlobal);
}
public static void callSinkOnGlobalBad() {
sGlobal = InferTaint.inferSecretSource();
callSinkOnGlobal();
}
public static void callSinkOnGlobalOk() {
sGlobal = InferTaint.inferSecretSource();
sGlobal = null;
callSinkOnGlobal();
}
public static void setGlobal(Object o) {
sGlobal = o;
}
public static void setGlobalThenCallSinkBad() {
setGlobal(InferTaint.inferSecretSource());
callSinkOnGlobal();
}
public static Object getGlobal() {
return sGlobal;
}
public static void getGlobalThenCallSink() {
Object local = getGlobal();
InferTaint.inferSensitiveSink(sGlobal);
}
public static void getGlobalThenCallSinkBad() {
sGlobal = InferTaint.inferSecretSource();
getGlobalThenCallSink();
}
// this should report two alarms, not three
public void callSinkNoTripleReportBad() {
Object source = InferTaint.inferSecretSource();
callSinkParam1(source, null);
callSinkParam2(null, source);
}
/** passthrough tests */
public static void singlePassthroughBad() {
Object source = InferTaint.inferSecretSource();
Object launderedSource = id(source);
InferTaint.inferSensitiveSink(launderedSource);
}
public static void doublePassthroughBad() {
Object source = InferTaint.inferSecretSource();
Object launderedSource1 = id(source);
Object launderedSource2 = id(launderedSource1);
InferTaint.inferSensitiveSink(launderedSource2);
}
/** false positives: an ideal analysis would not report these, but we will */
public static Object returnSourceConditional(boolean b) {
if (b) return InferTaint.inferSecretSource();
return null;
}
public static void FP_trackParamsOk() {
InferTaint.inferSensitiveSink(returnSourceConditional(false));
}
public static void reassignInCallee(Obj o) {
o.f = null;
}
public static void FP_reassignInCallee() {
Obj o = new Obj();
o.f = InferTaint.inferSecretSource();
reassignInCallee(o);
InferTaint.inferSensitiveSink(o.f);
}
static Object relevantPassthrough(Object param) {
return param;
}
static Object irrelevantPassthrough(Object param) {
return param;
}
// the following tests should show only "relevantPassthrough" in their traces
public static Object irrelevantPassthroughsIntraprocedural(Object param) {
Object irrelevant = irrelevantPassthrough(param);
Object source = InferTaint.inferSecretSource();
Object relevant = relevantPassthrough(source);
InferTaint.inferSensitiveSink(relevant);
return irrelevantPassthrough(relevant);
}
public static Object returnSourceIrrelevantPassthrough(Object param) {
Object irrelevant = irrelevantPassthrough(param);
Object source = InferTaint.inferSecretSource();
return relevantPassthrough(source);
}
public static Object irrelevantPassthroughsSourceInterprocedural(Object o) {
Object irrelevant = irrelevantPassthrough(o);
Object source = returnSourceIrrelevantPassthrough(irrelevant);
Object relevant = relevantPassthrough(source);
InferTaint.inferSensitiveSink(relevant);
return irrelevantPassthrough(source);
}
public static Object callSinkIrrelevantPassthrough(Object param) {
Object relevant = relevantPassthrough(param);
InferTaint.inferSensitiveSink(relevant);
Object irrelevant = irrelevantPassthrough(param);
return irrelevant;
}
public static Object irrelevantPassthroughsSinkInterprocedural(Object o) {
Object source = InferTaint.inferSecretSource();
Object relevant = relevantPassthrough(source);
callSinkIrrelevantPassthrough(relevant);
return irrelevantPassthrough(relevant);
}
public static Object irrelevantPassthroughsSourceAndSinkInterprocedural(Object o) {
Object irrelevant = irrelevantPassthrough(o);
Object source = returnSourceIrrelevantPassthrough(irrelevant);
Object relevant = relevantPassthrough(source);
callSinkIrrelevantPassthrough(relevant);
return irrelevantPassthrough(relevant);
}
/** false negatives: an ideal analysis would report on these, but we do not */
// this gets modeled as Object[] params in Java. need to treat the array is tainted if its
// contents are tainted in order to get this (t13493230).
public static void callSinkVariadic(Object... params) {
InferTaint.inferSensitiveSink(params);
}
public static void callSinkVariadicBad() {
callSinkVariadic(null, null, InferTaint.inferSecretSource());
}
void diverge() {
for (;;);
}
// we don't propagate divergence in callees to callers
public void FP_divergenceInCallee() {
Object source = InferTaint.inferSecretSource();
diverge();
InferTaint.inferSensitiveSink(source);
}
public static void callSinkThenDiverge(Object param) {
InferTaint.inferSensitiveSink(param);
for (;;);
}
// this fails because the exit block in callSinkThenDiverge is unreachable, so the summary is
// empty.
public void FN_callSinkThenDivergeBad() {
callSinkThenDiverge(InferTaint.inferSecretSource());
}
public void callSinkOnParam(Object o) {
InferTaint.inferSensitiveSink(o);
}
public void callSinkIndirectOnParam(Object o) {
callSinkOnParam(o);
}
Obj propagate(Object param) {
Obj o = new Obj();
o.f = param;
return o;
}
static Obj id2(Obj o) {
return o;
}
void callSinkA(Obj o) {
callSink1(o);
}
void callSinkB(Obj o) {
callSink2(o);
}
void callSinkC(Obj o) {
callSink3(o);
}
void callSinkD(Obj o) {
callSink4(o);
}
void callSink1(Obj o) {
InferTaint.inferSensitiveSink(id(o));
}
void callSink2(Obj o) {
InferTaint.inferSensitiveSink(id2(o).f);
}
void callSink3(Obj o) {
InferTaint.inferSensitiveSink(id(o.f));
}
void callSink4(Obj o) {
InferTaint.inferSensitiveSink(o.f);
}
public void callDeepSinkIndirectBad() {
Object source = InferTaint.inferSecretSource();
callSinkIndirectOnParam(source);
}
public void FN_callDeepSink1Bad() {
Obj source = propagate(InferTaint.inferSecretSource());
callSinkA(source);
}
public void FN_callDeepSink2Bad() {
Obj source = propagate(InferTaint.inferSecretSource());
callSinkB(source);
}
// shallow version of callSinkDeep2Bad
void FN_callShallowSinkBad(Obj o) {
o.f = InferTaint.inferSecretSource();
InferTaint.inferSensitiveSink(id2(o).f);
}
public void callDeepSink3Bad() {
Obj source = propagate(InferTaint.inferSecretSource());
callSinkC(source);
}
public void callDeepSink4Bad() {
Obj source = propagate(InferTaint.inferSecretSource());
callSinkD(source);
}
public static void swapParams(Object o1, Object o2) {
o1 = o2;
}
public static void assignSourceToParam(Object o) {
o = InferTaint.inferSecretSource();
}
public static void swapParamsOk() {
Object notASource = null;
Object source = InferTaint.inferSecretSource();
swapParams(notASource, source);
InferTaint.inferSensitiveSink(notASource);
}
public static void assignSourceToParamOk() {
Object o = null;
assignSourceToParam(o);
InferTaint.inferSensitiveSink(o);
}
}