1 #include <iostream>
2 #include <memory>
3 #include <string>
4 #include <vector>
5 
6 #include <android-base/file.h>
7 #include <property_info_parser/property_info_parser.h>
8 #include <property_info_serializer/property_info_serializer.h>
9 #include <sepol/context.h>
10 #include <sepol/context_record.h>
11 #include <sepol/handle.h>
12 #include <sepol/policydb.h>
13 #include <sepol/policydb/policydb.h>
14 
15 using android::base::ReadFileToString;
16 using android::properties::BuildTrie;
17 using android::properties::ParsePropertyInfoFile;
18 using android::properties::PropertyInfoArea;
19 using android::properties::PropertyInfoEntry;
20 
21 class ContextChecker {
22  public:
ContextChecker()23   ContextChecker()
24       : policy_file_(nullptr),
25         sepol_handle_(nullptr),
26         sepol_policy_file_(nullptr),
27         sepol_policy_db_(nullptr) {}
28 
~ContextChecker()29   ~ContextChecker() {
30     if (sepol_policy_db_ != nullptr) {
31       sepol_policydb_free(sepol_policy_db_);
32     }
33 
34     if (sepol_policy_file_ != nullptr) {
35       sepol_policy_file_free(sepol_policy_file_);
36     }
37 
38     if (sepol_handle_ != nullptr) {
39       sepol_handle_destroy(sepol_handle_);
40     }
41 
42     if (policy_file_ != nullptr) {
43       fclose(policy_file_);
44     }
45   }
46 
Initialize(const char * policy_file)47   bool Initialize(const char* policy_file) {
48     policy_file_ = fopen(policy_file, "re");
49     if (policy_file_ == nullptr) {
50       std::cerr << "Could not open policy file, " << policy_file << std::endl;
51       return false;
52     }
53 
54     sepol_handle_ = sepol_handle_create();
55     if (sepol_handle_ == nullptr) {
56       std::cerr << "Could not create policy handle." << std::endl;
57       return false;
58     }
59 
60     if (sepol_policy_file_create(&sepol_policy_file_) < 0) {
61       std::cerr << "Could not create policy file." << std::endl;
62       return false;
63     }
64 
65     if (sepol_policydb_create(&sepol_policy_db_) < 0) {
66       std::cerr << "Could not create policy db." << std::endl;
67       return false;
68     }
69 
70     sepol_policy_file_set_fp(sepol_policy_file_, policy_file_);
71     sepol_policy_file_set_handle(sepol_policy_file_, sepol_handle_);
72 
73     if (sepol_policydb_read(sepol_policy_db_, sepol_policy_file_) < 0) {
74       std::cerr << "Could not read policy file into policy db." << std::endl;
75       return false;
76     }
77 
78     auto* attr =
79         reinterpret_cast<type_datum*>(hashtab_search(policy_db_->p_types.table, "property_type"));
80     if (attr == nullptr || attr->flavor != TYPE_ATTRIB) {
81       std::cerr << "'property_type' is not defined correctly." << std::endl;
82       return false;
83     }
84 
85     property_type_bit_ = attr->s.value - 1;
86 
87     return true;
88   }
89 
CheckContext(const char * context)90   bool CheckContext(const char* context) {
91     sepol_context_t* sepol_context_raw;
92     if (sepol_context_from_string(sepol_handle_, context, &sepol_context_raw) < 0) {
93       std::cerr << "Could not allocate context for " << context << std::endl;
94       return false;
95     }
96     auto sepol_context = std::unique_ptr<sepol_context_t, decltype(&sepol_context_free)>{
97         sepol_context_raw, sepol_context_free};
98 
99     if (sepol_context_check(sepol_handle_, sepol_policy_db_, sepol_context.get()) < 0) {
100       std::cerr << "Sepol context check failed for " << context << std::endl;
101       return false;
102     }
103 
104     const char* context_type = sepol_context_get_type(sepol_context.get());
105 
106     auto* type =
107         reinterpret_cast<type_datum*>(hashtab_search(policy_db_->p_types.table, context_type));
108     if (type == nullptr) {
109       std::cerr << "Could not find context '" << context << "' in policy database" << std::endl;
110       return false;
111     }
112 
113     if (type->flavor != TYPE_TYPE) {
114       std::cerr << "Context '" << context << "' is not defined as a type in policy database"
115                 << std::endl;
116       return false;
117     }
118 
119     if (!ebitmap_get_bit(&policy_db_->type_attr_map[type->s.value - 1], property_type_bit_)) {
120       std::cerr << "Context '" << context << "' does not have property_type attribute" << std::endl;
121       return false;
122     }
123 
124     return true;
125   }
126 
127  private:
128   FILE* policy_file_;
129   sepol_handle_t* sepol_handle_;
130   sepol_policy_file_t* sepol_policy_file_;
131   union {
132     sepol_policydb_t* sepol_policy_db_;
133     policydb_t* policy_db_;
134   };
135   unsigned int property_type_bit_;
136 };
137 
main(int argc,char ** argv)138 int main(int argc, char** argv) {
139   if (argc < 3) {
140     std::cerr << "usage: " << argv[0]
141               << " COMPILED_SEPOLICY PROPERTY_INFO_FILE [PROPERTY_INFO_FILE]..." << std::endl;
142     return -1;
143   }
144 
145   auto property_info_entries = std::vector<PropertyInfoEntry>{};
146 
147   for (int i = 2; i < argc; ++i) {
148     auto filename = argv[i];
149     auto file_contents = std::string{};
150     if (!ReadFileToString(filename, &file_contents)) {
151       std::cerr << "Could not read properties from '" << filename << "'" << std::endl;
152       return -1;
153     }
154 
155     auto errors = std::vector<std::string>{};
156     ParsePropertyInfoFile(file_contents, true, &property_info_entries, &errors);
157     if (!errors.empty()) {
158       for (const auto& error : errors) {
159         std::cerr << "Could not read line from '" << filename << "': " << error << std::endl;
160       }
161       return -1;
162     }
163   }
164 
165   auto serialized_contexts = std::string{};
166   auto build_trie_error = std::string{};
167 
168   if (!BuildTrie(property_info_entries, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
169                  &build_trie_error)) {
170     std::cerr << "Unable to serialize property contexts: " << build_trie_error << std::endl;
171     return -1;
172   }
173 
174   auto checker = ContextChecker{};
175   if (!checker.Initialize(argv[1])) {
176     return -1;
177   }
178 
179   auto property_info_area = reinterpret_cast<PropertyInfoArea*>(serialized_contexts.data());
180   for (size_t i = 0; i < property_info_area->num_contexts(); ++i) {
181     if (!checker.CheckContext(property_info_area->context(i))) {
182       return -1;
183     }
184   }
185 
186   return 0;
187 }
188