input/Manager: Improve type checks of record fields with type any

Calling AsRecordType() or AsFunc() on a Val of type any isn't safe.

Closes #3836
This commit is contained in:
Arne Welzel 2024-07-19 10:50:56 +02:00
parent 0ba80d13b4
commit 3797622152
3 changed files with 70 additions and 1 deletions

View file

@ -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<RecordType>();
}
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) )

View file

@ -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

View file

@ -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() };
}