bool AuditRulesMonitor::check_kernel_rules()

in AuditRulesMonitor.cpp [169:298]


bool AuditRulesMonitor::check_kernel_rules() {
    _op_status->SetDesiredAuditRules(_desired_rules);
    if (_desired_rules.empty()) {
        return true;
    }

    std::vector<AuditRule> rules;
    auto ret = NetlinkRetry([this,&rules]() {
        rules.clear();
        return _netlink.AuditListRules(rules);
    });
    if (ret != 0) {
        Logger::Error("AuditRulesMonitor: Unable to fetch audit rules from kernel: %s", std::strerror(-ret));
        _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, std::string("Unable to fetch audit rules from kernel: ") + std::strerror(-ret));
        _op_status->SetLoadedAuditRules({{}});
        return false;
    } else {
        _op_status->SetLoadedAuditRules(rules);
    }

    auto merged_rules = MergeRules(rules);

    auto diff = DiffRules(merged_rules, _desired_rules, "");
    if (diff.empty()) {
        _op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL);
        return true;
    }

    uint32_t enabled = 0;
    ret = NetlinkRetry([this,&enabled]() { return _netlink.AuditGetEnabled(enabled); });
    if (ret != 0) {
        Logger::Error("AuditRulesMonitor: Unable to get audit status from kernel: %s", std::strerror(-ret));
        _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, std::string("Unable to get audit status from kernel: ") + std::strerror(-ret));
        return false;
    }

    if (enabled == 2) {
        if (!_rules_immutable) {
            Logger::Error("AuditRulesMonitor: Unable to add desired rules because audit rules are set to immutable");
            _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, "Unable to add desired rules because audit rules are set to immutable");
            _rules_immutable = true;
        }
        return true;
    } else {
        _rules_immutable = false;
    }

    Logger::Info("AuditRulesMonitor: Found desired audit rules not currently loaded, loading new rules");

    std::unordered_map<std::string, AuditRule> _dmap;
    for (auto& rule: _desired_rules) {
        _dmap.emplace(rule.CanonicalMergeKey(), rule);
    }

    bool failed_old = false;
    bool failed_new = false;
    // Delete all old auoms rules
    for (auto& rule: rules) {
        // Delete rule if it has AUOMS_RULE_KEY or matches any of the desired rules.
        bool delete_it = rule.GetKeys().count(AUOMS_RULE_KEY) > 0;
        if (!delete_it) {
            auto itr = _dmap.find(rule.CanonicalMergeKey());
            if (itr != _dmap.end()) {
                if (rule.IsWatch()) {
                    // Check to see if the rule's perms is a subset of the desired rule's perms
                    auto dset = itr->second.GetPerms();
                    auto aset = rule.GetPerms();
                    if (is_set_intersect(dset, aset)) {
                        delete_it = true;
                    }
                } else {
                    // Check to see if the rule's syscalls is a subset of the desired rule's syscalls
                    auto dset = itr->second.GetSyscalls();
                    auto aset = rule.GetSyscalls();
                    if (is_set_intersect(dset, aset)) {
                        delete_it = true;
                    }
                }
            }
        }
        if (delete_it) {
            ret = _netlink.AuditDelRule(rule);
            if (ret != 0) {
                Logger::Warn("AuditRulesMonitor: Failed to delete audit rule (%s): %s\n", rule.CanonicalText().c_str(), strerror(-ret));
                failed_old = true;
            }
        }
    }

    // refresh rules list
    ret = NetlinkRetry([this,&rules]() {
        rules.clear();
        return _netlink.AuditListRules(rules);
    });
    if (ret != 0) {
        Logger::Error("AuditRulesMonitor: Unable to fetch audit rules from kernel: %s", std::strerror(-ret));
        _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, std::string("Unable to fetch audit rules from kernel: ") + std::strerror(-ret));
        return false;
    }

    merged_rules = MergeRules(rules);

    // re-diff rules
    diff = DiffRules(merged_rules, _desired_rules, "");
    if (diff.empty()) {
        _op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL);
        return true;
    }

    // Add diff rules
    for (auto& rule: diff) {
        ret = _netlink.AuditAddRule(rule);
        if (ret != 0) {
            Logger::Warn("AuditRulesMonitor: Failed to load audit rule (%s): %s\n", rule.CanonicalText().c_str(), strerror(-ret));
            failed_new = true;
        }
    }

    if (failed_new && !failed_old) {
        _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, "Failed to add new rule(s)");
    } else if (!failed_new && failed_old) {
        _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, "Failed to delete old rule(s)");
    } else if (failed_new && failed_old) {
        _op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL, "Failed to delete old rule(s) and failed to add new rule(s)");
    } else {
        _op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_KERNEL);
    }

    return true;
}