diff --git a/CHANGES b/CHANGES index b218d49b60..5d180cb590 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,11 @@ +4.1.0-dev.255 | 2021-02-24 12:35:47 -0800 + + * Support explicit disabling of file analyzers (Jon Siwek, Corelight) + + This adds various methods/BIFs the enable/disable file analyzers + or query whether they're currently enabled. + 4.1.0-dev.252 | 2021-02-23 12:01:52 -0800 * "xform" btest alternative baseline update (Vern Paxson, Corelight) diff --git a/VERSION b/VERSION index 2d5d6b81d9..cbda9a9ee1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0-dev.252 +4.1.0-dev.255 diff --git a/scripts/base/frameworks/files/main.zeek b/scripts/base/frameworks/files/main.zeek index 3db4c80dbc..10cc81ba56 100644 --- a/scripts/base/frameworks/files/main.zeek +++ b/scripts/base/frameworks/files/main.zeek @@ -178,6 +178,27 @@ export { ## for the file isn't currently active. global set_timeout_interval: function(f: fa_file, t: interval): bool; + ## Enables a file analyzer. + ## + ## tag: the analyzer type to enable. + ## + ## Returns: false if the analyzer tag could not be found, else true. + global enable_analyzer: function(tag: Files::Tag): bool; + + ## Disables a file analyzer. + ## + ## tag: the analyzer type to disable. + ## + ## Returns: false if the analyzer tag could not be found, else true. + global disable_analyzer: function(tag: Files::Tag): bool; + + ## Checks whether a file analyzer is generally enabled. + ## + ## tag: the analyzer type to check. + ## + ## Returns: true if the analyzer is generally enabled, else false. + global analyzer_enabled: function(tag: Files::Tag): bool; + ## Adds an analyzer to the analysis of a given file. ## ## f: the file. @@ -377,8 +398,26 @@ function set_reassembly_buffer_size(f: fa_file, max: count) __set_reassembly_buffer(f$id, max); } +function enable_analyzer(tag: Files::Tag): bool + { + return __enable_analyzer(tag); + } + +function disable_analyzer(tag: Files::Tag): bool + { + return __disable_analyzer(tag); + } + +function analyzer_enabled(tag: Files::Tag): bool + { + return __analyzer_enabled(tag); + } + function add_analyzer(f: fa_file, tag: Files::Tag, args: AnalyzerArgs): bool { + if ( ! Files::analyzer_enabled(tag) ) + return F; + add f$info$analyzers[Files::analyzer_name(tag)]; if ( tag in analyzer_add_callbacks ) @@ -516,10 +555,7 @@ event file_sniff(f: fa_file, meta: fa_metadata) &priority=10 { local analyzers = mime_type_to_analyzers[meta$mime_type]; for ( a in analyzers ) - { - add f$info$analyzers[Files::analyzer_name(a)]; Files::add_analyzer(f, a); - } } } diff --git a/src/file_analysis/AnalyzerSet.cc b/src/file_analysis/AnalyzerSet.cc index 802b77d5ce..70fe686cce 100644 --- a/src/file_analysis/AnalyzerSet.cc +++ b/src/file_analysis/AnalyzerSet.cc @@ -175,6 +175,11 @@ file_analysis::Analyzer* AnalyzerSet::InstantiateAnalyzer(const Tag& tag, if ( ! a ) { + auto c = file_mgr->Lookup(tag); + + if ( c && ! c->Enabled() ) + return nullptr; + reporter->Error("[%s] Failed file analyzer %s instantiation", file->GetID().c_str(), file_mgr->GetComponentName(tag).c_str()); diff --git a/src/file_analysis/Component.cc b/src/file_analysis/Component.cc index d5d9b8462e..49065c646e 100644 --- a/src/file_analysis/Component.cc +++ b/src/file_analysis/Component.cc @@ -8,11 +8,12 @@ namespace zeek::file_analysis { -Component::Component(const std::string& name, factory_function arg_factory, Tag::subtype_t subtype) +Component::Component(const std::string& name, factory_function arg_factory, Tag::subtype_t subtype, bool arg_enabled) : plugin::Component(plugin::component::FILE_ANALYZER, name), plugin::TaggedComponent(subtype) { factory_func = arg_factory; + enabled = arg_enabled; } void Component::Initialize() @@ -31,7 +32,10 @@ void Component::DoDescribe(ODesc* d) const { d->Add("ANALYZER_"); d->Add(CanonicalName()); + d->Add(", "); } + + d->Add(enabled ? "enabled" : "disabled"); } } // namespace zeek::file_analysis diff --git a/src/file_analysis/Component.h b/src/file_analysis/Component.h index 0bbe167185..d2610d2251 100644 --- a/src/file_analysis/Component.h +++ b/src/file_analysis/Component.h @@ -48,8 +48,12 @@ public: * analyzer::Tag that the manager associates with this analyzer, and * analyzer instances can accordingly access it via analyzer::Tag(). * If not used, leave at zero. + * + * @param enabled If false the analyzer starts out as disabled and + * hence won't be used. It can still be enabled later via the + * manager, including from script-land. */ - Component(const std::string& name, factory_function factory, Tag::subtype_t subtype = 0); + Component(const std::string& name, factory_function factory, Tag::subtype_t subtype = 0, bool enabled = true); /** * Destructor. @@ -69,6 +73,20 @@ public: factory_function FactoryFunction() const { return factory_func; } + /** + * Returns true if the analyzer is currently enabled and hence + * available for use. + */ + bool Enabled() const { return enabled; } + + /** + * Enables or disables this analyzer. + * + * @param arg_enabled True to enabled, false to disable. + * + */ + void SetEnabled(bool arg_enabled) { enabled = arg_enabled; } + protected: /** * Overriden from plugin::Component. @@ -79,6 +97,7 @@ private: friend class Manager; factory_function factory_func; // The analyzer's factory callback. + bool enabled; // True if the analyzer is enabled. }; } // namespace zeek::file_analysis diff --git a/src/file_analysis/Manager.cc b/src/file_analysis/Manager.cc index cadca7368e..9300a9e2ea 100644 --- a/src/file_analysis/Manager.cc +++ b/src/file_analysis/Manager.cc @@ -458,6 +458,13 @@ Analyzer* Manager::InstantiateAnalyzer(const Tag& tag, return nullptr; } + if ( ! c->Enabled() ) + { + DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Skip instantiation of disabled analyzer %s", + f->id.c_str(), GetComponentName(tag).c_str()); + return nullptr; + } + DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Instantiate analyzer %s", f->id.c_str(), GetComponentName(tag).c_str()); diff --git a/src/file_analysis/file_analysis.bif b/src/file_analysis/file_analysis.bif index 0c609e80b1..bb738cd27b 100644 --- a/src/file_analysis/file_analysis.bif +++ b/src/file_analysis/file_analysis.bif @@ -38,6 +38,37 @@ function Files::__set_reassembly_buffer%(file_id: string, max: count%): bool return zeek::val_mgr->Bool(result); %} +## :zeek:see:`Files::enable_analyzer`. +function Files::__enable_analyzer%(tag: Files::Tag%) : bool + %{ + auto c = zeek::file_mgr->Lookup(tag->AsEnumVal()); + + if ( ! c ) + return zeek::val_mgr->False(); + + c->SetEnabled(true); + return zeek::val_mgr->True(); + %} + +## :zeek:see:`Files::disable_analyzer`. +function Files::__disable_analyzer%(tag: Files::Tag%) : bool + %{ + auto c = zeek::file_mgr->Lookup(tag->AsEnumVal()); + + if ( ! c ) + return zeek::val_mgr->False(); + + c->SetEnabled(false); + return zeek::val_mgr->True(); + %} + +## :zeek:see:`Files::analyzer_enabled`. +function Files::__analyzer_enabled%(tag: Files::Tag%) : bool + %{ + auto c = zeek::file_mgr->Lookup(tag->AsEnumVal()); + return zeek::val_mgr->Bool(c && c->Enabled()); + %} + ## :zeek:see:`Files::add_analyzer`. function Files::__add_analyzer%(file_id: string, tag: Files::Tag, args: any%): bool %{ diff --git a/testing/btest/Baseline/plugins.file/output b/testing/btest/Baseline/plugins.file/output index 1631f23a55..6d68624eb5 100644 --- a/testing/btest/Baseline/plugins.file/output +++ b/testing/btest/Baseline/plugins.file/output @@ -1,6 +1,6 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. Demo::Foo - A Foo test analyzer (dynamic, version 1.0.0) - [File Analyzer] Foo (ANALYZER_FOO) + [File Analyzer] Foo (ANALYZER_FOO, enabled) [Event] foo_piece === diff --git a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.enable-disable/out b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.enable-disable/out new file mode 100644 index 0000000000..c83a740fd1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.enable-disable/out @@ -0,0 +1,7 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +T +T +got pe_dos_header event +T +T +F diff --git a/testing/btest/scripts/base/frameworks/file-analysis/bifs/enable-disable.zeek b/testing/btest/scripts/base/frameworks/file-analysis/bifs/enable-disable.zeek new file mode 100644 index 0000000000..0028b959bf --- /dev/null +++ b/testing/btest/scripts/base/frameworks/file-analysis/bifs/enable-disable.zeek @@ -0,0 +1,30 @@ +# @TEST-EXEC: zeek -C -b -r $TRACES/pe/pe.trace %INPUT >out +# @TEST-EXEC: zeek -C -b -r $TRACES/pe/pe.trace %INPUT disable_it=T >>out +# @TEST-EXEC: btest-diff out + +@load base/protocols/ftp + +option disable_it = F; + +event zeek_init() + { + local pe_mime_types: set[string] = { "application/x-dosexec" }; + Files::register_for_mime_types(Files::ANALYZER_PE, pe_mime_types); + + print Files::analyzer_enabled(Files::ANALYZER_PE); + + Files::enable_analyzer(Files::ANALYZER_PE); + print Files::analyzer_enabled(Files::ANALYZER_PE); + + if ( disable_it ) + { + Files::disable_analyzer(Files::ANALYZER_PE); + print Files::analyzer_enabled(Files::ANALYZER_PE); + } + } + +event pe_dos_header(f: fa_file, h: PE::DOSHeader) + { + print "got pe_dos_header event"; + exit(0); + }