[quandary] reporting on getenv -> exec flows

Differential Revision: D4017588

fbshipit-source-id: ae099f8
master
Sam Blackshear 8 years ago committed by Facebook Github Bot
parent 6aee686cb2
commit 072fe0994f

@ -17,12 +17,16 @@ module CppSource = struct
module SourceKind = struct module SourceKind = struct
type t = type t =
| Footprint of AccessPath.t (** source that was read from the environment. *) | Footprint of AccessPath.t (** source that was read from the environment. *)
| EnvironmentVariable (** source that was read from an environment variable *)
| Other (** for testing or uncategorized sources *) | Other (** for testing or uncategorized sources *)
let compare sk1 sk2 = match sk1, sk2 with let compare sk1 sk2 = match sk1, sk2 with
| Footprint ap1, Footprint ap2 -> AccessPath.compare ap1 ap2 | Footprint ap1, Footprint ap2 -> AccessPath.compare ap1 ap2
| Footprint _, _ -> (-1) | Footprint _, _ -> (-1)
| _, Footprint _ -> 1 | _, Footprint _ -> 1
| EnvironmentVariable, EnvironmentVariable -> 0
| EnvironmentVariable, _ -> (-1)
| _, EnvironmentVariable -> 1
| Other, Other -> 0 | Other, Other -> 0
end end
@ -65,6 +69,7 @@ module CppSource = struct
| (C _) as pname -> | (C _) as pname ->
begin begin
match Procname.to_string pname with match Procname.to_string pname with
| "getenv" -> Some (make EnvironmentVariable site)
| "__infer_taint_source" -> Some (make Other site) | "__infer_taint_source" -> Some (make Other site)
| _ -> None | _ -> None
end end
@ -82,6 +87,7 @@ module CppSource = struct
let pp_kind fmt (kind : kind) = match kind with let pp_kind fmt (kind : kind) = match kind with
| Footprint ap -> F.fprintf fmt "Footprint[%a]" AccessPath.pp ap | Footprint ap -> F.fprintf fmt "Footprint[%a]" AccessPath.pp ap
| EnvironmentVariable -> F.fprintf fmt "EnvironmentVariable"
| Other -> F.fprintf fmt "Other" | Other -> F.fprintf fmt "Other"
let pp fmt s = let pp fmt s =
@ -98,9 +104,13 @@ module CppSink = struct
module SinkKind = struct module SinkKind = struct
type t = type t =
| ShellExec (** shell exec function *)
| Other (** for testing or uncategorized sinks *) | Other (** for testing or uncategorized sinks *)
let compare snk1 snk2 = match snk1, snk2 with let compare snk1 snk2 = match snk1, snk2 with
| ShellExec, ShellExec -> 0
| ShellExec, _ -> (-1)
| _, ShellExec -> 1
| Other, Other -> 0 | Other, Other -> 0
end end
@ -121,7 +131,11 @@ module CppSink = struct
let make kind site = let make kind site =
{ kind; site; } { kind; site; }
let get site _ = let get site actuals =
let taint_all actuals sink ~report_reachable =
IList.mapi
(fun actual_num _ -> Sink.make_sink_param sink actual_num ~report_reachable)
actuals in
match CallSite.pname site with match CallSite.pname site with
| (Procname.ObjC_Cpp cpp_pname) as pname -> | (Procname.ObjC_Cpp cpp_pname) as pname ->
begin begin
@ -133,6 +147,8 @@ module CppSink = struct
| (C _ as pname) -> | (C _ as pname) ->
begin begin
match Procname.to_string pname with match Procname.to_string pname with
| "execl" | "execlp" | "execle" | "execv" | "execvp" ->
taint_all actuals (make ShellExec site) ~report_reachable:false
| "__infer_taint_sink" -> | "__infer_taint_sink" ->
[Sink.make_sink_param (make Other site) 0 ~report_reachable:false] [Sink.make_sink_param (make Other site) 0 ~report_reachable:false]
| _ -> | _ ->
@ -154,6 +170,7 @@ module CppSink = struct
compare t1 t2 = 0 compare t1 t2 = 0
let pp_kind fmt (kind : kind) = match kind with let pp_kind fmt (kind : kind) = match kind with
| ShellExec -> F.fprintf fmt "ShellExec"
| Other -> F.fprintf fmt "Other" | Other -> F.fprintf fmt "Other"
let pp fmt s = let pp fmt s =
@ -175,6 +192,8 @@ include
let open Source in let open Source in
let open Sink in let open Sink in
match Source.kind source, Sink.kind sink with match Source.kind source, Sink.kind sink with
| SourceKind.EnvironmentVariable, SinkKind.ShellExec ->
true
| SourceKind.Other, SinkKind.Other -> | SourceKind.Other, SinkKind.Other ->
true true
| _ -> | _ ->

@ -14,6 +14,7 @@ INFERPRINT_OPTIONS = --issues-txt
FILES = \ FILES = \
basics.cpp \ basics.cpp \
execs.cpp \
compile: compile:
clang $(OPTIONS) $(FILES) clang $(OPTIONS) $(FILES)

@ -0,0 +1,63 @@
/*
* 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.
*/
#include <cstdlib>
#include <unistd.h>
extern int rand();
namespace execs {
int callAllSinks(const char* stringSource) {
switch (rand()) {
case 1:
return execl(NULL, stringSource);
case 2:
return execl(stringSource, NULL);
case 3:
// just one test for varargs; assume we get it right in the other cases
return execl(NULL, NULL, stringSource);
case 4:
return execlp(NULL, stringSource);
case 5:
return execlp(stringSource, NULL);
case 6:
return execle(NULL, stringSource);
case 7:
return execle(stringSource, NULL);
case 8:
return execv(stringSource, NULL);
case 9:
return execvp(stringSource, NULL);
}
return 0;
}
void callExecBad() {
const char* source = std::getenv("ENV_VAR");
callAllSinks(source);
}
// need to treat an array as tainted when its contents are tainted to get these
// two
void FN_envVarFlowsToEnvironment() {
char* execEnv[1] = {std::getenv("ENV_VAR")};
execv("something.s", execEnv);
execvp("something.sh", execEnv);
}
extern char* getenv(const char* var);
void execConstantStringOk() { callAllSinks("something.sh"); }
void customGetEnvOk() {
const char* source = execs::getenv("ENV_VAR");
callAllSinks(source);
}
}

@ -2,3 +2,12 @@ basics.cpp:28: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at
basics.cpp:33: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at [line 20]) -> Other(__infer_taint_sink at [line 33]) via { basics::returnSource at [line 32] } basics.cpp:33: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at [line 20]) -> Other(__infer_taint_sink at [line 33]) via { basics::returnSource at [line 32] }
basics.cpp:38: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at [line 37]) -> Other(__infer_taint_sink at [line 22]) via { basics::callSink at [line 38] } basics.cpp:38: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at [line 37]) -> Other(__infer_taint_sink at [line 22]) via { basics::callSink at [line 38] }
basics.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at [line 42]) -> Other(__infer_taint_sink at [line 22]) via { basics::callSink at [line 44], basics::id at [line 43] } basics.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: Other(__infer_taint_source at [line 42]) -> Other(__infer_taint_sink at [line 22]) via { basics::callSink at [line 44], basics::id at [line 43] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execl at [line 20]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execl at [line 22]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execl at [line 25]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execle at [line 31]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execle at [line 33]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execlp at [line 27]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execlp at [line 29]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execv at [line 35]) via { execs::callAllSinks at [line 44] }
execs.cpp:44: ERROR: QUANDARY_TAINT_ERROR Error: EnvironmentVariable(getenv at [line 43]) -> ShellExec(execvp at [line 37]) via { execs::callAllSinks at [line 44] }

Loading…
Cancel
Save