diff --git a/src/input/Manager.cc b/src/input/Manager.cc index 2de28b3735..127bd37514 100644 --- a/src/input/Manager.cc +++ b/src/input/Manager.cc @@ -264,6 +264,15 @@ bool Manager::CreateStream(Stream* info, RecordVal* description) { return true; } +// Return true if v is a TypeVal that contains a record type, else false; +static bool is_record_type_val(const zeek::ValPtr& v) { + const auto& t = v->GetType(); + return t->Tag() == TYPE_TYPE && t->AsTypeType()->GetType()->Tag() == TYPE_RECORD; +} + +// Return true if v contains is not nil and contains a FuncVal, else false; +static bool is_func_val(const zeek::ValPtr& v) { return v->GetType()->Tag() == TYPE_FUNC; } + bool Manager::CreateEventStream(RecordVal* fval) { RecordType* rtype = fval->GetType()->AsRecordType(); if ( ! same_type(rtype, BifType::Record::Input::EventDescription, false) ) { @@ -274,11 +283,21 @@ bool Manager::CreateEventStream(RecordVal* fval) { string stream_name = fval->GetFieldOrDefault("name")->AsString()->CheckString(); auto fields_val = fval->GetFieldOrDefault("fields"); + if ( ! is_record_type_val(fields_val) ) { + reporter->Error("Input stream %s: 'idx' field is not a record type", stream_name.c_str()); + return false; + } + RecordType* fields = fields_val->AsType()->AsTypeType()->GetType()->AsRecordType(); auto want_record = fval->GetFieldOrDefault("want_record"); auto ev_val = fval->GetFieldOrDefault("ev"); + if ( ev_val && ! is_func_val(ev_val) ) { + reporter->Error("Input stream %s: 'ev' field is not an event", stream_name.c_str()); + return false; + } + Func* event = ev_val->AsFunc(); const auto& etype = event->GetType(); @@ -356,6 +375,11 @@ bool Manager::CreateEventStream(RecordVal* fval) { assert(false); auto error_event_val = fval->GetFieldOrDefault("error_ev"); + if ( error_event_val && ! is_func_val(error_event_val) ) { + reporter->Error("Input stream %s: 'error_ev' field is not an event", stream_name.c_str()); + return false; + } + Func* error_event = error_event_val ? error_event_val->AsFunc() : nullptr; if ( ! CheckErrorEventTypes(stream_name, error_event, false) ) @@ -414,15 +438,31 @@ bool Manager::CreateTableStream(RecordVal* fval) { auto pred = fval->GetFieldOrDefault("pred"); auto idx_val = fval->GetFieldOrDefault("idx"); + if ( ! is_record_type_val(idx_val) ) { + reporter->Error("Input stream %s: 'idx' field is not a record type", stream_name.c_str()); + return false; + } + RecordType* idx = idx_val->AsType()->AsTypeType()->GetType()->AsRecordType(); RecordTypePtr val; auto val_val = fval->GetFieldOrDefault("val"); - if ( val_val ) + if ( val_val ) { + if ( ! is_record_type_val(val_val) ) { + reporter->Error("Input stream %s: 'val' field is not a record type", stream_name.c_str()); + return false; + } + val = val_val->AsType()->AsTypeType()->GetType(); + } auto dst = fval->GetFieldOrDefault("destination"); + if ( ! dst->GetType()->IsSet() && ! dst->GetType()->IsTable() ) { + reporter->Error("Input stream %s: 'destination' field has type %s, expected table or set identifier", + stream_name.c_str(), obj_desc_short(dst->GetType().get()).c_str()); + return false; + } // check if index fields match table description size_t num = idx->NumFields(); @@ -497,6 +537,11 @@ bool Manager::CreateTableStream(RecordVal* fval) { } auto event_val = fval->GetFieldOrDefault("ev"); + if ( event_val && ! is_func_val(event_val) ) { + reporter->Error("Input stream %s: 'ev' field is not an event", stream_name.c_str()); + return false; + } + Func* event = event_val ? event_val->AsFunc() : nullptr; if ( event ) { @@ -572,6 +617,11 @@ bool Manager::CreateTableStream(RecordVal* fval) { } auto error_event_val = fval->GetFieldOrDefault("error_ev"); + if ( error_event_val && ! is_func_val(error_event_val) ) { + reporter->Error("Input stream %s: 'error_ev' field is not an event", stream_name.c_str()); + return false; + } + Func* error_event = error_event_val ? error_event_val->AsFunc() : nullptr; if ( ! CheckErrorEventTypes(stream_name, error_event, true) ) diff --git a/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr b/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr index 66a9626596..1930931919 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr +++ b/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr @@ -40,4 +40,12 @@ error: Input stream error3: Error event's first attribute must be of type Input: error: Input stream error4: Error event's second attribute must be of type string error: Input stream error5: Error event's third attribute must be of type Reporter::Level error: Input stream error6: 'destination' field is a table, but 'val' field is not provided (did you mean to use a set instead of a table?) +error: Input stream types1: 'idx' field is not a record type +error: Input stream types2: 'val' field is not a record type +error: Input stream types3: 'destination' field has type string, expected table or set identifier +error: Input stream types4: 'ev' field is not an event +error: Input stream types5: 'error_ev' field is not an event +error: Input stream types6: 'idx' field is not a record type +error: Input stream types7: 'ev' field is not an event +error: Input stream types8: 'error_ev' field is not an event received termination signal diff --git a/testing/btest/scripts/base/frameworks/input/errors.zeek b/testing/btest/scripts/base/frameworks/input/errors.zeek index 0bd80f70e3..fe55530484 100644 --- a/testing/btest/scripts/base/frameworks/input/errors.zeek +++ b/testing/btest/scripts/base/frameworks/input/errors.zeek @@ -59,6 +59,7 @@ global val_table: table[count] of Val = table(); global val_table2: table[count, int] of Val = table(); global val_table3: table[count, int] of int = table(); global val_table4: table[count] of int; +global val_set: set[count]; event line_file(description: Input::EventDescription, tpe: Input::Event, r:FileVal) { @@ -190,5 +191,15 @@ event zeek_init() Input::add_table([$source="input.log", $name="error6", $idx=Idx, $destination=val_table]); + # Check that we do not crash when a user passes unexpected types to any fields in the description records. + Input::add_table([$source="input.log", $name="types1", $idx="string-is-not-allowed", $destination=val_set]); + Input::add_table([$source="input.log", $name="types2", $idx=Idx, $val="string-is-not-allowed", $destination=val_set]); + Input::add_table([$source="input.log", $name="types3", $idx=Idx, $destination="string-is-not-allowed"]); + Input::add_table([$source="input.log", $name="types4", $idx=Idx, $destination=val_set, $ev="not-an-event"]); + Input::add_table([$source="input.log", $name="types5", $idx=Idx, $destination=val_set, $error_ev="not-an-event"]); + Input::add_event([$source="input.log", $name="types6", $fields="string-is-not-allowed", $ev=event11]); + Input::add_event([$source="input.log", $name="types7", $fields=Val, $ev="not-an-event"]); + Input::add_event([$source="input.log", $name="types8", $fields=Val, $ev=event11, $error_ev="not-an-event"]); + schedule 3secs { kill_me() }; }