bool RawEventProcessor::process_syscall_event()

in RawEventProcessor.cpp [139:738]


bool RawEventProcessor::process_syscall_event(const Event& event) {

    using namespace std::string_view_literals;

    static auto SV_ZERO = "0"sv;
    static auto SV_TYPE = "type"sv;
    static auto SV_ITEMS = "items"sv;
    static auto SV_ITEM = "item"sv;
    static auto SV_NODE = "node"sv;
    static auto SV_ARGC = "argc"sv;
    static auto SV_CWD = "cwd"sv;
    static auto SV_SADDR = "saddr"sv;
    static auto SV_INTEGRITY_HASH = "hash"sv;
    static auto SV_NAME = "name"sv;
    static auto SV_NAMETYPE = "nametype"sv;
    static auto SV_OBJTYPE = "objtype"sv;
    static auto SV_MODE = "mode"sv;
    static auto SV_OUID = "ouid"sv;
    static auto SV_OGID = "ogid"sv;
    static auto SV_PATH_NAME = "path_name"sv;
    static auto SV_PATH_NAMETYPE = "path_nametype"sv;
    static auto SV_PATH_MODE = "path_mode"sv;
    static auto SV_PATH_OUID = "path_ouid"sv;
    static auto SV_PATH_OGID = "path_ogid"sv;
    static auto SV_EMPTY = ""sv;
    static auto SV_CMDLINE = "cmdline"sv;
    static auto SV_REDACTORS = "redactors"sv;
    static auto SV_CONTAINERID = "containerid"sv;
    static auto SV_DROPPED = "dropped_"sv;
    static auto SV_PID = "pid"sv;
    static auto SV_PPID = "ppid"sv;
    static auto SV_SYSCALL = "syscall"sv;
    static auto SV_PROCTITLE = "proctitle"sv;
    static auto S_EXECVE = std::string("execve");
    static auto SV_JSON_ARRAY_START = "[\""sv;
    static auto SV_JSON_ARRAY_SEP = "\",\""sv;
    static auto SV_JSON_ARRAY_END = "\"]"sv;
    static auto auoms_syscall_name = RecordTypeToName(RecordType::AUOMS_SYSCALL);
    static auto auoms_syscall_fragment_name = RecordTypeToName(RecordType::AUOMS_SYSCALL_FRAGMENT);
    static auto auoms_execve_name = RecordTypeToName(RecordType::AUOMS_EXECVE);
    static auto SV_AUOMSVERSION_NAME = "auoms_version"sv;
    static std::string S_AUOMS_VERSION = AUOMS_VERSION;
    static std::string_view SV_AUOMS_VERSION = S_AUOMS_VERSION;

    int num_fields = 0;
    int num_path = 0;
    int num_execve = 0;
    int uid;
    int gid;
    std::string exe;
    std::string syscall;

    auto rec_type = RecordType::AUOMS_SYSCALL_FRAGMENT;
    auto rec_type_name = auoms_syscall_fragment_name;

    EventRecord syscall_rec;
    EventRecordField syscall_field;
    EventRecord cwd_rec;
    EventRecordField cwd_field;
    EventRecord path_rec;
    std::vector<EventRecord> path_recs;
    std::vector<EventRecord> execve_recs;
    EventRecord argc_rec;
    EventRecordField argc_field;
    EventRecord sockaddr_rec;
    EventRecordField sockaddr_field;
    EventRecord integrity_rec;
    EventRecordField integrity_field;
    EventRecord proctitle_rec;
    EventRecordField proctitle_field;
    EventRecord dropped_rec;
    std::vector<EventRecord> other_recs;

    for (auto& rec: event) {
        switch(static_cast<RecordType>(rec.RecordType())) {
            case RecordType::SYSCALL:
                if (!syscall_rec) {
                    rec_type = RecordType::AUOMS_SYSCALL;
                    rec_type_name = auoms_syscall_name;
                    for (auto &f : rec) {
                        auto fname = f.FieldName();
                        switch (fname[0]) {
                            case 't': {
                                if (fname != SV_TYPE) {
                                    num_fields += 1;
                                }
                                break;
                            }
                            case 'i': {
                                if (fname != SV_ITEMS) {
                                    num_fields += 1;
                                }
                                break;
                            }
                            case 's': {
                                if (fname == SV_SYSCALL) {
                                    syscall_field = f;
                                }
                                num_fields += 1;
                                break;
                            }
                            default:
                                num_fields += 1;
                                break;
                        }
                    }
                    syscall_rec = rec;
                }
                break;
            case RecordType::EXECVE: {
                if (rec.NumFields() > 0) {
                    if (num_execve == 0) {
                        num_fields += 1;
                        if (!argc_rec) {
                            // the argc field should be the first (or second if node field is present) field in the record but check the first four just in case
                            for(uint16_t i = 0; i < rec.NumFields() && i < 4 ; i++) {
                                auto field = rec.FieldAt(i);
                                if (field.FieldName() == SV_ARGC) {
                                    num_fields += 1;
                                    argc_rec = rec;
                                    argc_field = field;
                                    break;
                                }
                            }
                        }
                    }
                    num_execve += 1;
                    execve_recs.emplace_back(rec);
                }
                break;
            }
            case RecordType::CWD:
                if (!cwd_rec) {
                    for (int i = 0; i < rec.NumFields(); ++i) {
                        auto field = rec.FieldAt(i);
                        if (field.FieldName() == SV_CWD) {
                            num_fields += 1;
                            cwd_rec = rec;
                            cwd_field = field;
                            break;
                        }
                    }
                }
                break;
            case RecordType::PATH:
                if (rec.NumFields() > 0) {
                    if (num_path == 0) {
                        // This assumes there will only be a nametype field or an objtype field but never both
                        num_fields += 5; // name, mode, ouid, ogid, (nametype or objtype)
                    }
                    num_path += 1;
                    path_recs.emplace_back(rec);
                    if (!path_rec) {
                        bool isItemZero = false;
                        unsigned int numNodeFields = 0;
                        for (auto& f: rec) {
                            if (f.FieldName() == SV_ITEM && f.RawValue() == SV_ZERO) {
                                isItemZero = true;
                            } else if (f.FieldName() == SV_NODE) {
                                numNodeFields++;
                            }
                        }
                        if (isItemZero) {
                            num_fields += rec.NumFields() - 1 - numNodeFields; // exclude item and node fields
                            path_rec = rec;
                        }
                    }
                }
                break;
            case RecordType::SOCKADDR:
                if (!sockaddr_rec) {
                    for (int i = 0; i < rec.NumFields(); ++i) {
                        auto field = rec.FieldAt(i);
                        if (field.FieldName() == SV_SADDR) {
                            sockaddr_rec = rec;
                            sockaddr_field = field;
                            num_fields += 1;
                            break;
                        }
                    }
                }
                break;
            case RecordType::INTEGRITY_RULE:
                if (!integrity_rec) {
                    for (int i = 0; i < rec.NumFields(); ++i) {
                        auto field = rec.FieldAt(i);
                        if (field.FieldName() == SV_INTEGRITY_HASH) {
                            integrity_rec = rec;
                            integrity_field = field;
                            num_fields += 1;
                        }
                    }
                }
                break;
            case RecordType::PROCTITLE:
                if (!proctitle_rec) {
                    for (int i = 0; i < rec.NumFields(); ++i) {
                        auto field = rec.FieldAt(i);
                        if (field.FieldName() == SV_PROCTITLE) {
                            num_fields += 1;
                            proctitle_rec = rec;
                            proctitle_field = field;
                            break;
                        }
                    }
                }
                break;
            case RecordType::AUOMS_DROPPED_RECORDS:
                dropped_rec = rec;
                num_fields += dropped_rec->NumFields();
                break;
            default:
                if (rec.NumFields() > 0) {
                    num_fields += rec.NumFields();
                    other_recs.emplace_back(rec);
                }
                break;
        }
    }

    // Sort PATH records by item field
    std::sort(path_recs.begin(), path_recs.end(), [](const EventRecord& a, const EventRecord& b) -> int {
        auto fa = a.FieldByName(SV_ITEM);
        auto fb = b.FieldByName(SV_ITEM);
        int a_num = INT32_MAX; // PATH records with a missing or invalid item value should be sorted to the end;
        int b_num = INT32_MAX;

        if (fa) {
            try {
                a_num = std::stoi(std::string(fa.FieldName()));
            } catch (std::logic_error&) {
                // Ignore
            }
        }

        if (fb) {
            try {
                b_num = std::stoi(std::string(fb.FieldName()));
            } catch (std::logic_error&) {
                // Ignore
            }
        }

        return a_num > b_num;
    });

    if (syscall_rec && syscall_field) {
        if (InterpretField(_tmp_val, syscall_rec, syscall_field, field_type_t::SYSCALL)) {
            if (starts_with(_tmp_val, S_EXECVE)) {
                rec_type = RecordType::AUOMS_EXECVE;
                rec_type_name = auoms_execve_name;
            }
        }
        _syscall = _tmp_val;
    }

    // Exclude proctitle if EXECVE is present
    if (execve_recs.size() > 0 && proctitle_rec && proctitle_field) {
        num_fields -= 1;
    }

    if (execve_recs.size() > 0 || (proctitle_rec && proctitle_field)) {
        // for redactors field
        num_fields += 1;
    }

    if (num_fields == 0) {
        return false;
    }

    // For containerid and auoms_version
    num_fields += 2;

    if (!_builder->BeginEvent(event.Seconds(), event.Milliseconds(), event.Serial(), 1)) {
        throw std::runtime_error("Queue closed");
    }
    _event_flags = EVENT_FLAG_IS_AUOMS_EVENT;

    if (!_builder->BeginRecord(static_cast<uint32_t>(rec_type), rec_type_name, SV_EMPTY, num_fields)) {
        throw std::runtime_error("Queue closed");
    }

    if (!_builder->AddField(SV_AUOMSVERSION_NAME, SV_AUOMS_VERSION, nullptr, field_type_t::UNCLASSIFIED)) {
        throw std::runtime_error("Queue closed");
    }

    if (syscall_rec) {
        for (auto &f : syscall_rec) {
            auto fname = f.FieldName();
            bool add_field = false;
            switch (fname[0]) {
                case 't': {
                    if (fname != SV_TYPE) {
                        add_field = true;
                    }
                    break;
                }
                case 'i': {
                    if (fname != SV_ITEMS) {
                        add_field = true;
                    }
                    break;
                }
                case 'p':
                    if (fname == SV_PID) {
                        _pid = atoi(f.RawValuePtr());
                        _builder->SetEventPid(_pid);
                    }
                    if (fname == SV_PPID) {
                        _ppid = atoi(f.RawValuePtr());
                    }
                    add_field = true;
                    break;
                case 'u':
                    if (fname == "uid") {
                        uid = atoi(f.RawValuePtr());
                    }
                    add_field = true;
                    break;
                case 'g':
                    if (fname == "gid") {
                        gid = atoi(f.RawValuePtr());
                    }
                    add_field = true;
                    break;
                case 'e':
                    if (fname == "exe") {
                        exe = std::string(f.RawValuePtr());
                    }
                    add_field = true;
                    break;
                default:
                    add_field = true;
                    break;
            }
            if (add_field) {
                if (!process_field(syscall_rec, f, 0)) {
                    cancel_event();
                    return false;
                }
            }
        }
    }

    if (cwd_rec && cwd_field) {
        if (!process_field(cwd_rec, cwd_field, 0)) {
            cancel_event();
            return false;
        }
    }

    if (path_rec) {
        for (auto &f : path_rec) {
            auto fname = f.FieldName();
            if (fname != SV_ITEM && fname != SV_NODE) {
                if (!process_field(path_rec, f, 0)) {
                    cancel_event();
                    return false;
                }
            }
        }
    }

    _path_name.resize(0);
    _path_nametype.resize(0);
    _path_mode.resize(0);
    _path_ouid.resize(0);
    _path_ogid.resize(0);

    if (path_recs.size() > 0) {
        _path_name = SV_JSON_ARRAY_START;
        _path_nametype = SV_JSON_ARRAY_START;
        _path_mode = SV_JSON_ARRAY_START;
        _path_ouid = SV_JSON_ARRAY_START;
        _path_ogid = SV_JSON_ARRAY_START;

        int path_num = 0;

        for (auto& rec: path_recs) {
            bool found_nametype = false;
            for (auto &f : rec) {
                auto fname = f.FieldName();
                if (fname.size() >= 2) {
                    switch (fname[0]) {
                        case 'm': {
                            if (fname == SV_MODE) {
                                if (path_num != 0) {
                                    _path_mode.append(SV_JSON_ARRAY_SEP);
                                }
                                _path_mode.append(f.RawValuePtr(), f.RawValueSize());
                            }
                            break;
                        }
                        case 'n': {
                            if (fname == SV_NAME) {
                                if (path_num != 0) {
                                    _path_name.append(SV_JSON_ARRAY_SEP);
                                }
                                // name might be escaped
                                unescape_raw_field(_unescaped_val, f.RawValuePtr(), f.RawValueSize());
                                // Path names might have non-ASCII/non-printable chars, escape the name before adding it.
                                json_escape_string(_tmp_val, _unescaped_val.data(), _unescaped_val.size());
                                _path_name.append(_tmp_val);
                            } else if (fname == SV_NAMETYPE && !found_nametype) {
                                if (path_num != 0) {
                                    _path_nametype.append(SV_JSON_ARRAY_SEP);
                                }
                                _path_nametype.append(f.RawValuePtr(), f.RawValueSize());
                                found_nametype = true;
                            }
                            break;
                        }
                        case 'o': {
                            switch (fname[1]) {
                                case 'b':
                                    if (fname == SV_OBJTYPE && !found_nametype) {
                                        if (path_num != 0) {
                                            _path_nametype.append(SV_JSON_ARRAY_SEP);
                                        }
                                        _path_nametype.append(f.RawValuePtr(), f.RawValueSize());
                                        found_nametype = true;
                                    }
                                    break;
                                case 'g':
                                    if (fname == SV_OGID) {
                                        if (path_num != 0) {
                                            _path_ogid.append(SV_JSON_ARRAY_SEP);
                                        }
                                        _path_ogid.append(f.RawValuePtr(), f.RawValueSize());
                                    }
                                    break;
                                case 'u':
                                    if (fname == SV_OUID) {
                                        if (path_num != 0) {
                                            _path_ouid.append(SV_JSON_ARRAY_SEP);
                                        }
                                        _path_ouid.append(f.RawValuePtr(), f.RawValueSize());
                                    }
                                    break;
                            }
                            break;
                        }
                    }
                }
            }
            path_num += 1;
        }

        _path_name.append(SV_JSON_ARRAY_END);
        _path_nametype.append(SV_JSON_ARRAY_END);
        _path_mode.append(SV_JSON_ARRAY_END);
        _path_ouid.append(SV_JSON_ARRAY_END);
        _path_ogid.append(SV_JSON_ARRAY_END);

        if (!_builder->AddField(SV_PATH_NAME, _path_name, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }

        if (!_builder->AddField(SV_PATH_NAMETYPE, _path_nametype, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }

        if (!_builder->AddField(SV_PATH_MODE, _path_mode, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }

        if (!_builder->AddField(SV_PATH_OUID, _path_ouid, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }

        if (!_builder->AddField(SV_PATH_OGID, _path_ogid, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }
    }

    if (argc_rec && argc_field) {
        if (!process_field(argc_rec, argc_field, 0)) {
            cancel_event();
            return false;
        }
    }

    if (execve_recs.size() > 0) {
        // Exclude proctitle since we have EXECVE
        proctitle_rec = EventRecord();
        proctitle_field = EventRecordField();

        _execve_converter.Convert(execve_recs, _cmdline);
        _cmdline_redactor->ApplyRules(_cmdline, _tmp_val);

        if (!_builder->AddField(SV_CMDLINE, _cmdline, nullptr, field_type_t::UNESCAPED)) {
            throw std::runtime_error("Queue closed");
        }

        if (!_builder->AddField(SV_REDACTORS, _tmp_val, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }
    } else {
        _cmdline.resize(0);
    }

    if (sockaddr_rec && sockaddr_field) {
        if (!process_field(sockaddr_rec, sockaddr_field, 0)) {
            cancel_event();
            return false;
        }
    }

    if (integrity_rec && integrity_field) {
        if (!process_field(integrity_rec, integrity_field, 0)) {
            cancel_event();
            return false;
        }
    }

    if (proctitle_rec && proctitle_field) {
        unescape_raw_field(_unescaped_val, proctitle_field.RawValuePtr(), proctitle_field.RawValueSize());
        ExecveConverter::ConvertRawCmdline(_unescaped_val, _cmdline);
        _cmdline_redactor->ApplyRules(_cmdline, _tmp_val);

        if (!_builder->AddField(SV_PROCTITLE, _cmdline, nullptr, field_type_t::PROCTITLE)) {
            throw std::runtime_error("Queue closed");
        }

        if (!_builder->AddField(SV_REDACTORS, _tmp_val, nullptr, field_type_t::UNCLASSIFIED)) {
            throw std::runtime_error("Queue closed");
        }
    }

    if (other_recs.size() > 0) {
        _other_tag += 1;
        for (auto& rec : other_recs) {
            auto r = _other_rtype_counts.emplace(std::make_pair(rec.RecordType(), std::make_pair(_other_tag, 1)));
            if (!r.second) {
                if (r.first->second.first != _other_tag) {
                    r.first->second.first = _other_tag;
                    r.first->second.second = 1;
                }
            }
            for (auto &field: rec) {
                if (!process_field(rec, field, r.first->second.second)) {
                    cancel_event();
                    return false;
                }
            }
            r.first->second.second += 1;
        }
    }

    if (dropped_rec) {
        for (auto& field: dropped_rec) {
            _field_name.assign(SV_DROPPED);
            _field_name.append(field.FieldName());
            if (!_builder->AddField(_field_name, field.RawValue(), nullptr, field_type_t::UNCLASSIFIED)) {
                throw std::runtime_error("Queue closed");
            }
        }
    }

    std::shared_ptr<ProcessTreeItem> p;
    std::string cmdline;

    std::string containerid;

    if (_processTree) {
        if (!_syscall.empty() && starts_with(_syscall, "execve")) {
            if (!exe.empty() && exe.front() == '"' && exe.back() == '"') {
                exe = exe.substr(1, exe.length() - 2);
            }
            p = _processTree->AddProcess(ProcessTreeSource_execve, _pid, _ppid, uid, gid, exe, _cmdline);
        } else if (!_syscall.empty()) {
            p = _processTree->GetInfoForPid(_pid);
        }

        if (p) {
            containerid = p->containerid();
        }
    }

    if (!_builder->AddField(SV_CONTAINERID, containerid, nullptr, field_type_t::UNCLASSIFIED)) {
        throw std::runtime_error("Queue closed");
    }

    if (!_builder->EndRecord()) {
        throw std::runtime_error("Queue closed");
    }

    bool filtered = false;
    if (_filtersEngine && p && _filtersEngine->IsEventFiltered(_syscall, p, _filtersEngine->GetCommonFlagsMask())) {
        filtered = true;
    }

    if (!filtered) {
        end_event();
    } else {
        cancel_event();
    }

    return true;
}