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: 23 ContextChecker() 24 : policy_file_(nullptr), 25 sepol_handle_(nullptr), 26 sepol_policy_file_(nullptr), 27 sepol_policy_db_(nullptr) {} 28 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 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 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 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, &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