source/TaintV2.cpp (176 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <mariana-trench/JsonValidation.h>
#include <mariana-trench/TaintV2.h>
namespace marianatrench {
TaintV2::TaintV2(std::initializer_list<Frame> frames) {
for (const auto& frame : frames) {
add(frame);
}
}
void TaintV2::add(const Frame& frame) {
set_.add(CalleeFrames{frame});
}
bool TaintV2::leq(const TaintV2& other) const {
return set_.leq(other.set_);
}
bool TaintV2::equals(const TaintV2& other) const {
return set_.equals(other.set_);
}
void TaintV2::join_with(const TaintV2& other) {
set_.join_with(other.set_);
}
void TaintV2::widen_with(const TaintV2& other) {
set_.widen_with(other.set_);
}
void TaintV2::meet_with(const TaintV2& other) {
set_.meet_with(other.set_);
}
void TaintV2::narrow_with(const TaintV2& other) {
set_.narrow_with(other.set_);
}
void TaintV2::difference_with(const TaintV2& other) {
set_.difference_with(other.set_);
}
void TaintV2::add_inferred_features(const FeatureMayAlwaysSet& features) {
if (features.empty()) {
return;
}
map([&features](CalleeFrames& frames) {
frames.add_inferred_features(features);
});
}
void TaintV2::add_local_position(const Position* position) {
map([position](CalleeFrames& frames) {
frames.add_local_position(position);
});
}
void TaintV2::set_local_positions(const LocalPositionSet& positions) {
map([&positions](CalleeFrames& frames) {
frames.set_local_positions(positions);
});
}
void TaintV2::add_inferred_features_and_local_position(
const FeatureMayAlwaysSet& features,
const Position* MT_NULLABLE position) {
if (features.empty() && position == nullptr) {
return;
}
map([&features, position](CalleeFrames& frames) {
frames.add_inferred_features_and_local_position(features, position);
});
}
TaintV2 TaintV2::propagate(
const Method* callee,
const AccessPath& callee_port,
const Position* call_position,
int maximum_source_sink_distance,
const FeatureMayAlwaysSet& extra_features,
Context& context,
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
const std::vector<std::optional<std::string>>& source_constant_arguments)
const {
TaintV2 result;
for (const auto& frames : set_) {
auto propagated = frames.propagate(
callee,
callee_port,
call_position,
maximum_source_sink_distance,
context,
source_register_types,
source_constant_arguments);
if (propagated.is_bottom()) {
continue;
}
propagated.add_inferred_features(extra_features);
result.add(propagated);
}
return result;
}
TaintV2 TaintV2::attach_position(const Position* position) const {
TaintV2 result;
for (const auto& frames : set_) {
result.add(frames.attach_position(position));
}
return result;
}
TaintV2 TaintV2::transform_kind_with_features(
const std::function<std::vector<const Kind*>(const Kind*)>& transform_kind,
const std::function<FeatureMayAlwaysSet(const Kind*)>& add_features) const {
TaintV2 new_taint;
for (const auto& callee_frames : set_) {
new_taint.add(callee_frames.transform_kind_with_features(
transform_kind, add_features));
}
return new_taint;
}
void TaintV2::append_callee_port(
Path::Element path_element,
const std::function<bool(const Kind*)>& filter) {
map([&](CalleeFrames& frames) {
frames.append_callee_port(path_element, filter);
});
}
void TaintV2::update_non_leaf_positions(
const std::function<
const Position*(const Method*, const AccessPath&, const Position*)>&
new_call_position,
const std::function<LocalPositionSet(const LocalPositionSet&)>&
new_local_positions) {
map([&](CalleeFrames& frames) {
if (frames.callee() == nullptr) {
// This contains only leaf frames (no next hop/callee).
return;
}
auto new_frames = CalleeFrames::bottom();
for (const auto& frame : frames) {
auto new_frame = Frame(
frame.kind(),
frame.callee_port(),
frame.callee(),
frame.field_callee(),
new_call_position(
frame.callee(), frame.callee_port(), frame.call_position()),
frame.distance(),
frame.origins(),
frame.field_origins(),
frame.inferred_features(),
frame.locally_inferred_features(),
frame.user_features(),
frame.via_type_of_ports(),
frame.via_value_of_ports(),
new_local_positions(frame.local_positions()),
frame.canonical_names());
new_frames.add(new_frame);
}
frames = std::move(new_frames);
});
}
void TaintV2::filter_invalid_frames(
const std::function<bool(const Method*, const AccessPath&, const Kind*)>&
is_valid) {
map([&](CalleeFrames& frames) { frames.filter_invalid_frames(is_valid); });
}
bool TaintV2::contains_kind(const Kind* kind) const {
return std::any_of(
set_.begin(), set_.end(), [&](const CalleeFrames& callee_frames) {
return callee_frames.contains_kind(kind);
});
}
std::unordered_map<const Kind*, TaintV2> TaintV2::partition_by_kind() const {
return partition_by_kind<const Kind*>([](const Kind* kind) { return kind; });
}
FeatureMayAlwaysSet TaintV2::features_joined() const {
auto features = FeatureMayAlwaysSet::bottom();
for (const auto& callee_frames : set_) {
for (const auto& frame : callee_frames) {
features.join_with(frame.features());
}
}
return features;
}
void TaintV2::add(const CalleeFrames& frames) {
set_.add(frames);
}
void TaintV2::map(const std::function<void(CalleeFrames&)>& f) {
set_.map(f);
}
} // namespace marianatrench