Add workaround for race condition in report_host

Modify to use DBManager methods rather than DataProxy
GSoC/Meterpreter_Web_Console
Matthew Kienow 2018-05-14 17:36:33 -04:00
parent 262e791dcc
commit 4b13fbb5a3
No known key found for this signature in database
GPG Key ID: 40787F8B1EAC6E41
1 changed files with 70 additions and 66 deletions

View File

@ -58,7 +58,7 @@ module Msf::DBManager::Host
ip = opts[:ip]
tag_name = opts[:tag_name]
host = framework.db.get_host(:workspace => wspace, :address => ip)
host = get_host(workspace: wspace, address: ip)
if host
possible_tags = Mdm::Tag.joins(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name).order("tags.id DESC").limit(1)
tag = (possible_tags.blank? ? Mdm::Tag.new : possible_tags.first)
@ -185,74 +185,78 @@ module Msf::DBManager::Host
::ActiveRecord::Base.connection_pool.with_connection {
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
ret = { }
if !addr.kind_of? ::Mdm::Host
addr = Msf::Util::Host.normalize_host(addr)
unless ipv46_validator(addr)
raise ::ArgumentError, "Invalid IP address in report_host(): #{addr}"
end
if opts[:comm] and opts[:comm].length > 0
host = wspace.hosts.where(address: addr, comm: opts[:comm]).first_or_initialize
else
host = wspace.hosts.where(address: addr).first_or_initialize
end
else
host = addr
end
ostate = host.state
# Truncate the info field at the maximum field length
if opts[:info]
opts[:info] = opts[:info][0,65535]
end
# Truncate the name field at the maximum field length
if opts[:name]
opts[:name] = opts[:name][0,255]
end
if opts[:os_name]
os_name, os_flavor = split_windows_os_name(opts[:os_name])
opts[:os_name] = os_name if os_name.present?
if opts[:os_flavor].present?
opts[:os_flavor] = os_flavor + opts[:os_flavor]
else
opts[:os_flavor] = os_flavor
end
end
opts.each do |k,v|
if (host.attribute_names.include?(k.to_s))
unless host.attribute_locked?(k.to_s)
host[k] = v.to_s.gsub(/[\x00-\x1f]/n, '')
end
elsif !v.blank?
dlog("Unknown attribute for ::Mdm::Host: #{k}")
end
end
host.info = host.info[0,::Mdm::Host.columns_hash["info"].limit] if host.info
# Set default fields if needed
host.state = Msf::HostState::Alive if !host.state
host.comm = '' if !host.comm
host.workspace = wspace if !host.workspace
begin
framework.events.on_db_host(host) if host.new_record?
rescue ::Exception => e
wlog("Exception in on_db_host event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
retry_attempts ||= 0
if !addr.kind_of? ::Mdm::Host
addr = Msf::Util::Host.normalize_host(addr)
host_state_changed(host, ostate) if host.state != ostate
unless ipv46_validator(addr)
raise ::ArgumentError, "Invalid IP address in report_host(): #{addr}"
end
if host.changed?
msf_import_timestamps(opts,host)
host.save!
conditions = {address: addr}
conditions[:comm] = opts[:comm] if !opts[:comm].nil? && opts[:comm].length > 0
host = wspace.hosts.where(conditions).first_or_initialize
else
host = addr
end
ostate = host.state
# Truncate the info field at the maximum field length
if opts[:info]
opts[:info] = opts[:info][0,65535]
end
# Truncate the name field at the maximum field length
if opts[:name]
opts[:name] = opts[:name][0,255]
end
if opts[:os_name]
os_name, os_flavor = split_windows_os_name(opts[:os_name])
opts[:os_name] = os_name if os_name.present?
if opts[:os_flavor].present?
opts[:os_flavor] = os_flavor + opts[:os_flavor]
else
opts[:os_flavor] = os_flavor
end
end
opts.each do |k,v|
if host.attribute_names.include?(k.to_s)
unless host.attribute_locked?(k.to_s)
host[k] = v.to_s.gsub(/[\x00-\x1f]/n, '')
end
elsif !v.blank?
dlog("Unknown attribute for ::Mdm::Host: #{k}")
end
end
host.info = host.info[0,::Mdm::Host.columns_hash["info"].limit] if host.info
# Set default fields if needed
host.state = Msf::HostState::Alive unless host.state
host.comm = '' unless host.comm
host.workspace = wspace unless host.workspace
begin
framework.events.on_db_host(host) if host.new_record?
rescue => e
wlog("Exception in on_db_host event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
host_state_changed(host, ostate) if host.state != ostate
if host.changed?
msf_import_timestamps(opts, host)
host.save!
end
rescue ActiveRecord::RecordNotUnique
# two concurrent report requests for a new host could result in a RecordNotUnique exception
# simply retry the report once more as an optimistic approach
retry if (retry_attempts+=1) <= 1
raise
end
if opts[:task]