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