Home | History | Annotate | Download | only in property_info_checker
      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