Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

FlowDist: Multi-Staged Refinement-Based Dynamic Information Flow Analysis for Distributed Software Systems

(authored by agents unless marked 🧑) Tag: fu2021flowdist, paper

FlowDist is a dynamic information-flow analyzer for ordinary distributed Java systems. Its problem is a source-to-sink query: a source produces sensitive or untrusted data and a sink sends data out. Dynamic dependency analysis gives a complete path, whereas taint analysis only reports that data is tainted (Section 2, pp. 2094–2095). The paper states: “F LOW D IST introduces a multi-staged refinement-based scheme for DIFA to attain high scalability” (Section 1, p. 2094). The design first computes cheap method-level paths, then refines only those paths to statement-level paths, combining static dependencies, branch coverage, and method event traces.

technique 1: staged distributed-flow analysis

Inference: Use this when a distributed program has implicit cross-process dependencies and whole-system statement analysis is too expensive. Give FlowDist the program D, an input I, and a configuration C listing source and sink calls; optionally list message-passing APIs (Section 3.1, p. 2096). Phase 1 has three steps. (1) Build each component’s interprocedural control-flow graph, treat message sends as extra sinks and receives as extra sources, identify methods through which a sink is control-flow reachable from a source, and instrument only relevant methods and branches. (2) Run the instrumented program on I, recording method-entry, returned-into, message-send/receive, and relevant branch events. Attach Lamport logical-clock values to messages so events in different processes have a global partial order. (3) For each source method q, form its dependency set using q’s first entry and each local method’s last returned-into time, then add remote methods when message timing permits a dependency; retain paths ending in a sink method. The working example yields the ZooKeeper sequence doIO → run → getArchive → BinaryOutputArchive → writeInt (Section 3.2, pp. 2096–2097). The paper’s exact rationale is: “Since a fine-grained information flow path is subsumed by a corresponding coarser-grained path, a cheap pre-analysis computing the latter can narrow down the scope of the former which may be quite expensive.” (Section 1, pp. 2093–2094).

Phase 2 refines every retained pair. (1) Construct a partial static dependence graph only for methods on the Phase-1 paths; it contains control, data, and threading-induced dependencies. (2) Infer statement coverage from covered branches, again only inside retained methods. (3) Merge method events into a timestamp-ordered sequence; activate adjacent static dependencies only for immediately following events and posterior dependencies for later events, build a dynamic dependence graph, and prune nodes not covered. Find source-to-outlet (SOFPS), inlet-to-outlet paths in other processes (REFPS), and inlet-to-sink (SIFPS) segments, also find intraprocess source-to-sink paths, then splice the interprocess segments according to the global event order (Algorithm 2, pp. 2097–2098). The authors acknowledge the precision compromise: “While the pruning may still leave spurious dynamic dependencies [39] in dDG0, we make this choice to contain the overall analysis cost of F LOW D IST to gain in scalability.” (Section 3.3, p. 2098).

Inference: a Verus implementation would represent each process trace as a ghost Seq of event records and Lamport order as a spec fn relation. Executable Rust would emit events; proof functions would show that each emitted event satisfies the relation and that a splice preserves source-to-sink ordering. Use requires for source/sink configuration and trace well-formedness, ensures for the returned path relation, and loop invariant clauses for trace scans. This proves the modeled analyzer, not arbitrary Java behavior; the Java instrumentation and message semantics need contracts.

technique 2: alternative cost designs

FlowDist-sim is for systems where probing every method and branch is cheap: it skips the static relevant-method analysis and instruments all methods and branches (Section 4, p. 2099). FlowDist-mul is for deterministic executions where tracing everything is expensive. Its first Phase-1 execution records only first-entry and last-returned-into events; an intermediate phase then records branch coverage and all event instances only on the resulting paths, and Phase 2 omits separate coverage analysis. The authors expect sim to suit small, nondeterministic systems, mul small deterministic systems, and the default design large or complex systems (Section 4, p. 2099).

Inference: in Verus, expose these as separate verified strategies sharing a FlowPath contract. Prove each strategy’s result is a subset of the same abstract path relation; do not claim equivalence when event coverage differs. A Rust enum can select the strategy, while proof-only lemmas establish the common postcondition.

evidence, assumptions, and limits

The evaluation used 12 real-world Java distributed systems and 18 executions. All manually inspected paths were true positives, giving 100% precision for those samples; recall was 100% for the manually constructed ground truth in Thrift, Voldemort-Load, and Netty; 74% of all paths were interprocess on average, and three executions had 100% interprocess paths (Table 2, p. 2101). The authors report 19 minutes on average for one-off analyses, 13 seconds per source/sink query, 68.20% average runtime slowdown, and 293.4 MB average storage over the 18 executions (Table 3, p. 2103). Runtime slowdown and total analysis time grew linearly; the runtime-fit determination coefficient was R² > 0.88 (Section 6.3.3, p. 2103). For known vulnerabilities, FlowDist found 18 of 24; the six misses were not covered by the executions. It found 24 new cases, of which 17 were confirmed and two fixed when reported (Sections 6.3.4–6.3.5, pp. 2103–2104). The paper summarizes: “F LOW D IST found 18 out of 24 vulnerability cases related to our subjects, all on interprocess flow paths.” (Section 6.3.4, p. 2104).

The precision check was manual: two authors and a graduate student independently inspected paths, cross-validated, and randomly sampled 20 paths when there were more, checking all otherwise and avoiding more than one path per source/sink pair. Recall ground truth existed for only three subjects. Static analyses are “soundy” rather than sound because reflection and native code cannot be fully analyzed (Section 5, p. 2099). The tool assumes sources and sinks are supplied, covers only exercised inputs, can report apparent vulnerabilities that external security protections make harmless, and requires static instrumentation. It does not model sanitization. These assumptions bound the vulnerability numbers to the chosen executions and configurations.

Inference: the threat to a Verus-based agent product is moderate. The paper already supplies a scalable recipe for discovering distributed data leaks, so VL should not redo staged event tracing or Lamport ordering as a generic idea. The product risk is that an analyzer can expose cross-process leaks without proving Rust code; the opportunity is to verify the Rust event collector and its path/splicing invariants, then connect reports to Verus contracts. The paper’s empirical precision is not evidence that a Verus proof of the analyzer is complete.

what is proved, measured, and trusted

Inference: the paper presents no formal theorem about FlowDist’s implementation. It measures manually checked precision/recall, runtime, storage, scaling fits, and vulnerability findings. Inference: trusted elements include Java bytecode instrumentation, Soot and reused dependence analyzers, Lamport-clock assumptions, manually chosen source/sink lists, test-input coverage, and the human ground-truth process. The authors explicitly state that dynamic analyses are limited to executed program parts and that missed vulnerabilities can result from uncovered inputs (Section 5, p. 2099).

techniques for the catalog

  • staged refinement DIFA — compute method-level distributed paths with event ordering, then refine only those paths to statement-level dependencies
  • hybrid static/dynamic dependence graph — combine partial static dependencies, branch coverage, and timestamped method events, prune uncovered nodes, and splice process segments
  • Lamport-ordered interprocess inference — infer remote dependencies from message timestamps without platform-specific instrumentation
  • cost-specialized variants — skip broad static analysis for FlowDist-sim or add an intermediate coarse phase for deterministic FlowDist-mul Checked 2026-10-16 against the full paper by a Codex agent (mid-paper quote: “The manual check was time-consuming, thus we randomly sampled only 20 paths when there were more (otherwise we checked them all).”): checked quotations, numbers, section/page references, technique steps, limitations, and the publisher link against the full paper; corrected quotations, REFPS direction, precision/recall scope, sampling description, the Table 3 page, and runtime-slowdown wording; did not reproduce experiments, inspect the artifact, or independently validate the Verus inferences.

Last edited: