From b753f3cb607e7705abe52d8f6f75d3ee52facb39 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Mon, 24 Jan 2022 15:27:10 +0000 Subject: [PATCH 01/17] Initial implementation of DLIR->Souffle Emitter --- src/ir/auth_logic/BUILD | 2 ++ src/ir/auth_logic/ast.h | 24 ++++++++++++++++++++++++ src/ir/auth_logic/datalog_ir.h | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index 5ea7b6508..48c5a64a6 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -23,6 +23,7 @@ cc_library( name = "ast", hdrs = [ "ast.h", + "datalog_ir.h", ], visibility = ["//test:__pkg__"], deps = [ @@ -41,6 +42,7 @@ cc_library( "lowering_ast_datalog.h", "map_iter.h", "move_append.h", + "souffle_emitter.h" # TODO move this ], visibility = ["//test:__pkg__"], deps = [ diff --git a/src/ir/auth_logic/ast.h b/src/ir/auth_logic/ast.h index f647594ce..eff37b927 100644 --- a/src/ir/auth_logic/ast.h +++ b/src/ir/auth_logic/ast.h @@ -53,6 +53,30 @@ class Predicate { const std::vector& args() const { return args_; } Sign sign() const { return sign_; } + // We need a hash function for predicates because the SouffleEmitter + // uses an std::unordered_set to track which predicates have already been + // declared. + struct HashFunction { + size_t operator()(const Predicate& predicate) const { + size_t ret = std::hash()(predicate.name()) ^ + std::hash()(predicate.sign()); + for (auto arg : predicate.args()) { + ret ^= std::hash()(arg); + } + return ret; + } + }; + + // Equality is also needed to use a Predicate in an std::unordered_set + bool operator==(const Predicate& otherPredicate) const { + if (this->args().size() != otherPredicate.args().size()) return false; + for (int i = 0; i < this->args().size(); i++) { + if (this->args()[i] != otherPredicate.args()[i]) return false; + } + return this->name() == otherPredicate.name() && + this->sign() == otherPredicate.sign(); + } + private: std::string name_; std::vector args_; diff --git a/src/ir/auth_logic/datalog_ir.h b/src/ir/auth_logic/datalog_ir.h index 2dade0c47..ef0a6640c 100644 --- a/src/ir/auth_logic/datalog_ir.h +++ b/src/ir/auth_logic/datalog_ir.h @@ -31,6 +31,8 @@ class DLIRCondAssertion { public: explicit DLIRCondAssertion(Predicate lhs, std::vector rhs) : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {} + const Predicate& lhs() { return lhs_; } + const std::vector& rhs() { return rhs_; } private: Predicate lhs_; @@ -48,6 +50,7 @@ class DLIRAssertion { using DLIRAssertionVariantType = std::variant; explicit DLIRAssertion(DLIRAssertionVariantType value) : value_(std::move(value)) {} + const DLIRAssertionVariantType& GetValue() const { return value_; } private: std::variant value_; @@ -58,6 +61,8 @@ class DLIRProgram { DLIRProgram(std::vector assertions, std::vector outputs) : assertions_(std::move(assertions)), outputs_(std::move(outputs)) {} + const std::vector& assertions() { return assertions_; } + const std::vector& outputs() { return outputs_; } private: std::vector assertions_; From 1c3b6a479ee05aa827eaff42634bb2c675077112 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Mon, 24 Jan 2022 15:29:25 +0000 Subject: [PATCH 02/17] Add missing file --- src/ir/auth_logic/souffle_emitter.h | 143 ++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 src/ir/auth_logic/souffle_emitter.h diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h new file mode 100644 index 000000000..d8b1681a0 --- /dev/null +++ b/src/ir/auth_logic/souffle_emitter.h @@ -0,0 +1,143 @@ +/* + * Copyright 2022 The Raksha Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ +#define SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ + +#include + +#include "src/ir/auth_logic/ast.h" + +namespace raksha::ir::auth_logic { + +class SouffleEmitter { + public: + std::string EmitProgram(DLIRProgram program) { + SouffleEmitter emitter; + std::string body = emitter.EmitProgramBody(program); + std::string outputs = emitter.EmitOutputs(program); + std::string decls = emitter.EmitDeclarations(); + return std::move(body) + + "\n" + + std::move(outputs) + + "\n" + + std::move(decls); + } + + private: + SouffleEmitter() + : declarations_( + std::unordered_set()) + {}; + + // This function produces a normalized version of predicates to + // be used when generating declarations of the predicates. It replaces + // argument names with generic numbered ones. It is applied + // to predicates before they are added to the set of declarations so that + // there are no duplicate delcarations (which would otherwise happen + // whenever a predicate is referenced more than once with different + // arguments). + // To prevent instances of negated and non-negated uses of the predicate + // from generating two declarations, the sign here is always positive. + Predicate PredToDeclaration(Predicate predicate) { + std::vector decl_args; + for( int i=0; i < predicate.args().size(); i++ ) { + decl_args.push_back("x" + std::to_string(i)); + } + return Predicate(predicate.name(), predicate.args(), kPositive); + } + + std::string EmitVecSeparated(std::vector vec, + std::string sep) { + std::string ret = ""; + bool is_first = true; + for(auto elm : vec) { + if( !is_first ) { ret += sep; } else { is_first = false; } + ret += elm; + } + return ret; + } + + std::string EmitPredicate(Predicate predicate) { + // Whenever a new predicate is encountered, it is added to the set of + // declarations (which does not include duplicates because it is a set). + declarations_.insert(PredToDeclaration(predicate)); + return (predicate.sign() == kNegated ? "!" : "") + + predicate.name() + + "(" + EmitVecSeparated(predicate.args(), ", ") + ")"; + } + + std::string EmitAssertionInner(Predicate predicate) { + return EmitPredicate(predicate) + "."; + } + + std::string EmitAssertionInner(DLIRCondAssertion cond_assertion) { + std::string lhs = EmitPredicate(cond_assertion.lhs()); + std::vector rhs_translated; + for(auto arg: cond_assertion.rhs()) { + rhs_translated.push_back(EmitPredicate(arg)); + } + std::string rhs = EmitVecSeparated(rhs_translated, ", "); + return std::move(lhs) + " :- " + std::move(rhs) + "."; + } + + std::string EmitAssertion(DLIRAssertion assertion) { + return std::visit( + [this](auto value) { return EmitAssertionInner(value); }, + assertion.GetValue()); + } + + std::string EmitProgramBody(DLIRProgram program) { + std::vector body_translated; + for(auto assertion : program.assertions()) { + body_translated.push_back(EmitAssertion(assertion)); + } + return EmitVecSeparated(body_translated, "\n"); + } + + std::string EmitOutputs(DLIRProgram program) { + std::string ret; + for (auto out : program.outputs()) { + ret += ".output " + out + "\n"; + } + return ret; + } + + std::string EmitDeclaration(Predicate predicate) { + std::string args = ""; + bool is_first = true; + for(auto elm : predicate.args()) { + if(!is_first) { args += ", "; } else { is_first = false; } + args += elm + ": symbol"; + } + return ".decl " + predicate.name() + "(" + + args + ")"; + } + + std::string EmitDeclarations() { + std::vector ret; + for(auto decl : declarations_) { + ret.push_back(EmitDeclaration(decl)); + } + return EmitVecSeparated(ret, "\n"); + } + + std::unordered_set declarations_; +}; + +} // namespace raksha::ir::auth_logic + +#endif //SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ From e25e903b0fda6c4e3bc6380c684d3cd7f4b49501 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Tue, 25 Jan 2022 17:22:46 +0000 Subject: [PATCH 03/17] PR Fixup --- src/ir/auth_logic/BUILD | 17 ++++++++-- src/ir/auth_logic/ast.h | 15 ++++++--- src/ir/auth_logic/souffle_emitter.h | 48 ++++++++++++++--------------- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index 48c5a64a6..d4dd83aa6 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -23,7 +23,6 @@ cc_library( name = "ast", hdrs = [ "ast.h", - "datalog_ir.h", ], visibility = ["//test:__pkg__"], deps = [ @@ -37,7 +36,6 @@ cc_library( name = "lowering_ast_datalog", srcs = ["lowering_ast_datalog.cc"], hdrs = [ - "ast.h", "datalog_ir.h", "lowering_ast_datalog.h", "map_iter.h", @@ -46,12 +44,27 @@ cc_library( ], visibility = ["//test:__pkg__"], deps = [ + "//src/ir/auth_logic:ast", "//src/common/logging", "//src/utils:overloaded", "@absl//absl/strings:str_format", ], ) +cc_library( + name = "souffle_emitter", + srcs = ["souffle_emitter_build_stub.cc"], + hdrs = [ + "souffle_emitter.h", + ], + deps = [ + "//src/ir/auth_logic:ast", + "//src/ir/auth_logic:lowering_ast_datalog", + "@absl//absl/container:flat_hash_set", + "@absl//absl/strings", + ], +) + cc_test( name = "ast_test", srcs = ["ast_test.cc"], diff --git a/src/ir/auth_logic/ast.h b/src/ir/auth_logic/ast.h index eff37b927..ff0f26dfe 100644 --- a/src/ir/auth_logic/ast.h +++ b/src/ir/auth_logic/ast.h @@ -69,12 +69,19 @@ class Predicate { // Equality is also needed to use a Predicate in an std::unordered_set bool operator==(const Predicate& otherPredicate) const { - if (this->args().size() != otherPredicate.args().size()) return false; + if (this->name() != otherPredicate.name()) { + return false; + } + if (this->sign() != otherPredicate.sign()) { + return false; + } + if (this->args().size() != otherPredicate.args().size()) { + return false; + } for (int i = 0; i < this->args().size(); i++) { - if (this->args()[i] != otherPredicate.args()[i]) return false; + if (this->args().at(i) != otherPredicate.args().at(i)) return false; } - return this->name() == otherPredicate.name() && - this->sign() == otherPredicate.sign(); + return true; } private: diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index d8b1681a0..7c1e6d878 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -17,9 +17,10 @@ #ifndef SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ #define SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ -#include - -#include "src/ir/auth_logic/ast.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "src/ir/auth_logic/datalog_ir.h" namespace raksha::ir::auth_logic { @@ -30,17 +31,17 @@ class SouffleEmitter { std::string body = emitter.EmitProgramBody(program); std::string outputs = emitter.EmitOutputs(program); std::string decls = emitter.EmitDeclarations(); - return std::move(body) - + "\n" - + std::move(outputs) - + "\n" - + std::move(decls); + return absl::StrCat(std::move(body), + "\n", + std::move(outputs), + "\n", + std::move(decls)); } private: SouffleEmitter() : declarations_( - std::unordered_set()) + absl::flat_hash_set()) {}; // This function produces a normalized version of predicates to @@ -75,9 +76,10 @@ class SouffleEmitter { // Whenever a new predicate is encountered, it is added to the set of // declarations (which does not include duplicates because it is a set). declarations_.insert(PredToDeclaration(predicate)); - return (predicate.sign() == kNegated ? "!" : "") - + predicate.name() - + "(" + EmitVecSeparated(predicate.args(), ", ") + ")"; + return absl::StrCat( + predicate.sign() == kNegated ? "!" : "", + predicate.name(), + "(", absl::StrJoin(predicate.args(), ", "), ")"); } std::string EmitAssertionInner(Predicate predicate) { @@ -90,8 +92,8 @@ class SouffleEmitter { for(auto arg: cond_assertion.rhs()) { rhs_translated.push_back(EmitPredicate(arg)); } - std::string rhs = EmitVecSeparated(rhs_translated, ", "); - return std::move(lhs) + " :- " + std::move(rhs) + "."; + return absl::StrCat(std::move(lhs), " :- ", + absl::StrJoin(rhs_translated, ", "), "."); } std::string EmitAssertion(DLIRAssertion assertion) { @@ -105,26 +107,24 @@ class SouffleEmitter { for(auto assertion : program.assertions()) { body_translated.push_back(EmitAssertion(assertion)); } - return EmitVecSeparated(body_translated, "\n"); + return absl::StrJoin(body_translated, "\n"); } std::string EmitOutputs(DLIRProgram program) { std::string ret; for (auto out : program.outputs()) { - ret += ".output " + out + "\n"; + absl::StrAppend(&ret, absl::StrCat(".output", out, "\n")); } return ret; } std::string EmitDeclaration(Predicate predicate) { - std::string args = ""; - bool is_first = true; + std::vector args_with_types; for(auto elm : predicate.args()) { - if(!is_first) { args += ", "; } else { is_first = false; } - args += elm + ": symbol"; + args_with_types.push_back(absl::StrCat(elm, ": symbol")); } - return ".decl " + predicate.name() + "(" - + args + ")"; + return absl::StrCat(".decl ", predicate.name(), + "(", absl::StrJoin(args_with_types, ", "), ")"); } std::string EmitDeclarations() { @@ -132,10 +132,10 @@ class SouffleEmitter { for(auto decl : declarations_) { ret.push_back(EmitDeclaration(decl)); } - return EmitVecSeparated(ret, "\n"); + return absl::StrJoin(ret, "\n"); } - std::unordered_set declarations_; + absl::flat_hash_set declarations_; }; } // namespace raksha::ir::auth_logic From 2dcc63a58356783683375805e07eecee63cdd110 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Tue, 25 Jan 2022 17:29:34 +0000 Subject: [PATCH 04/17] PR Fixup --- src/ir/auth_logic/souffle_emitter.h | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index 7c1e6d878..22232823e 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -58,18 +58,7 @@ class SouffleEmitter { for( int i=0; i < predicate.args().size(); i++ ) { decl_args.push_back("x" + std::to_string(i)); } - return Predicate(predicate.name(), predicate.args(), kPositive); - } - - std::string EmitVecSeparated(std::vector vec, - std::string sep) { - std::string ret = ""; - bool is_first = true; - for(auto elm : vec) { - if( !is_first ) { ret += sep; } else { is_first = false; } - ret += elm; - } - return ret; + return Predicate(predicate.name(), decl_args, kPositive); } std::string EmitPredicate(Predicate predicate) { From fc1cca79fd7de0bb617bef3f3b18df0af4dcf304 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Tue, 25 Jan 2022 17:31:37 +0000 Subject: [PATCH 05/17] linters --- src/ir/auth_logic/BUILD | 2 +- src/ir/auth_logic/souffle_emitter.h | 176 ++++++++++++++-------------- 2 files changed, 86 insertions(+), 92 deletions(-) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index d4dd83aa6..e1e7bd0de 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -44,8 +44,8 @@ cc_library( ], visibility = ["//test:__pkg__"], deps = [ - "//src/ir/auth_logic:ast", "//src/common/logging", + "//src/ir/auth_logic:ast", "//src/utils:overloaded", "@absl//absl/strings:str_format", ], diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index 22232823e..5b7adc811 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -25,108 +25,102 @@ namespace raksha::ir::auth_logic { class SouffleEmitter { - public: - std::string EmitProgram(DLIRProgram program) { - SouffleEmitter emitter; - std::string body = emitter.EmitProgramBody(program); - std::string outputs = emitter.EmitOutputs(program); - std::string decls = emitter.EmitDeclarations(); - return absl::StrCat(std::move(body), - "\n", - std::move(outputs), - "\n", - std::move(decls)); - } - - private: - SouffleEmitter() + public: + std::string EmitProgram(DLIRProgram program) { + SouffleEmitter emitter; + std::string body = emitter.EmitProgramBody(program); + std::string outputs = emitter.EmitOutputs(program); + std::string decls = emitter.EmitDeclarations(); + return absl::StrCat(std::move(body), "\n", std::move(outputs), "\n", + std::move(decls)); + } + + private: + SouffleEmitter() : declarations_( - absl::flat_hash_set()) - {}; - - // This function produces a normalized version of predicates to - // be used when generating declarations of the predicates. It replaces - // argument names with generic numbered ones. It is applied - // to predicates before they are added to the set of declarations so that - // there are no duplicate delcarations (which would otherwise happen - // whenever a predicate is referenced more than once with different - // arguments). - // To prevent instances of negated and non-negated uses of the predicate - // from generating two declarations, the sign here is always positive. - Predicate PredToDeclaration(Predicate predicate) { - std::vector decl_args; - for( int i=0; i < predicate.args().size(); i++ ) { - decl_args.push_back("x" + std::to_string(i)); - } - return Predicate(predicate.name(), decl_args, kPositive); - } - - std::string EmitPredicate(Predicate predicate) { - // Whenever a new predicate is encountered, it is added to the set of - // declarations (which does not include duplicates because it is a set). - declarations_.insert(PredToDeclaration(predicate)); - return absl::StrCat( - predicate.sign() == kNegated ? "!" : "", - predicate.name(), - "(", absl::StrJoin(predicate.args(), ", "), ")"); + absl::flat_hash_set()){}; + + // This function produces a normalized version of predicates to + // be used when generating declarations of the predicates. It replaces + // argument names with generic numbered ones. It is applied + // to predicates before they are added to the set of declarations so that + // there are no duplicate delcarations (which would otherwise happen + // whenever a predicate is referenced more than once with different + // arguments). + // To prevent instances of negated and non-negated uses of the predicate + // from generating two declarations, the sign here is always positive. + Predicate PredToDeclaration(Predicate predicate) { + std::vector decl_args; + for (int i = 0; i < predicate.args().size(); i++) { + decl_args.push_back("x" + std::to_string(i)); } - - std::string EmitAssertionInner(Predicate predicate) { - return EmitPredicate(predicate) + "."; + return Predicate(predicate.name(), decl_args, kPositive); + } + + std::string EmitPredicate(Predicate predicate) { + // Whenever a new predicate is encountered, it is added to the set of + // declarations (which does not include duplicates because it is a set). + declarations_.insert(PredToDeclaration(predicate)); + return absl::StrCat(predicate.sign() == kNegated ? "!" : "", + predicate.name(), "(", + absl::StrJoin(predicate.args(), ", "), ")"); + } + + std::string EmitAssertionInner(Predicate predicate) { + return EmitPredicate(predicate) + "."; + } + + std::string EmitAssertionInner(DLIRCondAssertion cond_assertion) { + std::string lhs = EmitPredicate(cond_assertion.lhs()); + std::vector rhs_translated; + for (auto arg : cond_assertion.rhs()) { + rhs_translated.push_back(EmitPredicate(arg)); } - - std::string EmitAssertionInner(DLIRCondAssertion cond_assertion) { - std::string lhs = EmitPredicate(cond_assertion.lhs()); - std::vector rhs_translated; - for(auto arg: cond_assertion.rhs()) { - rhs_translated.push_back(EmitPredicate(arg)); - } - return absl::StrCat(std::move(lhs), " :- ", - absl::StrJoin(rhs_translated, ", "), "."); + return absl::StrCat(std::move(lhs), " :- ", + absl::StrJoin(rhs_translated, ", "), "."); + } + + std::string EmitAssertion(DLIRAssertion assertion) { + return std::visit([this](auto value) { return EmitAssertionInner(value); }, + assertion.GetValue()); + } + + std::string EmitProgramBody(DLIRProgram program) { + std::vector body_translated; + for (auto assertion : program.assertions()) { + body_translated.push_back(EmitAssertion(assertion)); } + return absl::StrJoin(body_translated, "\n"); + } - std::string EmitAssertion(DLIRAssertion assertion) { - return std::visit( - [this](auto value) { return EmitAssertionInner(value); }, - assertion.GetValue()); + std::string EmitOutputs(DLIRProgram program) { + std::string ret; + for (auto out : program.outputs()) { + absl::StrAppend(&ret, absl::StrCat(".output", out, "\n")); } + return ret; + } - std::string EmitProgramBody(DLIRProgram program) { - std::vector body_translated; - for(auto assertion : program.assertions()) { - body_translated.push_back(EmitAssertion(assertion)); - } - return absl::StrJoin(body_translated, "\n"); + std::string EmitDeclaration(Predicate predicate) { + std::vector args_with_types; + for (auto elm : predicate.args()) { + args_with_types.push_back(absl::StrCat(elm, ": symbol")); } - - std::string EmitOutputs(DLIRProgram program) { - std::string ret; - for (auto out : program.outputs()) { - absl::StrAppend(&ret, absl::StrCat(".output", out, "\n")); - } - return ret; - } - - std::string EmitDeclaration(Predicate predicate) { - std::vector args_with_types; - for(auto elm : predicate.args()) { - args_with_types.push_back(absl::StrCat(elm, ": symbol")); - } - return absl::StrCat(".decl ", predicate.name(), - "(", absl::StrJoin(args_with_types, ", "), ")"); - } - - std::string EmitDeclarations() { - std::vector ret; - for(auto decl : declarations_) { - ret.push_back(EmitDeclaration(decl)); - } - return absl::StrJoin(ret, "\n"); + return absl::StrCat(".decl ", predicate.name(), "(", + absl::StrJoin(args_with_types, ", "), ")"); + } + + std::string EmitDeclarations() { + std::vector ret; + for (auto decl : declarations_) { + ret.push_back(EmitDeclaration(decl)); } + return absl::StrJoin(ret, "\n"); + } - absl::flat_hash_set declarations_; + absl::flat_hash_set declarations_; }; } // namespace raksha::ir::auth_logic -#endif //SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ +#endif // SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ From fb7478b4ea3f7bf0fb7ef5e8197e1eae644dbe19 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Tue, 25 Jan 2022 17:53:53 +0000 Subject: [PATCH 06/17] add missing file --- src/ir/auth_logic/souffle_emitter_build_stub.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/ir/auth_logic/souffle_emitter_build_stub.cc diff --git a/src/ir/auth_logic/souffle_emitter_build_stub.cc b/src/ir/auth_logic/souffle_emitter_build_stub.cc new file mode 100644 index 000000000..c3154becc --- /dev/null +++ b/src/ir/auth_logic/souffle_emitter_build_stub.cc @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Raksha Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "souffle_emitter.h" From 2847c56d42efba17aeee854b41a2fab0b7d172a4 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Tue, 8 Feb 2022 18:12:08 +0000 Subject: [PATCH 07/17] Emitter tests --- src/ir/auth_logic/BUILD | 10 + src/ir/auth_logic/lowering_ast_datalog.cc | 31 +-- src/ir/auth_logic/souffle_emitter.h | 8 +- src/ir/auth_logic/souffle_emitter_test.cc | 255 ++++++++++++++++++++++ 4 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 src/ir/auth_logic/souffle_emitter_test.cc diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index e1e7bd0de..5298c91f8 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -65,6 +65,16 @@ cc_library( ], ) +cc_test( + name = "souffle_emitter_test", + srcs = ["souffle_emitter_test.cc"], + deps = [ + ":souffle_emitter", + "//src/common/testing:gtest", + ], +) + + cc_test( name = "ast_test", srcs = ["ast_test.cc"], diff --git a/src/ir/auth_logic/lowering_ast_datalog.cc b/src/ir/auth_logic/lowering_ast_datalog.cc index ec9080039..8a04cd2fc 100644 --- a/src/ir/auth_logic/lowering_ast_datalog.cc +++ b/src/ir/auth_logic/lowering_ast_datalog.cc @@ -66,7 +66,6 @@ Predicate CanActAsToDLIR(const CanActAs& can_act_as) { DLIRAssertion LoweringToDatalogPass::SpokenAttributeToDLIR( const Principal& speaker, const Attribute& attribute) { - Predicate main_predicate = AttributeToDLIR(attribute); // Attributes interact with "canActAs" because if "Y canActAs X" // then Y also picks up X's attributes. We need to generate @@ -78,16 +77,17 @@ DLIRAssertion LoweringToDatalogPass::SpokenAttributeToDLIR( Principal prin_y(FreshVar()); // This is `speaker says Y PredX` - Predicate generated_lhs = PushPrincipal("says_", prin_y, main_predicate); - - Predicate y_can_act_as_x("canActAs", - {prin_y.name(), attribute.principal().name()}, - Sign::kPositive); + Predicate y_predX = AttributeToDLIR(Attribute(prin_y, attribute.predicate())); + Predicate generated_lhs = PushPrincipal("says_", speaker, y_predX); + // This is `speaker says Y canActAs X` + Predicate y_can_act_as_x = CanActAsToDLIR(CanActAs(prin_y, + attribute.principal())); Predicate speaker_says_y_can_act_as_x = PushPrincipal("says_", speaker, y_can_act_as_x); // This is `speaker says X PredX` + Predicate main_predicate = AttributeToDLIR(attribute); Predicate speaker_says_x_pred = PushPrincipal("says_", speaker, main_predicate); @@ -101,28 +101,29 @@ DLIRAssertion LoweringToDatalogPass::SpokenAttributeToDLIR( DLIRAssertion LoweringToDatalogPass::SpokenCanActAsToDLIR( const Principal& speaker, const CanActAs& can_act_as) { - Predicate main_predicate = CanActAsToDLIR(can_act_as); // "canActAs" facts are passed to principals via other canActAs facts in // essentially the same way as attributes. This function adds extra // rules to pass these around. If the `canActAs` under translation // is `X canActAs Z`, then the rule we need to generate is: - // `speaker says Y PredX :- - // speaker says Y canActAs X, speaker says X canActAsZ` + // `speaker says Y canActAs Z :- + // speaker says Y canActAs X, speaker says X canActAs Z` // (Where Y is a fresh variable) Principal prin_y(FreshVar()); - // This is `speaker says Y PredX` - Predicate generated_lhs = PushPrincipal("says_", prin_y, main_predicate); - - Predicate y_can_act_as_x("canActAs", - {prin_y.name(), can_act_as.left_principal().name()}, - Sign::kPositive); + // This is `speaker says Y canActAs Z` + Predicate y_can_act_as_z = CanActAsToDLIR(CanActAs(prin_y, + can_act_as.right_principal())); + Predicate generated_lhs = PushPrincipal("says_", speaker, y_can_act_as_z); + // This is `speaker says Y canActAs X` + Predicate y_can_act_as_x = CanActAsToDLIR(CanActAs(prin_y, + can_act_as.left_principal())); Predicate speaker_says_y_can_act_as_x = PushPrincipal("says_", speaker, y_can_act_as_x); // This is `speaker says X canActAs Z` + Predicate main_predicate = CanActAsToDLIR(can_act_as); Predicate speaker_says_x_can_act_as_z = PushPrincipal("says_", speaker, main_predicate); diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index 5b7adc811..a9774f6e2 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -26,7 +26,7 @@ namespace raksha::ir::auth_logic { class SouffleEmitter { public: - std::string EmitProgram(DLIRProgram program) { + static std::string EmitProgram(DLIRProgram program) { SouffleEmitter emitter; std::string body = emitter.EmitProgramBody(program); std::string outputs = emitter.EmitOutputs(program); @@ -52,7 +52,7 @@ class SouffleEmitter { Predicate PredToDeclaration(Predicate predicate) { std::vector decl_args; for (int i = 0; i < predicate.args().size(); i++) { - decl_args.push_back("x" + std::to_string(i)); + decl_args.push_back(absl::StrCat("x", std::to_string(i))); } return Predicate(predicate.name(), decl_args, kPositive); } @@ -67,7 +67,7 @@ class SouffleEmitter { } std::string EmitAssertionInner(Predicate predicate) { - return EmitPredicate(predicate) + "."; + return absl::StrCat(EmitPredicate(predicate), "."); } std::string EmitAssertionInner(DLIRCondAssertion cond_assertion) { @@ -96,7 +96,7 @@ class SouffleEmitter { std::string EmitOutputs(DLIRProgram program) { std::string ret; for (auto out : program.outputs()) { - absl::StrAppend(&ret, absl::StrCat(".output", out, "\n")); + absl::StrAppend(&ret, absl::StrCat(".output ", out, "\n")); } return ret; } diff --git a/src/ir/auth_logic/souffle_emitter_test.cc b/src/ir/auth_logic/souffle_emitter_test.cc new file mode 100644 index 000000000..65557ce32 --- /dev/null +++ b/src/ir/auth_logic/souffle_emitter_test.cc @@ -0,0 +1,255 @@ +/* + * Copyright 2022 Google LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/common/testing/gtest.h" +#include "src/ir/auth_logic/ast.h" +#include "src/ir/auth_logic/datalog_ir.h" +#include "src/ir/auth_logic/lowering_ast_datalog.h" +#include "src/ir/auth_logic/souffle_emitter.h" +#include "src/ir/auth_logic/move_append.h" + +namespace raksha::ir::auth_logic { + + Program BuildSingleAssertionProgram(SaysAssertion assertion) { + std::vector assertion_list = {}; + assertion_list.push_back(std::move(assertion)); + return Program(std::move(assertion_list), {}); + } + + SaysAssertion BuildSingleSaysAssertion(Principal speaker, Assertion assertion) { + std::vector assertion_list = {}; + assertion_list.push_back(std::move(assertion)); + return SaysAssertion(std::move(speaker), std::move(assertion_list)); + } + + Program BuildPredicateTestProgram() { + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestPrincipal"), Assertion(Fact(BaseFact( + Predicate("foo", {"bar", "baz"}, kPositive)))))); + } + + TEST(EmitterTestSuite, SimpleTest) { + std::string expected = +R"(says_foo(TestPrincipal, bar, baz). +grounded_dummy(dummy_var). + +.decl says_foo(x0: symbol, x1: symbol, x2: symbol) +.decl grounded_dummy(x0: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildPredicateTestProgram())); + + EXPECT_EQ(actual, expected); + } + + Program BuildAttributeTestProgram() { + return BuildSingleAssertionProgram( + BuildSingleSaysAssertion(Principal("TestSpeaker"), + Assertion(Fact(BaseFact( + Attribute(Principal("OtherTestPrincipal"), + Predicate("hasProperty", {"wellTested"}, kPositive))))) + )); + } + + TEST(EmitterTestSuite, AttributeTest) { + std::string expected = +R"(says_hasProperty(TestSpeaker, x__1, wellTested) :- says_canActAs(TestSpeaker, x__1, OtherTestPrincipal), says_hasProperty(TestSpeaker, OtherTestPrincipal, wellTested). +says_hasProperty(TestSpeaker, OtherTestPrincipal, wellTested). +grounded_dummy(dummy_var). + +.decl says_canActAs(x0: symbol, x1: symbol, x2: symbol) +.decl grounded_dummy(x0: symbol) +.decl says_hasProperty(x0: symbol, x1: symbol, x2: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildAttributeTestProgram())); + + EXPECT_EQ(actual, expected); + } + + Program BuildCanActAsProgram() { + return BuildSingleAssertionProgram( + BuildSingleSaysAssertion(Principal("TestSpeaker"), + Assertion(Fact(BaseFact( + CanActAs(Principal("PrincipalA"), Principal("PrincipalB"))))) + )); + } + + TEST(EmitterTestSuite, CanActAsTest) { + std::string expected = +R"(says_canActAs(TestSpeaker, x__1, PrincipalB) :- says_canActAs(TestSpeaker, x__1, PrincipalA), says_canActAs(TestSpeaker, PrincipalA, PrincipalB). +says_canActAs(TestSpeaker, PrincipalA, PrincipalB). +grounded_dummy(dummy_var). + +.decl grounded_dummy(x0: symbol) +.decl says_canActAs(x0: symbol, x1: symbol, x2: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildCanActAsProgram())); + + EXPECT_EQ(actual, expected); + } + + Program BuildCanSayProgram() { + std::unique_ptr inner_fact = std::unique_ptr( + new Fact(BaseFact(Predicate("grantAccess", + {"secretFile"}, kPositive)))); + Fact::FactVariantType cansay_fact = std::unique_ptr( + new CanSay(Principal("PrincipalA"), inner_fact)); + return BuildSingleAssertionProgram( + BuildSingleSaysAssertion(Principal("TestSpeaker"), + Assertion(Fact(std::move(cansay_fact))))); + } + + TEST(EmitterTestSuite, CanSayTest) { + std::string expected = +R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFile), says_canSay_grantAccess(TestSpeaker, x__1, secretFile). +says_canSay_grantAccess(TestSpeaker, PrincipalA, secretFile). +grounded_dummy(dummy_var). + +.decl says_grantAccess(x0: symbol, x1: symbol) +.decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol) +.decl grounded_dummy(x0: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildCanSayProgram())); + + EXPECT_EQ(actual, expected); + } + + Program BuildDoubleCanSayProgram() { + // So much fun with unique pointers! + std::unique_ptr inner_fact = std::unique_ptr( + new Fact(BaseFact(Predicate("grantAccess", + {"secretFile"}, kPositive)))); + Fact::FactVariantType inner_cansay = std::unique_ptr( + new CanSay(Principal("PrincipalA"), inner_fact)); + std::unique_ptr inner_cansay_fact = std::unique_ptr( + new Fact(std::move(inner_cansay))); + Fact::FactVariantType cansay_fact = std::unique_ptr( + new CanSay(Principal("PrincipalB"), inner_cansay_fact)); + return BuildSingleAssertionProgram( + BuildSingleSaysAssertion(Principal("TestSpeaker"), + Assertion(Fact(std::move(cansay_fact))))); + } + + TEST(EmitterTestSuite, DoubleCanSayTest) { + std::string expected = +R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFile), says_canSay_grantAccess(TestSpeaker, x__1, secretFile). +says_canSay_grantAccess(TestSpeaker, PrincipalA, secretFile) :- says_canSay_grantAccess(x__2, PrincipalA, secretFile), says_canSay_canSay_grantAccess(TestSpeaker, x__2, PrincipalA, secretFile). +says_canSay_canSay_grantAccess(TestSpeaker, PrincipalB, PrincipalA, secretFile). +grounded_dummy(dummy_var). + +.decl says_canSay_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol, x3: symbol) +.decl grounded_dummy(x0: symbol) +.decl says_grantAccess(x0: symbol, x1: symbol) +.decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildDoubleCanSayProgram())); + + EXPECT_EQ(actual, expected); + } + + Program BuildConditionalProgram() { + std::vector rhs = {BaseFact(Predicate( + "isEmployee", {"somePerson"}, kPositive))}; + Fact lhs(BaseFact(Predicate("canAccess", {"somePerson", "someFile"}, + kPositive))); + return BuildSingleAssertionProgram( + BuildSingleSaysAssertion(Principal("TestSpeaker"), + Assertion(ConditionalAssertion(std::move(lhs), std::move(rhs))))); + } + + TEST(EmitterTestSuite, ConditionalProgramTest) { + std::string expected = +R"(says_canAccess(TestSpeaker, somePerson, someFile) :- says_isEmployee(TestSpeaker, somePerson). +grounded_dummy(dummy_var). + +.decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) +.decl grounded_dummy(x0: symbol) +.decl says_isEmployee(x0: symbol, x1: symbol))"; + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildConditionalProgram())); + EXPECT_EQ(actual, expected); + } + + Program BuildMultiAssertionProgram() { + // Conditional Assertion + std::vector rhs = {BaseFact(Predicate( + "isEmployee", {"somePerson"}, kPositive))}; + Fact lhs(BaseFact(Predicate("canAccess", {"somePerson", "someFile"}, + kPositive))); + SaysAssertion condAssertion = BuildSingleSaysAssertion( + Principal("TestPrincipal"), + Assertion(ConditionalAssertion(std::move(lhs), + std::move(rhs)))); + + // Assertion stating the condition + SaysAssertion predicateAssertion = BuildSingleSaysAssertion( + Principal("TestPrincipal"), + Assertion(Fact(BaseFact( + Predicate("isEmployee", {"somePerson"}, + kPositive)))) + ); + + // I would love to just write this: + // return Program({std::move(condAssertion), + // std::move(predicateAssertion)}, {}); + + std::vector assertion_list = {}; + assertion_list.push_back(std::move(condAssertion)); + assertion_list.push_back(std::move(predicateAssertion)); + return Program(std::move(assertion_list), {}); + } + + TEST(EmitterTestSuite, MultiAssertionProgramTest) { + std::string expected = R"(says_canAccess(TestPrincipal, somePerson, someFile) :- says_isEmployee(TestPrincipal, somePerson). +says_isEmployee(TestPrincipal, somePerson). +grounded_dummy(dummy_var). + +.decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) +.decl grounded_dummy(x0: symbol) +.decl says_isEmployee(x0: symbol, x1: symbol))"; + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildMultiAssertionProgram())); + EXPECT_EQ(actual, expected); + } + + Program BuildQueryProgram() { + Query testQuery("theTestQuery", Principal("TestSpeaker"), + Fact(BaseFact(Predicate("anything", {"atAll"}, kPositive)))); + std::vector query_list = {}; + query_list.push_back(std::move(testQuery)); + return Program({}, std::move(query_list)); + } + + TEST(EmitterTestSuite, QueryTestProgram) { + std::string expected = +R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). +grounded_dummy(dummy_var). +.output theTestQuery + +.decl theTestQuery(x0: symbol) +.decl says_anything(x0: symbol, x1: symbol) +.decl grounded_dummy(x0: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildQueryProgram())); + EXPECT_EQ(actual, expected); + } + +} From ae04f4e68a2b9078a65faee41b9193498d35d67a Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Wed, 9 Feb 2022 13:54:10 +0000 Subject: [PATCH 08/17] PR Fixup --- src/ir/auth_logic/BUILD | 4 +-- src/ir/auth_logic/ast.h | 36 +++++------------------ src/ir/auth_logic/datalog_ir.h | 8 ++--- src/ir/auth_logic/lowering_ast_datalog.h | 2 ++ src/ir/auth_logic/souffle_emitter.h | 26 ++++++++-------- src/ir/auth_logic/souffle_emitter_test.cc | 34 +++++++++++++-------- 6 files changed, 49 insertions(+), 61 deletions(-) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index 5298c91f8..d7ac245ac 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -29,6 +29,7 @@ cc_library( "//src/common/logging", "//src/utils:overloaded", "@absl//absl/strings:str_format", + "@absl//absl/hash:hash", ], ) @@ -40,7 +41,6 @@ cc_library( "lowering_ast_datalog.h", "map_iter.h", "move_append.h", - "souffle_emitter.h" # TODO move this ], visibility = ["//test:__pkg__"], deps = [ @@ -60,7 +60,7 @@ cc_library( deps = [ "//src/ir/auth_logic:ast", "//src/ir/auth_logic:lowering_ast_datalog", - "@absl//absl/container:flat_hash_set", + "@absl//absl/container:btree", "@absl//absl/strings", ], ) diff --git a/src/ir/auth_logic/ast.h b/src/ir/auth_logic/ast.h index ff0f26dfe..df549e943 100644 --- a/src/ir/auth_logic/ast.h +++ b/src/ir/auth_logic/ast.h @@ -53,35 +53,13 @@ class Predicate { const std::vector& args() const { return args_; } Sign sign() const { return sign_; } - // We need a hash function for predicates because the SouffleEmitter - // uses an std::unordered_set to track which predicates have already been - // declared. - struct HashFunction { - size_t operator()(const Predicate& predicate) const { - size_t ret = std::hash()(predicate.name()) ^ - std::hash()(predicate.sign()); - for (auto arg : predicate.args()) { - ret ^= std::hash()(arg); - } - return ret; - } - }; - - // Equality is also needed to use a Predicate in an std::unordered_set - bool operator==(const Predicate& otherPredicate) const { - if (this->name() != otherPredicate.name()) { - return false; - } - if (this->sign() != otherPredicate.sign()) { - return false; - } - if (this->args().size() != otherPredicate.args().size()) { - return false; - } - for (int i = 0; i < this->args().size(); i++) { - if (this->args().at(i) != otherPredicate.args().at(i)) return false; - } - return true; + + // < operator is needed for btree_set, which is only used for declarations. + // Since declarations are uniquely defined by the name of the predicate, + // this implementation that just uses < on the predicate names should be + // sufficent in the context where it is used. + bool operator< (const Predicate& otherPredicate) const { + return this->name() < otherPredicate.name(); } private: diff --git a/src/ir/auth_logic/datalog_ir.h b/src/ir/auth_logic/datalog_ir.h index ef0a6640c..370dd183c 100644 --- a/src/ir/auth_logic/datalog_ir.h +++ b/src/ir/auth_logic/datalog_ir.h @@ -31,8 +31,8 @@ class DLIRCondAssertion { public: explicit DLIRCondAssertion(Predicate lhs, std::vector rhs) : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {} - const Predicate& lhs() { return lhs_; } - const std::vector& rhs() { return rhs_; } + const Predicate& lhs() const { return lhs_; } + const std::vector& rhs() const { return rhs_; } private: Predicate lhs_; @@ -61,8 +61,8 @@ class DLIRProgram { DLIRProgram(std::vector assertions, std::vector outputs) : assertions_(std::move(assertions)), outputs_(std::move(outputs)) {} - const std::vector& assertions() { return assertions_; } - const std::vector& outputs() { return outputs_; } + const std::vector& assertions() const { return assertions_; } + const std::vector& outputs() const { return outputs_; } private: std::vector assertions_; diff --git a/src/ir/auth_logic/lowering_ast_datalog.h b/src/ir/auth_logic/lowering_ast_datalog.h index ea331762a..cd984274b 100644 --- a/src/ir/auth_logic/lowering_ast_datalog.h +++ b/src/ir/auth_logic/lowering_ast_datalog.h @@ -156,6 +156,8 @@ class LoweringToDatalogPass { DLIRAssertion SpokenAttributeToDLIR(const Principal& speaker, const Attribute& attribute); + Predicate CanActAsToDLIR(const CanActAs& can_act_as); + // In the same way that attributes are passed around with "CanActAs", so // are other "CanActAs" facts. To implement this, the translation of // CanActAs also results in both a predicate and an extra rule that passes diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index a9774f6e2..3a3c13580 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Raksha Authors + * Copyright 2022 Google LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ #ifndef SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ #define SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ -#include "absl/container/flat_hash_set.h" +#include "absl/container/btree_set.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "src/ir/auth_logic/datalog_ir.h" @@ -26,7 +26,7 @@ namespace raksha::ir::auth_logic { class SouffleEmitter { public: - static std::string EmitProgram(DLIRProgram program) { + static std::string EmitProgram(const DLIRProgram& program) { SouffleEmitter emitter; std::string body = emitter.EmitProgramBody(program); std::string outputs = emitter.EmitOutputs(program); @@ -38,7 +38,7 @@ class SouffleEmitter { private: SouffleEmitter() : declarations_( - absl::flat_hash_set()){}; + absl::btree_set()){}; // This function produces a normalized version of predicates to // be used when generating declarations of the predicates. It replaces @@ -49,7 +49,7 @@ class SouffleEmitter { // arguments). // To prevent instances of negated and non-negated uses of the predicate // from generating two declarations, the sign here is always positive. - Predicate PredToDeclaration(Predicate predicate) { + Predicate PredToDeclaration(const Predicate& predicate) { std::vector decl_args; for (int i = 0; i < predicate.args().size(); i++) { decl_args.push_back(absl::StrCat("x", std::to_string(i))); @@ -57,7 +57,7 @@ class SouffleEmitter { return Predicate(predicate.name(), decl_args, kPositive); } - std::string EmitPredicate(Predicate predicate) { + std::string EmitPredicate(const Predicate& predicate) { // Whenever a new predicate is encountered, it is added to the set of // declarations (which does not include duplicates because it is a set). declarations_.insert(PredToDeclaration(predicate)); @@ -66,11 +66,11 @@ class SouffleEmitter { absl::StrJoin(predicate.args(), ", "), ")"); } - std::string EmitAssertionInner(Predicate predicate) { + std::string EmitAssertionInner(const Predicate& predicate) { return absl::StrCat(EmitPredicate(predicate), "."); } - std::string EmitAssertionInner(DLIRCondAssertion cond_assertion) { + std::string EmitAssertionInner(const DLIRCondAssertion& cond_assertion) { std::string lhs = EmitPredicate(cond_assertion.lhs()); std::vector rhs_translated; for (auto arg : cond_assertion.rhs()) { @@ -80,12 +80,12 @@ class SouffleEmitter { absl::StrJoin(rhs_translated, ", "), "."); } - std::string EmitAssertion(DLIRAssertion assertion) { + std::string EmitAssertion(const DLIRAssertion& assertion) { return std::visit([this](auto value) { return EmitAssertionInner(value); }, assertion.GetValue()); } - std::string EmitProgramBody(DLIRProgram program) { + std::string EmitProgramBody(const DLIRProgram& program) { std::vector body_translated; for (auto assertion : program.assertions()) { body_translated.push_back(EmitAssertion(assertion)); @@ -93,7 +93,7 @@ class SouffleEmitter { return absl::StrJoin(body_translated, "\n"); } - std::string EmitOutputs(DLIRProgram program) { + std::string EmitOutputs(const DLIRProgram& program) { std::string ret; for (auto out : program.outputs()) { absl::StrAppend(&ret, absl::StrCat(".output ", out, "\n")); @@ -101,7 +101,7 @@ class SouffleEmitter { return ret; } - std::string EmitDeclaration(Predicate predicate) { + std::string EmitDeclaration(const Predicate& predicate) { std::vector args_with_types; for (auto elm : predicate.args()) { args_with_types.push_back(absl::StrCat(elm, ": symbol")); @@ -118,7 +118,7 @@ class SouffleEmitter { return absl::StrJoin(ret, "\n"); } - absl::flat_hash_set declarations_; + absl::btree_set declarations_; }; } // namespace raksha::ir::auth_logic diff --git a/src/ir/auth_logic/souffle_emitter_test.cc b/src/ir/auth_logic/souffle_emitter_test.cc index 65557ce32..9c788130a 100644 --- a/src/ir/auth_logic/souffle_emitter_test.cc +++ b/src/ir/auth_logic/souffle_emitter_test.cc @@ -46,8 +46,8 @@ namespace raksha::ir::auth_logic { R"(says_foo(TestPrincipal, bar, baz). grounded_dummy(dummy_var). -.decl says_foo(x0: symbol, x1: symbol, x2: symbol) -.decl grounded_dummy(x0: symbol))"; +.decl grounded_dummy(x0: symbol) +.decl says_foo(x0: symbol, x1: symbol, x2: symbol))"; std::string actual = SouffleEmitter::EmitProgram( LoweringToDatalogPass::Lower(BuildPredicateTestProgram())); @@ -70,8 +70,8 @@ R"(says_hasProperty(TestSpeaker, x__1, wellTested) :- says_canActAs(TestSpeaker, says_hasProperty(TestSpeaker, OtherTestPrincipal, wellTested). grounded_dummy(dummy_var). -.decl says_canActAs(x0: symbol, x1: symbol, x2: symbol) .decl grounded_dummy(x0: symbol) +.decl says_canActAs(x0: symbol, x1: symbol, x2: symbol) .decl says_hasProperty(x0: symbol, x1: symbol, x2: symbol))"; std::string actual = SouffleEmitter::EmitProgram( @@ -120,9 +120,9 @@ R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFil says_canSay_grantAccess(TestSpeaker, PrincipalA, secretFile). grounded_dummy(dummy_var). -.decl says_grantAccess(x0: symbol, x1: symbol) +.decl grounded_dummy(x0: symbol) .decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol) -.decl grounded_dummy(x0: symbol))"; +.decl says_grantAccess(x0: symbol, x1: symbol))"; std::string actual = SouffleEmitter::EmitProgram( LoweringToDatalogPass::Lower(BuildCanSayProgram())); @@ -153,10 +153,10 @@ says_canSay_grantAccess(TestSpeaker, PrincipalA, secretFile) :- says_canSay_gran says_canSay_canSay_grantAccess(TestSpeaker, PrincipalB, PrincipalA, secretFile). grounded_dummy(dummy_var). -.decl says_canSay_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol, x3: symbol) .decl grounded_dummy(x0: symbol) -.decl says_grantAccess(x0: symbol, x1: symbol) -.decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol))"; +.decl says_canSay_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol, x3: symbol) +.decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol) +.decl says_grantAccess(x0: symbol, x1: symbol))"; std::string actual = SouffleEmitter::EmitProgram( LoweringToDatalogPass::Lower(BuildDoubleCanSayProgram())); @@ -179,8 +179,8 @@ grounded_dummy(dummy_var). R"(says_canAccess(TestSpeaker, somePerson, someFile) :- says_isEmployee(TestSpeaker, somePerson). grounded_dummy(dummy_var). -.decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) .decl grounded_dummy(x0: symbol) +.decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) .decl says_isEmployee(x0: symbol, x1: symbol))"; std::string actual = SouffleEmitter::EmitProgram( LoweringToDatalogPass::Lower(BuildConditionalProgram())); @@ -221,8 +221,8 @@ grounded_dummy(dummy_var). says_isEmployee(TestPrincipal, somePerson). grounded_dummy(dummy_var). -.decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) .decl grounded_dummy(x0: symbol) +.decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) .decl says_isEmployee(x0: symbol, x1: symbol))"; std::string actual = SouffleEmitter::EmitProgram( LoweringToDatalogPass::Lower(BuildMultiAssertionProgram())); @@ -238,14 +238,22 @@ grounded_dummy(dummy_var). } TEST(EmitterTestSuite, QueryTestProgram) { - std::string expected = + std::string expected = R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). grounded_dummy(dummy_var). .output theTestQuery -.decl theTestQuery(x0: symbol) +.decl grounded_dummy(x0: symbol) .decl says_anything(x0: symbol, x1: symbol) -.decl grounded_dummy(x0: symbol))"; +.decl theTestQuery(x0: symbol))"; + +// R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). +// grounded_dummy(dummy_var). +// .output theTestQuery +// +// .decl theTestQuery(x0: symbol) +// .decl says_anything(x0: symbol, x1: symbol) +// .decl grounded_dummy(x0: symbol))"; std::string actual = SouffleEmitter::EmitProgram( LoweringToDatalogPass::Lower(BuildQueryProgram())); From d1b4f0a74e58615fb8081fe781fefd82563e7ec0 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Wed, 9 Feb 2022 14:34:41 +0000 Subject: [PATCH 09/17] PR fixup --- src/ir/auth_logic/souffle_emitter.h | 18 ++++++++---------- .../auth_logic/souffle_emitter_build_stub.cc | 2 +- src/ir/auth_logic/souffle_emitter_test.cc | 1 - 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index 3a3c13580..de6870231 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -94,11 +94,10 @@ class SouffleEmitter { } std::string EmitOutputs(const DLIRProgram& program) { - std::string ret; - for (auto out : program.outputs()) { - absl::StrAppend(&ret, absl::StrCat(".output ", out, "\n")); - } - return ret; + return absl::StrJoin(program.outputs(), "\n", + [](std::string *out, const std::string& prog_out){ + return absl::StrAppend(out, absl::StrCat(".output ", prog_out)); + }); } std::string EmitDeclaration(const Predicate& predicate) { @@ -111,11 +110,10 @@ class SouffleEmitter { } std::string EmitDeclarations() { - std::vector ret; - for (auto decl : declarations_) { - ret.push_back(EmitDeclaration(decl)); - } - return absl::StrJoin(ret, "\n"); + return absl::StrJoin(declarations_, "\n", + [this](std::string *out, auto decl) { + return absl::StrAppend(out, EmitDeclaration(decl)); + }); } absl::btree_set declarations_; diff --git a/src/ir/auth_logic/souffle_emitter_build_stub.cc b/src/ir/auth_logic/souffle_emitter_build_stub.cc index c3154becc..53c425e7c 100644 --- a/src/ir/auth_logic/souffle_emitter_build_stub.cc +++ b/src/ir/auth_logic/souffle_emitter_build_stub.cc @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Raksha Authors + * Copyright 2022 Google LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/ir/auth_logic/souffle_emitter_test.cc b/src/ir/auth_logic/souffle_emitter_test.cc index 9c788130a..f022beb04 100644 --- a/src/ir/auth_logic/souffle_emitter_test.cc +++ b/src/ir/auth_logic/souffle_emitter_test.cc @@ -242,7 +242,6 @@ grounded_dummy(dummy_var). R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). grounded_dummy(dummy_var). .output theTestQuery - .decl grounded_dummy(x0: symbol) .decl says_anything(x0: symbol, x1: symbol) .decl theTestQuery(x0: symbol))"; From 49047043d260fe6f5e53aa5846b00c1db3ee3bf1 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Wed, 9 Feb 2022 14:43:46 +0000 Subject: [PATCH 10/17] one more strjoin --- src/ir/auth_logic/souffle_emitter.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index de6870231..e7d634a66 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -101,12 +101,12 @@ class SouffleEmitter { } std::string EmitDeclaration(const Predicate& predicate) { - std::vector args_with_types; - for (auto elm : predicate.args()) { - args_with_types.push_back(absl::StrCat(elm, ": symbol")); - } + std::string arguments = absl::StrJoin(predicate.args(), ", ", + [](std::string *out, const std::string& arg) { + return absl::StrAppend(out, absl::StrCat(arg, ": symbol")); + }); return absl::StrCat(".decl ", predicate.name(), "(", - absl::StrJoin(args_with_types, ", "), ")"); + arguments, ")"); } std::string EmitDeclarations() { From 9d20cd2abae9e3fcca9c49c185d6338a1d47330c Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Wed, 9 Feb 2022 14:50:54 +0000 Subject: [PATCH 11/17] newline at end of output --- src/ir/auth_logic/ast.h | 5 +- src/ir/auth_logic/souffle_emitter.h | 30 +- src/ir/auth_logic/souffle_emitter_test.cc | 392 +++++++++++----------- 3 files changed, 212 insertions(+), 215 deletions(-) diff --git a/src/ir/auth_logic/ast.h b/src/ir/auth_logic/ast.h index df549e943..48fa3ca7d 100644 --- a/src/ir/auth_logic/ast.h +++ b/src/ir/auth_logic/ast.h @@ -53,12 +53,11 @@ class Predicate { const std::vector& args() const { return args_; } Sign sign() const { return sign_; } - // < operator is needed for btree_set, which is only used for declarations. // Since declarations are uniquely defined by the name of the predicate, - // this implementation that just uses < on the predicate names should be + // this implementation that just uses < on the predicate names should be // sufficent in the context where it is used. - bool operator< (const Predicate& otherPredicate) const { + bool operator<(const Predicate& otherPredicate) const { return this->name() < otherPredicate.name(); } diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index e7d634a66..997479ac4 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -32,13 +32,11 @@ class SouffleEmitter { std::string outputs = emitter.EmitOutputs(program); std::string decls = emitter.EmitDeclarations(); return absl::StrCat(std::move(body), "\n", std::move(outputs), "\n", - std::move(decls)); + std::move(decls), "\n"); } private: - SouffleEmitter() - : declarations_( - absl::btree_set()){}; + SouffleEmitter() : declarations_(absl::btree_set()){}; // This function produces a normalized version of predicates to // be used when generating declarations of the predicates. It replaces @@ -95,25 +93,25 @@ class SouffleEmitter { std::string EmitOutputs(const DLIRProgram& program) { return absl::StrJoin(program.outputs(), "\n", - [](std::string *out, const std::string& prog_out){ - return absl::StrAppend(out, absl::StrCat(".output ", prog_out)); - }); + [](std::string* out, const std::string& prog_out) { + return absl::StrAppend( + out, absl::StrCat(".output ", prog_out)); + }); } std::string EmitDeclaration(const Predicate& predicate) { - std::string arguments = absl::StrJoin(predicate.args(), ", ", - [](std::string *out, const std::string& arg) { - return absl::StrAppend(out, absl::StrCat(arg, ": symbol")); - }); - return absl::StrCat(".decl ", predicate.name(), "(", - arguments, ")"); + std::string arguments = absl::StrJoin( + predicate.args(), ", ", [](std::string* out, const std::string& arg) { + return absl::StrAppend(out, absl::StrCat(arg, ": symbol")); + }); + return absl::StrCat(".decl ", predicate.name(), "(", arguments, ")"); } std::string EmitDeclarations() { return absl::StrJoin(declarations_, "\n", - [this](std::string *out, auto decl) { - return absl::StrAppend(out, EmitDeclaration(decl)); - }); + [this](std::string* out, auto decl) { + return absl::StrAppend(out, EmitDeclaration(decl)); + }); } absl::btree_set declarations_; diff --git a/src/ir/auth_logic/souffle_emitter_test.cc b/src/ir/auth_logic/souffle_emitter_test.cc index f022beb04..b5947d3af 100644 --- a/src/ir/auth_logic/souffle_emitter_test.cc +++ b/src/ir/auth_logic/souffle_emitter_test.cc @@ -14,141 +14,140 @@ * limitations under the License. */ +#include "src/ir/auth_logic/souffle_emitter.h" + #include "src/common/testing/gtest.h" #include "src/ir/auth_logic/ast.h" #include "src/ir/auth_logic/datalog_ir.h" #include "src/ir/auth_logic/lowering_ast_datalog.h" -#include "src/ir/auth_logic/souffle_emitter.h" #include "src/ir/auth_logic/move_append.h" namespace raksha::ir::auth_logic { - Program BuildSingleAssertionProgram(SaysAssertion assertion) { - std::vector assertion_list = {}; - assertion_list.push_back(std::move(assertion)); - return Program(std::move(assertion_list), {}); - } - - SaysAssertion BuildSingleSaysAssertion(Principal speaker, Assertion assertion) { - std::vector assertion_list = {}; - assertion_list.push_back(std::move(assertion)); - return SaysAssertion(std::move(speaker), std::move(assertion_list)); - } - - Program BuildPredicateTestProgram() { - return BuildSingleAssertionProgram(BuildSingleSaysAssertion( - Principal("TestPrincipal"), Assertion(Fact(BaseFact( - Predicate("foo", {"bar", "baz"}, kPositive)))))); - } - - TEST(EmitterTestSuite, SimpleTest) { - std::string expected = -R"(says_foo(TestPrincipal, bar, baz). +Program BuildSingleAssertionProgram(SaysAssertion assertion) { + std::vector assertion_list = {}; + assertion_list.push_back(std::move(assertion)); + return Program(std::move(assertion_list), {}); +} + +SaysAssertion BuildSingleSaysAssertion(Principal speaker, Assertion assertion) { + std::vector assertion_list = {}; + assertion_list.push_back(std::move(assertion)); + return SaysAssertion(std::move(speaker), std::move(assertion_list)); +} + +Program BuildPredicateTestProgram() { + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestPrincipal"), + Assertion(Fact(BaseFact(Predicate("foo", {"bar", "baz"}, kPositive)))))); +} + +TEST(EmitterTestSuite, SimpleTest) { + std::string expected = + R"(says_foo(TestPrincipal, bar, baz). grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) -.decl says_foo(x0: symbol, x1: symbol, x2: symbol))"; - - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildPredicateTestProgram())); - - EXPECT_EQ(actual, expected); - } - - Program BuildAttributeTestProgram() { - return BuildSingleAssertionProgram( - BuildSingleSaysAssertion(Principal("TestSpeaker"), - Assertion(Fact(BaseFact( - Attribute(Principal("OtherTestPrincipal"), - Predicate("hasProperty", {"wellTested"}, kPositive))))) - )); - } - - TEST(EmitterTestSuite, AttributeTest) { - std::string expected = -R"(says_hasProperty(TestSpeaker, x__1, wellTested) :- says_canActAs(TestSpeaker, x__1, OtherTestPrincipal), says_hasProperty(TestSpeaker, OtherTestPrincipal, wellTested). +.decl says_foo(x0: symbol, x1: symbol, x2: symbol) +)"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildPredicateTestProgram())); + + EXPECT_EQ(actual, expected); +} + +Program BuildAttributeTestProgram() { + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestSpeaker"), + Assertion(Fact(BaseFact( + Attribute(Principal("OtherTestPrincipal"), + Predicate("hasProperty", {"wellTested"}, kPositive))))))); +} + +TEST(EmitterTestSuite, AttributeTest) { + std::string expected = + R"(says_hasProperty(TestSpeaker, x__1, wellTested) :- says_canActAs(TestSpeaker, x__1, OtherTestPrincipal), says_hasProperty(TestSpeaker, OtherTestPrincipal, wellTested). says_hasProperty(TestSpeaker, OtherTestPrincipal, wellTested). grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) .decl says_canActAs(x0: symbol, x1: symbol, x2: symbol) -.decl says_hasProperty(x0: symbol, x1: symbol, x2: symbol))"; +.decl says_hasProperty(x0: symbol, x1: symbol, x2: symbol) +)"; - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildAttributeTestProgram())); + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildAttributeTestProgram())); - EXPECT_EQ(actual, expected); - } + EXPECT_EQ(actual, expected); +} - Program BuildCanActAsProgram() { - return BuildSingleAssertionProgram( - BuildSingleSaysAssertion(Principal("TestSpeaker"), - Assertion(Fact(BaseFact( - CanActAs(Principal("PrincipalA"), Principal("PrincipalB"))))) - )); - } +Program BuildCanActAsProgram() { + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestSpeaker"), + Assertion(Fact(BaseFact( + CanActAs(Principal("PrincipalA"), Principal("PrincipalB"))))))); +} - TEST(EmitterTestSuite, CanActAsTest) { - std::string expected = -R"(says_canActAs(TestSpeaker, x__1, PrincipalB) :- says_canActAs(TestSpeaker, x__1, PrincipalA), says_canActAs(TestSpeaker, PrincipalA, PrincipalB). +TEST(EmitterTestSuite, CanActAsTest) { + std::string expected = + R"(says_canActAs(TestSpeaker, x__1, PrincipalB) :- says_canActAs(TestSpeaker, x__1, PrincipalA), says_canActAs(TestSpeaker, PrincipalA, PrincipalB). says_canActAs(TestSpeaker, PrincipalA, PrincipalB). grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) -.decl says_canActAs(x0: symbol, x1: symbol, x2: symbol))"; - - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildCanActAsProgram())); - - EXPECT_EQ(actual, expected); - } - - Program BuildCanSayProgram() { - std::unique_ptr inner_fact = std::unique_ptr( - new Fact(BaseFact(Predicate("grantAccess", - {"secretFile"}, kPositive)))); - Fact::FactVariantType cansay_fact = std::unique_ptr( - new CanSay(Principal("PrincipalA"), inner_fact)); - return BuildSingleAssertionProgram( - BuildSingleSaysAssertion(Principal("TestSpeaker"), - Assertion(Fact(std::move(cansay_fact))))); - } - - TEST(EmitterTestSuite, CanSayTest) { - std::string expected = -R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFile), says_canSay_grantAccess(TestSpeaker, x__1, secretFile). +.decl says_canActAs(x0: symbol, x1: symbol, x2: symbol) +)"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildCanActAsProgram())); + + EXPECT_EQ(actual, expected); +} + +Program BuildCanSayProgram() { + std::unique_ptr inner_fact = std::unique_ptr( + new Fact(BaseFact(Predicate("grantAccess", {"secretFile"}, kPositive)))); + Fact::FactVariantType cansay_fact = + std::unique_ptr(new CanSay(Principal("PrincipalA"), inner_fact)); + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestSpeaker"), Assertion(Fact(std::move(cansay_fact))))); +} + +TEST(EmitterTestSuite, CanSayTest) { + std::string expected = + R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFile), says_canSay_grantAccess(TestSpeaker, x__1, secretFile). says_canSay_grantAccess(TestSpeaker, PrincipalA, secretFile). grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) .decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol) -.decl says_grantAccess(x0: symbol, x1: symbol))"; - - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildCanSayProgram())); - - EXPECT_EQ(actual, expected); - } - - Program BuildDoubleCanSayProgram() { - // So much fun with unique pointers! - std::unique_ptr inner_fact = std::unique_ptr( - new Fact(BaseFact(Predicate("grantAccess", - {"secretFile"}, kPositive)))); - Fact::FactVariantType inner_cansay = std::unique_ptr( - new CanSay(Principal("PrincipalA"), inner_fact)); - std::unique_ptr inner_cansay_fact = std::unique_ptr( - new Fact(std::move(inner_cansay))); - Fact::FactVariantType cansay_fact = std::unique_ptr( - new CanSay(Principal("PrincipalB"), inner_cansay_fact)); - return BuildSingleAssertionProgram( - BuildSingleSaysAssertion(Principal("TestSpeaker"), - Assertion(Fact(std::move(cansay_fact))))); - } - - TEST(EmitterTestSuite, DoubleCanSayTest) { - std::string expected = -R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFile), says_canSay_grantAccess(TestSpeaker, x__1, secretFile). +.decl says_grantAccess(x0: symbol, x1: symbol) +)"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildCanSayProgram())); + + EXPECT_EQ(actual, expected); +} + +Program BuildDoubleCanSayProgram() { + // So much fun with unique pointers! + std::unique_ptr inner_fact = std::unique_ptr( + new Fact(BaseFact(Predicate("grantAccess", {"secretFile"}, kPositive)))); + Fact::FactVariantType inner_cansay = + std::unique_ptr(new CanSay(Principal("PrincipalA"), inner_fact)); + std::unique_ptr inner_cansay_fact = + std::unique_ptr(new Fact(std::move(inner_cansay))); + Fact::FactVariantType cansay_fact = std::unique_ptr( + new CanSay(Principal("PrincipalB"), inner_cansay_fact)); + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestSpeaker"), Assertion(Fact(std::move(cansay_fact))))); +} + +TEST(EmitterTestSuite, DoubleCanSayTest) { + std::string expected = + R"(says_grantAccess(TestSpeaker, secretFile) :- says_grantAccess(x__1, secretFile), says_canSay_grantAccess(TestSpeaker, x__1, secretFile). says_canSay_grantAccess(TestSpeaker, PrincipalA, secretFile) :- says_canSay_grantAccess(x__2, PrincipalA, secretFile), says_canSay_canSay_grantAccess(TestSpeaker, x__2, PrincipalA, secretFile). says_canSay_canSay_grantAccess(TestSpeaker, PrincipalB, PrincipalA, secretFile). grounded_dummy(dummy_var). @@ -156,107 +155,108 @@ grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) .decl says_canSay_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol, x3: symbol) .decl says_canSay_grantAccess(x0: symbol, x1: symbol, x2: symbol) -.decl says_grantAccess(x0: symbol, x1: symbol))"; - - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildDoubleCanSayProgram())); - - EXPECT_EQ(actual, expected); - } - - Program BuildConditionalProgram() { - std::vector rhs = {BaseFact(Predicate( - "isEmployee", {"somePerson"}, kPositive))}; - Fact lhs(BaseFact(Predicate("canAccess", {"somePerson", "someFile"}, - kPositive))); - return BuildSingleAssertionProgram( - BuildSingleSaysAssertion(Principal("TestSpeaker"), - Assertion(ConditionalAssertion(std::move(lhs), std::move(rhs))))); - } - - TEST(EmitterTestSuite, ConditionalProgramTest) { - std::string expected = -R"(says_canAccess(TestSpeaker, somePerson, someFile) :- says_isEmployee(TestSpeaker, somePerson). +.decl says_grantAccess(x0: symbol, x1: symbol) +)"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildDoubleCanSayProgram())); + + EXPECT_EQ(actual, expected); +} + +Program BuildConditionalProgram() { + std::vector rhs = { + BaseFact(Predicate("isEmployee", {"somePerson"}, kPositive))}; + Fact lhs( + BaseFact(Predicate("canAccess", {"somePerson", "someFile"}, kPositive))); + return BuildSingleAssertionProgram(BuildSingleSaysAssertion( + Principal("TestSpeaker"), + Assertion(ConditionalAssertion(std::move(lhs), std::move(rhs))))); +} + +TEST(EmitterTestSuite, ConditionalProgramTest) { + std::string expected = + R"(says_canAccess(TestSpeaker, somePerson, someFile) :- says_isEmployee(TestSpeaker, somePerson). grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) .decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) -.decl says_isEmployee(x0: symbol, x1: symbol))"; - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildConditionalProgram())); - EXPECT_EQ(actual, expected); - } - - Program BuildMultiAssertionProgram() { - // Conditional Assertion - std::vector rhs = {BaseFact(Predicate( - "isEmployee", {"somePerson"}, kPositive))}; - Fact lhs(BaseFact(Predicate("canAccess", {"somePerson", "someFile"}, - kPositive))); - SaysAssertion condAssertion = BuildSingleSaysAssertion( - Principal("TestPrincipal"), - Assertion(ConditionalAssertion(std::move(lhs), - std::move(rhs)))); - - // Assertion stating the condition - SaysAssertion predicateAssertion = BuildSingleSaysAssertion( - Principal("TestPrincipal"), - Assertion(Fact(BaseFact( - Predicate("isEmployee", {"somePerson"}, - kPositive)))) - ); - - // I would love to just write this: - // return Program({std::move(condAssertion), - // std::move(predicateAssertion)}, {}); - - std::vector assertion_list = {}; - assertion_list.push_back(std::move(condAssertion)); - assertion_list.push_back(std::move(predicateAssertion)); - return Program(std::move(assertion_list), {}); - } - - TEST(EmitterTestSuite, MultiAssertionProgramTest) { - std::string expected = R"(says_canAccess(TestPrincipal, somePerson, someFile) :- says_isEmployee(TestPrincipal, somePerson). +.decl says_isEmployee(x0: symbol, x1: symbol) +)"; + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildConditionalProgram())); + EXPECT_EQ(actual, expected); +} + +Program BuildMultiAssertionProgram() { + // Conditional Assertion + std::vector rhs = { + BaseFact(Predicate("isEmployee", {"somePerson"}, kPositive))}; + Fact lhs( + BaseFact(Predicate("canAccess", {"somePerson", "someFile"}, kPositive))); + SaysAssertion condAssertion = BuildSingleSaysAssertion( + Principal("TestPrincipal"), + Assertion(ConditionalAssertion(std::move(lhs), std::move(rhs)))); + + // Assertion stating the condition + SaysAssertion predicateAssertion = BuildSingleSaysAssertion( + Principal("TestPrincipal"), + Assertion( + Fact(BaseFact(Predicate("isEmployee", {"somePerson"}, kPositive))))); + + // I would love to just write this: + // return Program({std::move(condAssertion), + // std::move(predicateAssertion)}, {}); + + std::vector assertion_list = {}; + assertion_list.push_back(std::move(condAssertion)); + assertion_list.push_back(std::move(predicateAssertion)); + return Program(std::move(assertion_list), {}); +} + +TEST(EmitterTestSuite, MultiAssertionProgramTest) { + std::string expected = + R"(says_canAccess(TestPrincipal, somePerson, someFile) :- says_isEmployee(TestPrincipal, somePerson). says_isEmployee(TestPrincipal, somePerson). grounded_dummy(dummy_var). .decl grounded_dummy(x0: symbol) .decl says_canAccess(x0: symbol, x1: symbol, x2: symbol) -.decl says_isEmployee(x0: symbol, x1: symbol))"; - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildMultiAssertionProgram())); - EXPECT_EQ(actual, expected); - } - - Program BuildQueryProgram() { - Query testQuery("theTestQuery", Principal("TestSpeaker"), - Fact(BaseFact(Predicate("anything", {"atAll"}, kPositive)))); - std::vector query_list = {}; - query_list.push_back(std::move(testQuery)); - return Program({}, std::move(query_list)); - } - - TEST(EmitterTestSuite, QueryTestProgram) { - std::string expected = -R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). +.decl says_isEmployee(x0: symbol, x1: symbol) +)"; + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildMultiAssertionProgram())); + EXPECT_EQ(actual, expected); +} + +Program BuildQueryProgram() { + Query testQuery("theTestQuery", Principal("TestSpeaker"), + Fact(BaseFact(Predicate("anything", {"atAll"}, kPositive)))); + std::vector query_list = {}; + query_list.push_back(std::move(testQuery)); + return Program({}, std::move(query_list)); +} + +TEST(EmitterTestSuite, QueryTestProgram) { + std::string expected = + R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). grounded_dummy(dummy_var). .output theTestQuery .decl grounded_dummy(x0: symbol) .decl says_anything(x0: symbol, x1: symbol) -.decl theTestQuery(x0: symbol))"; - -// R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), grounded_dummy(dummy_var). -// grounded_dummy(dummy_var). -// .output theTestQuery -// -// .decl theTestQuery(x0: symbol) -// .decl says_anything(x0: symbol, x1: symbol) -// .decl grounded_dummy(x0: symbol))"; - - std::string actual = SouffleEmitter::EmitProgram( - LoweringToDatalogPass::Lower(BuildQueryProgram())); - EXPECT_EQ(actual, expected); - } - +.decl theTestQuery(x0: symbol) +)"; + + // R"(theTestQuery(dummy_var) :- says_anything(TestSpeaker, atAll), + // grounded_dummy(dummy_var). grounded_dummy(dummy_var). .output theTestQuery + // + // .decl theTestQuery(x0: symbol) + // .decl says_anything(x0: symbol, x1: symbol) + // .decl grounded_dummy(x0: symbol))"; + + std::string actual = SouffleEmitter::EmitProgram( + LoweringToDatalogPass::Lower(BuildQueryProgram())); + EXPECT_EQ(actual, expected); } + +} // namespace raksha::ir::auth_logic From f31708176c38a4ed62b6cf850568c1c04556bba4 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Wed, 9 Feb 2022 14:51:52 +0000 Subject: [PATCH 12/17] bazel lint --- src/ir/auth_logic/BUILD | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index d7ac245ac..32d4390d1 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -28,8 +28,8 @@ cc_library( deps = [ "//src/common/logging", "//src/utils:overloaded", + "@absl//absl/hash", "@absl//absl/strings:str_format", - "@absl//absl/hash:hash", ], ) @@ -74,7 +74,6 @@ cc_test( ], ) - cc_test( name = "ast_test", srcs = ["ast_test.cc"], From 3067ef8437f9cdb7df1c180ff4a41c47669b8e1e Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Thu, 10 Feb 2022 12:53:31 +0000 Subject: [PATCH 13/17] Make CanActAs not member again --- src/ir/auth_logic/lowering_ast_datalog.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ir/auth_logic/lowering_ast_datalog.h b/src/ir/auth_logic/lowering_ast_datalog.h index cd984274b..ea331762a 100644 --- a/src/ir/auth_logic/lowering_ast_datalog.h +++ b/src/ir/auth_logic/lowering_ast_datalog.h @@ -156,8 +156,6 @@ class LoweringToDatalogPass { DLIRAssertion SpokenAttributeToDLIR(const Principal& speaker, const Attribute& attribute); - Predicate CanActAsToDLIR(const CanActAs& can_act_as); - // In the same way that attributes are passed around with "CanActAs", so // are other "CanActAs" facts. To implement this, the translation of // CanActAs also results in both a predicate and an extra rule that passes From ecd6007e70f654e46291adde9fdd72ae4dc14113 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Thu, 10 Feb 2022 14:56:31 +0000 Subject: [PATCH 14/17] PR fixup --- src/ir/auth_logic/souffle_emitter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index 997479ac4..de330a088 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -36,7 +36,7 @@ class SouffleEmitter { } private: - SouffleEmitter() : declarations_(absl::btree_set()){}; + SouffleEmitter() = default; // This function produces a normalized version of predicates to // be used when generating declarations of the predicates. It replaces From 5864064539202e2bbb3fd4f69e234ea8e456db84 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Thu, 10 Feb 2022 15:22:20 +0000 Subject: [PATCH 15/17] Use flat_hash_set --- src/ir/auth_logic/BUILD | 2 +- src/ir/auth_logic/ast.h | 29 ++++++++++++++++++++++++++--- src/ir/auth_logic/souffle_emitter.h | 10 +++++++--- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index 32d4390d1..3bdcb0f39 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -60,7 +60,7 @@ cc_library( deps = [ "//src/ir/auth_logic:ast", "//src/ir/auth_logic:lowering_ast_datalog", - "@absl//absl/container:btree", + "@absl//absl/container:flat_hash_set", "@absl//absl/strings", ], ) diff --git a/src/ir/auth_logic/ast.h b/src/ir/auth_logic/ast.h index 48fa3ca7d..255e26e1a 100644 --- a/src/ir/auth_logic/ast.h +++ b/src/ir/auth_logic/ast.h @@ -24,6 +24,8 @@ #include #include +#include "absl/hash/hash.h" + namespace raksha::ir::auth_logic { class Principal { @@ -53,13 +55,34 @@ class Predicate { const std::vector& args() const { return args_; } Sign sign() const { return sign_; } + template + friend H AbslHashValue(H h, const Predicate& p) { + return H::combine(std::move(h), p.name(), p.args(), p.sign()); + } + // Equality is also needed to use a Predicate in a flat_hash_set + bool operator==(const Predicate& otherPredicate) const { + if (this->name() != otherPredicate.name()) { + return false; + } + if (this->sign() != otherPredicate.sign()) { + return false; + } + if (this->args().size() != otherPredicate.args().size()) { + return false; + } + for (int i = 0; i < this->args().size(); i++) { + if (this->args().at(i) != otherPredicate.args().at(i)) return false; + } + return true; + } + // < operator is needed for btree_set, which is only used for declarations. // Since declarations are uniquely defined by the name of the predicate, - // this implementation that just uses < on the predicate names should be + // this implementation that just uses < on the predicate names should be // sufficent in the context where it is used. - bool operator<(const Predicate& otherPredicate) const { + bool operator< (const Predicate& otherPredicate) const { return this->name() < otherPredicate.name(); - } + } private: std::string name_; diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index de330a088..4257c0f1e 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -17,7 +17,7 @@ #ifndef SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ #define SRC_IR_AUTH_LOGIC_SOUFFLE_EMITTER_H_ -#include "absl/container/btree_set.h" +#include "absl/container/flat_hash_set.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "src/ir/auth_logic/datalog_ir.h" @@ -108,13 +108,17 @@ class SouffleEmitter { } std::string EmitDeclarations() { - return absl::StrJoin(declarations_, "\n", + std::vector elements_vec( + std::make_move_iterator(declarations_.begin()), + std::make_move_iterator(declarations_.end())); + std::sort(elements_vec.begin(), elements_vec.end()); + return absl::StrJoin(elements_vec, "\n", [this](std::string* out, auto decl) { return absl::StrAppend(out, EmitDeclaration(decl)); }); } - absl::btree_set declarations_; + absl::flat_hash_set declarations_; }; } // namespace raksha::ir::auth_logic From bbb6cca86b3fda1751ab10ffe77f6f50d0ea2c16 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Fri, 11 Feb 2022 13:05:47 +0000 Subject: [PATCH 16/17] PR Fixup --- src/ir/auth_logic/BUILD | 9 ++++ src/ir/auth_logic/ast.h | 12 ++--- src/ir/auth_logic/ast_equality_test.cc | 64 +++++++++++++++++++++++ src/ir/auth_logic/lowering_ast_datalog.cc | 14 +++-- src/ir/auth_logic/souffle_emitter.h | 39 +++++++------- 5 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 src/ir/auth_logic/ast_equality_test.cc diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index 3bdcb0f39..18994aba4 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -33,6 +33,15 @@ cc_library( ], ) +cc_test( + name = "ast_equality_test", + srcs = ["ast_equality_test.cc"], + deps = [ + ":ast", + "//src/common/testing:gtest", + ], +) + cc_library( name = "lowering_ast_datalog", srcs = ["lowering_ast_datalog.cc"], diff --git a/src/ir/auth_logic/ast.h b/src/ir/auth_logic/ast.h index 255e26e1a..e43913ed5 100644 --- a/src/ir/auth_logic/ast.h +++ b/src/ir/auth_logic/ast.h @@ -59,13 +59,13 @@ class Predicate { friend H AbslHashValue(H h, const Predicate& p) { return H::combine(std::move(h), p.name(), p.args(), p.sign()); } - // Equality is also needed to use a Predicate in a flat_hash_set + // Equality is also needed to use a Predicate in a flat_hash_set bool operator==(const Predicate& otherPredicate) const { if (this->name() != otherPredicate.name()) { - return false; + return false; } if (this->sign() != otherPredicate.sign()) { - return false; + return false; } if (this->args().size() != otherPredicate.args().size()) { return false; @@ -78,11 +78,11 @@ class Predicate { // < operator is needed for btree_set, which is only used for declarations. // Since declarations are uniquely defined by the name of the predicate, - // this implementation that just uses < on the predicate names should be + // this implementation that just uses < on the predicate names should be // sufficent in the context where it is used. - bool operator< (const Predicate& otherPredicate) const { + bool operator<(const Predicate& otherPredicate) const { return this->name() < otherPredicate.name(); - } + } private: std::string name_; diff --git a/src/ir/auth_logic/ast_equality_test.cc b/src/ir/auth_logic/ast_equality_test.cc new file mode 100644 index 000000000..d78c44184 --- /dev/null +++ b/src/ir/auth_logic/ast_equality_test.cc @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------- + +#include "src/common/testing/gtest.h" +#include "src/ir/auth_logic/ast.h" + +namespace raksha::ir::auth_logic { + +TEST(AstEqualityTestSuite, Test1) { + Predicate p1("foo", {"bar", "baz"}, kPositive); + Predicate p2("foo", {"bar", "baz"}, kPositive); + EXPECT_TRUE(p1 == p2); +} + +TEST(AstEqualityTestSuite, Test2) { + Predicate p1("foo", {"bar", "baz"}, kPositive); + Predicate p2("food", {"bar", "baz"}, kPositive); + EXPECT_TRUE(!(p1 == p2)); +} + +TEST(AstEqualityTestSuite, Test3) { + Predicate p1("foo", {"bar", "baz"}, kPositive); + Predicate p2("foo", {"baz", "bar"}, kPositive); + EXPECT_TRUE(!(p1 == p2)); +} + +TEST(AstEqualityTestSuite, Test4) { + Predicate p1("foo", {"barrrrr", "baz"}, kPositive); + Predicate p2("foo", {"bar", "baz"}, kPositive); + EXPECT_TRUE(!(p1 == p2)); +} + +TEST(AstEqualityTestSuite, Test5) { + Predicate p1("foo", {"bar", "baz"}, kPositive); + Predicate p2("foo", {"bar", "bas"}, kPositive); + EXPECT_TRUE(!(p1 == p2)); +} + +TEST(AstEqualityTestSuite, Test6) { + Predicate p1("foo", {"bar", "baz"}, kPositive); + Predicate p2("foo", {"bar", "baz"}, kNegated); + EXPECT_TRUE(!(p1 == p2)); +} + +TEST(AstEqualityTestSuite, Test7) { + Predicate p1("foo", {"bar", "baz"}, kPositive); + Predicate p2("foo", {"bar", "baz", "beef"}, kPositive); + EXPECT_TRUE(!(p1 == p2)); +} + +} // namespace raksha::ir::auth_logic diff --git a/src/ir/auth_logic/lowering_ast_datalog.cc b/src/ir/auth_logic/lowering_ast_datalog.cc index 8a04cd2fc..84529058f 100644 --- a/src/ir/auth_logic/lowering_ast_datalog.cc +++ b/src/ir/auth_logic/lowering_ast_datalog.cc @@ -66,7 +66,6 @@ Predicate CanActAsToDLIR(const CanActAs& can_act_as) { DLIRAssertion LoweringToDatalogPass::SpokenAttributeToDLIR( const Principal& speaker, const Attribute& attribute) { - // Attributes interact with "canActAs" because if "Y canActAs X" // then Y also picks up X's attributes. We need to generate // an additional rule to implement this behavior. If the attribute @@ -81,8 +80,8 @@ DLIRAssertion LoweringToDatalogPass::SpokenAttributeToDLIR( Predicate generated_lhs = PushPrincipal("says_", speaker, y_predX); // This is `speaker says Y canActAs X` - Predicate y_can_act_as_x = CanActAsToDLIR(CanActAs(prin_y, - attribute.principal())); + Predicate y_can_act_as_x = + CanActAsToDLIR(CanActAs(prin_y, attribute.principal())); Predicate speaker_says_y_can_act_as_x = PushPrincipal("says_", speaker, y_can_act_as_x); @@ -101,7 +100,6 @@ DLIRAssertion LoweringToDatalogPass::SpokenAttributeToDLIR( DLIRAssertion LoweringToDatalogPass::SpokenCanActAsToDLIR( const Principal& speaker, const CanActAs& can_act_as) { - // "canActAs" facts are passed to principals via other canActAs facts in // essentially the same way as attributes. This function adds extra // rules to pass these around. If the `canActAs` under translation @@ -112,13 +110,13 @@ DLIRAssertion LoweringToDatalogPass::SpokenCanActAsToDLIR( Principal prin_y(FreshVar()); // This is `speaker says Y canActAs Z` - Predicate y_can_act_as_z = CanActAsToDLIR(CanActAs(prin_y, - can_act_as.right_principal())); + Predicate y_can_act_as_z = + CanActAsToDLIR(CanActAs(prin_y, can_act_as.right_principal())); Predicate generated_lhs = PushPrincipal("says_", speaker, y_can_act_as_z); // This is `speaker says Y canActAs X` - Predicate y_can_act_as_x = CanActAsToDLIR(CanActAs(prin_y, - can_act_as.left_principal())); + Predicate y_can_act_as_x = + CanActAsToDLIR(CanActAs(prin_y, can_act_as.left_principal())); Predicate speaker_says_y_can_act_as_x = PushPrincipal("says_", speaker, y_can_act_as_x); diff --git a/src/ir/auth_logic/souffle_emitter.h b/src/ir/auth_logic/souffle_emitter.h index 4257c0f1e..fc6941e6c 100644 --- a/src/ir/auth_logic/souffle_emitter.h +++ b/src/ir/auth_logic/souffle_emitter.h @@ -21,6 +21,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "src/ir/auth_logic/datalog_ir.h" +#include "src/ir/auth_logic/map_iter.h" namespace raksha::ir::auth_logic { @@ -48,11 +49,14 @@ class SouffleEmitter { // To prevent instances of negated and non-negated uses of the predicate // from generating two declarations, the sign here is always positive. Predicate PredToDeclaration(const Predicate& predicate) { - std::vector decl_args; - for (int i = 0; i < predicate.args().size(); i++) { - decl_args.push_back(absl::StrCat("x", std::to_string(i))); - } - return Predicate(predicate.name(), decl_args, kPositive); + int i = 0; + return Predicate(predicate.name(), + MapIter( + predicate.args(), + [i](const std::string& arg) mutable { + return absl::StrCat("x", std::to_string(i++)); + }), + kPositive); } std::string EmitPredicate(const Predicate& predicate) { @@ -69,12 +73,10 @@ class SouffleEmitter { } std::string EmitAssertionInner(const DLIRCondAssertion& cond_assertion) { - std::string lhs = EmitPredicate(cond_assertion.lhs()); - std::vector rhs_translated; - for (auto arg : cond_assertion.rhs()) { - rhs_translated.push_back(EmitPredicate(arg)); - } - return absl::StrCat(std::move(lhs), " :- ", + std::vector rhs_translated = MapIter( + cond_assertion.rhs(), + [this](const Predicate& arg) { return EmitPredicate(arg); }); + return absl::StrCat(EmitPredicate(cond_assertion.lhs()), " :- ", absl::StrJoin(rhs_translated, ", "), "."); } @@ -84,11 +86,11 @@ class SouffleEmitter { } std::string EmitProgramBody(const DLIRProgram& program) { - std::vector body_translated; - for (auto assertion : program.assertions()) { - body_translated.push_back(EmitAssertion(assertion)); - } - return absl::StrJoin(body_translated, "\n"); + return absl::StrJoin( + MapIter( + program.assertions(), + [this](const DLIRAssertion& astn) { return EmitAssertion(astn); }), + "\n"); } std::string EmitOutputs(const DLIRProgram& program) { @@ -108,9 +110,8 @@ class SouffleEmitter { } std::string EmitDeclarations() { - std::vector elements_vec( - std::make_move_iterator(declarations_.begin()), - std::make_move_iterator(declarations_.end())); + std::vector elements_vec(std::make_move_iterator(declarations_.begin()), + std::make_move_iterator(declarations_.end())); std::sort(elements_vec.begin(), elements_vec.end()); return absl::StrJoin(elements_vec, "\n", [this](std::string* out, auto decl) { From df5e0bff7ad6d676d5bba51210499f19726a96c3 Mon Sep 17 00:00:00 2001 From: Andrew Ferraiuolo Date: Fri, 11 Feb 2022 16:49:40 +0000 Subject: [PATCH 17/17] PR fixes --- src/ir/auth_logic/BUILD | 4 ++-- .../{ast_equality_test.cc => predicate_test.cc} | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) rename src/ir/auth_logic/{ast_equality_test.cc => predicate_test.cc} (78%) diff --git a/src/ir/auth_logic/BUILD b/src/ir/auth_logic/BUILD index 18994aba4..4dac30002 100644 --- a/src/ir/auth_logic/BUILD +++ b/src/ir/auth_logic/BUILD @@ -34,8 +34,8 @@ cc_library( ) cc_test( - name = "ast_equality_test", - srcs = ["ast_equality_test.cc"], + name = "predicate_test", + srcs = ["predicate_test.cc"], deps = [ ":ast", "//src/common/testing:gtest", diff --git a/src/ir/auth_logic/ast_equality_test.cc b/src/ir/auth_logic/predicate_test.cc similarity index 78% rename from src/ir/auth_logic/ast_equality_test.cc rename to src/ir/auth_logic/predicate_test.cc index d78c44184..483bf9e2c 100644 --- a/src/ir/auth_logic/ast_equality_test.cc +++ b/src/ir/auth_logic/predicate_test.cc @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// Copyright 2021 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,43 +19,44 @@ namespace raksha::ir::auth_logic { -TEST(AstEqualityTestSuite, Test1) { +TEST(PredicateTest, EqualReturnsForIdenticalPredicates) { Predicate p1("foo", {"bar", "baz"}, kPositive); Predicate p2("foo", {"bar", "baz"}, kPositive); EXPECT_TRUE(p1 == p2); } -TEST(AstEqualityTestSuite, Test2) { +TEST(PredicateTest, UnequalReturnsForDifferntPredicateNames) { Predicate p1("foo", {"bar", "baz"}, kPositive); Predicate p2("food", {"bar", "baz"}, kPositive); EXPECT_TRUE(!(p1 == p2)); } -TEST(AstEqualityTestSuite, Test3) { +TEST(PredicateTest, UnequalReturnsForDifferentlyOrderedParameters) { Predicate p1("foo", {"bar", "baz"}, kPositive); Predicate p2("foo", {"baz", "bar"}, kPositive); EXPECT_TRUE(!(p1 == p2)); } -TEST(AstEqualityTestSuite, Test4) { +TEST(PredicateTest, UnequalReturnsForDifferentParameterNames) { Predicate p1("foo", {"barrrrr", "baz"}, kPositive); Predicate p2("foo", {"bar", "baz"}, kPositive); EXPECT_TRUE(!(p1 == p2)); } -TEST(AstEqualityTestSuite, Test5) { +TEST(PredicateTest, + UnequalReturnsForDifferentParameterNamesInDifferentPosition) { Predicate p1("foo", {"bar", "baz"}, kPositive); Predicate p2("foo", {"bar", "bas"}, kPositive); EXPECT_TRUE(!(p1 == p2)); } -TEST(AstEqualityTestSuite, Test6) { +TEST(PredicateTest, UnequalReturnsForDifferentPolarity) { Predicate p1("foo", {"bar", "baz"}, kPositive); Predicate p2("foo", {"bar", "baz"}, kNegated); EXPECT_TRUE(!(p1 == p2)); } -TEST(AstEqualityTestSuite, Test7) { +TEST(PredicateTest, UnequalReturnsForPrefixingUnequalParameterList) { Predicate p1("foo", {"bar", "baz"}, kPositive); Predicate p2("foo", {"bar", "baz", "beef"}, kPositive); EXPECT_TRUE(!(p1 == p2));