forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land rapid7#9220, Module cache improvements
- Loading branch information
1 parent
faf1a44
commit 0465a7b
Showing
14 changed files
with
581 additions
and
247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ module ClassMethods | |
# | ||
|
||
def fullname | ||
type + '/' + refname | ||
"#{type}/#{refname}" | ||
end | ||
|
||
def promptname | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# -*- coding: binary -*- | ||
require 'msf/core/modules' | ||
|
||
# Namespace for module metadata related data and operations | ||
module Msf::Modules::Metadata | ||
|
||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
require 'singleton' | ||
require 'msf/events' | ||
require 'rex/ui/text/output/stdio' | ||
require 'msf/core/constants' | ||
require 'msf/core/modules/metadata' | ||
require 'msf/core/modules/metadata/obj' | ||
require 'msf/core/modules/metadata/search' | ||
require 'msf/core/modules/metadata/store' | ||
|
||
# | ||
# Core service class that provides storage of module metadata as well as operations on the metadata. | ||
# Note that operations on this metadata are included as separate modules. | ||
# | ||
module Msf | ||
module Modules | ||
module Metadata | ||
|
||
class Cache | ||
include Singleton | ||
include Msf::Modules::Metadata::Search | ||
include Msf::Modules::Metadata::Store | ||
|
||
# | ||
# Refreshes cached module metadata as well as updating the store | ||
# | ||
def refresh_metadata_instance(module_instance) | ||
refresh_metadata_instance_internal(module_instance) | ||
update_store | ||
end | ||
|
||
# | ||
# Returns the module data cache, but first ensures all the metadata is loaded | ||
# | ||
def get_metadata | ||
wait_for_load | ||
@module_metadata_cache.values | ||
end | ||
|
||
# | ||
# Checks for modules loaded that are not a part of the cache and updates the underlying store | ||
# if there are changes. | ||
# | ||
def refresh_metadata(module_sets) | ||
unchanged_module_references = get_unchanged_module_references | ||
has_changes = false | ||
module_sets.each do |mt| | ||
unchanged_reference_name_set = unchanged_module_references[mt[0]] | ||
|
||
mt[1].keys.sort.each do |mn| | ||
next if unchanged_reference_name_set.include? mn | ||
module_instance = mt[1].create(mn) | ||
next if not module_instance | ||
begin | ||
refresh_metadata_instance_internal(module_instance) | ||
has_changes = true | ||
rescue Exception => e | ||
elog("Error updating module details for #{module_instance.fullname}: #{$!.class} #{$!} : #{e.message}") | ||
end | ||
end | ||
end | ||
|
||
update_store if has_changes | ||
end | ||
|
||
# | ||
# Returns a hash(type->set) which references modules that have not changed. | ||
# | ||
def get_unchanged_module_references | ||
skip_reference_name_set_by_module_type = Hash.new { |hash, module_type| | ||
hash[module_type] = Set.new | ||
} | ||
|
||
@module_metadata_cache.each_value do |module_metadata| | ||
|
||
unless module_metadata.path and ::File.exist?(module_metadata.path) | ||
next | ||
end | ||
|
||
if ::File.mtime(module_metadata.path).to_i != module_metadata.mod_time.to_i | ||
next | ||
end | ||
|
||
skip_reference_name_set = skip_reference_name_set_by_module_type[module_metadata.type] | ||
skip_reference_name_set.add(module_metadata.ref_name) | ||
end | ||
|
||
return skip_reference_name_set_by_module_type | ||
end | ||
|
||
####### | ||
private | ||
####### | ||
|
||
def wait_for_load | ||
@load_thread.join unless @store_loaded | ||
end | ||
|
||
def refresh_metadata_instance_internal(module_instance) | ||
metadata_obj = Obj.new(module_instance) | ||
@module_metadata_cache[get_cache_key(module_instance)] = metadata_obj | ||
end | ||
|
||
def get_cache_key(module_instance) | ||
key = '' | ||
key << (module_instance.type.nil? ? '' : module_instance.type) | ||
key << '_' | ||
key << module_instance.refname | ||
return key | ||
end | ||
|
||
def initialize | ||
@module_metadata_cache = {} | ||
@store_loaded = false | ||
@console = Rex::Ui::Text::Output::Stdio.new | ||
@load_thread = Thread.new { | ||
init_store | ||
@store_loaded = true | ||
} | ||
end | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
require 'msf/core/modules/metadata' | ||
|
||
# | ||
# Simple object for storing a modules metadata. | ||
# | ||
module Msf | ||
module Modules | ||
module Metadata | ||
|
||
class Obj | ||
attr_reader :name | ||
attr_reader :full_name | ||
attr_reader :rank | ||
attr_reader :disclosure_date | ||
attr_reader :type | ||
attr_reader :author | ||
attr_reader :description | ||
attr_reader :references | ||
attr_reader :is_server | ||
attr_reader :is_client | ||
attr_reader :platform | ||
attr_reader :arch | ||
attr_reader :rport | ||
attr_reader :targets | ||
attr_reader :mod_time | ||
attr_reader :is_install_path | ||
attr_reader :ref_name | ||
|
||
def initialize(module_instance) | ||
@name = module_instance.name | ||
@full_name = module_instance.fullname | ||
@disclosure_date = module_instance.disclosure_date | ||
@rank = module_instance.rank.to_i | ||
@type = module_instance.type | ||
@description = module_instance.description.to_s.strip | ||
@author = module_instance.author.map{|x| x.to_s} | ||
@references = module_instance.references.map{|x| [x.ctx_id, x.ctx_val].join("-") } | ||
@is_server = (module_instance.respond_to?(:stance) and module_instance.stance == "aggressive") | ||
@is_client = (module_instance.respond_to?(:stance) and module_instance.stance == "passive") | ||
@platform = module_instance.platform_to_s | ||
@arch = module_instance.arch_to_s | ||
@rport = module_instance.datastore['RPORT'].to_s | ||
@path = module_instance.file_path | ||
@mod_time = ::File.mtime(@path) rescue Time.now | ||
@ref_name = module_instance.refname | ||
install_path = Msf::Config.install_root.to_s | ||
if (@path.to_s.include? (install_path)) | ||
@path = @path.sub(install_path, '') | ||
@is_install_path = true | ||
end | ||
|
||
if module_instance.respond_to?(:targets) and module_instance.targets | ||
@targets = module_instance.targets.map{|x| x.name} | ||
end | ||
end | ||
|
||
def update_mod_time(mod_time) | ||
@mod_time = mod_time | ||
end | ||
|
||
def path | ||
if @is_install_path | ||
return ::File.join(Msf::Config.install_root, @path) | ||
end | ||
|
||
@path | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.