Class: Contrast::AgentLib::Interface

Inherits:
InterfaceBase show all
Includes:
CommandInjection, Init, InputTracing, Panic, PathSemanticFileSecurityBypass, Components::Logger::InstanceMethods
Defined in:
lib/contrast/agent_lib/interface.rb

Overview

The interface to react with the AgentLib. This will be the one place of contact with the DynamicLib, synchronized and loaded with modules to use.

Constant Summary

Constants inherited from InterfaceBase

Contrast::AgentLib::InterfaceBase::LOG_DIR, Contrast::AgentLib::InterfaceBase::LOG_LEVEL

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Components::Logger::InstanceMethods

#cef_logger, #logger

Methods included from InputTracing

dl__free_check, dl__free_eval

Methods included from Init

#dl__init_with_options, #init, #init_with_options

Methods inherited from InterfaceBase

#db_set, #eval_option, #input_set, #rule_set

Constructor Details

#initialize(enable_logging = nil, set_log_level = nil, set_log_dir = nil) ⇒ Boolean

Initializes the Agent lib.

likely to be a C segfaults and termination, probably redundant but safe.

Parameters:

  • enable_logging (Boolean, nil) (defaults to: nil)

    flag to enable or disable logging.

  • set_log_level (Integer, nil) (defaults to: nil)
  • set_log_dir (String, nil) (defaults to: nil)

    dir to write log files.

Raises:

  • (StandardError)

    Any Errors raised in the init process are most



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/contrast/agent_lib/interface.rb', line 77

def initialize enable_logging = nil, set_log_level = nil, set_log_dir = nil
  super
  @mutex = Mutex.new
  @enable_log = !!enable_logging
  self.log_level = set_log_level
  @log_dir = create_log_dir(set_log_dir)
  @init_status = if enable_log && log_dir && log_level
                   # Preferred as we will be able to to set the log level at run time.
                   @enable_log_change = true
                   with_mutex { dl__init_with_options(enable_log, log_dir, log_level) }
                 else
                   # Initialize the lib without logging.
                   # The log level could not be changed during runtime.
                   @enable_log_change = false
                   with_mutex { dl__init }
                 end
rescue StandardError => e
  logger.error('Could not start АgentLib', error: e, backtrace: e.backtrace)
end

Instance Attribute Details

#enable_logObject (readonly)

Returns the value of attribute enable_log.



44
45
46
# File 'lib/contrast/agent_lib/interface.rb', line 44

def enable_log
  @enable_log
end

#enable_log_changeObject (readonly)

If true the log level and enable status could be change during runtime.



52
53
54
# File 'lib/contrast/agent_lib/interface.rb', line 52

def enable_log_change
  @enable_log_change
end

#init_statusBoolean (readonly)

Initialization status

Returns:

  • (Boolean)


55
56
57
# File 'lib/contrast/agent_lib/interface.rb', line 55

def init_status
  @init_status
end

#last_errorObject (readonly)

retrieves last error message. note: last_error_message is the name of the attached function and will override the agent_lib native method if renamed.



67
68
69
# File 'lib/contrast/agent_lib/interface.rb', line 67

def last_error
  @last_error
end

#log_dirObject (readonly)

Returns the value of attribute log_dir.



46
47
48
# File 'lib/contrast/agent_lib/interface.rb', line 46

def log_dir
  @log_dir
end

#log_levelObject

Returns the value of attribute log_level.



48
49
50
# File 'lib/contrast/agent_lib/interface.rb', line 48

def log_level
  @log_level
end

#mutexObject (readonly)

We need to synchronize all calls to the AgentLib vie mutex or monitor.

such as calling a re_init on not init lib: This is not the thread you are looking for.



61
62
63
# File 'lib/contrast/agent_lib/interface.rb', line 61

def mutex
  @mutex
end

Instance Method Details

#chained_cmdi_index(cmd) ⇒ Object

Checks that a given shell command contained a chained command. This is used for the cmd-injection-semantic-chained-commands rule.

If the chaining index is >= 0, an injection is detected. Returns -1 when no command chaining is found.

Parameters:

  • cmd (String)

    command to check.



154
155
156
157
158
# File 'lib/contrast/agent_lib/interface.rb', line 154

def chained_cmdi_index cmd
  return unless cmd

  with_mutex { dl__index_of_chained_command(cmd) }
end

#change_log_options(new_enable_log, new_log_level) ⇒ Object

Changes the logs level in runtime.

Parameters:

  • new_enable_log (Boolean)

    flag to enable or disable logging this sets the inner flag.

  • new_log_level (Integer)


101
102
103
104
105
106
# File 'lib/contrast/agent_lib/interface.rb', line 101

def change_log_options new_enable_log, new_log_level
  return unless @enable_log_change

  update_logging(new_log_level, new_enable_log)
  with_mutex { dl__change_log_settings(enable_log, log_level) }
end

#check_cmdi_query(input_index, input_length, input_cmd) ⇒ Object

Evaluate a subset of executing shell command for token boundaries being crossed. This is used by the cmd-injection rule during sink time. If a previously worth-watching input is contained in the shell command it crosses token boundaries then an injection should be raised.

Parameters:

  • input_index (Integer)

    index in the cmdText string where user input was found.

  • input_length (Integer)

    length of the user input.

  • input_cmd (String)

    full text of the command being executed.



181
182
183
184
185
# File 'lib/contrast/agent_lib/interface.rb', line 181

def check_cmdi_query input_index, input_length, input_cmd
  return unless input_index && input_length && input_cmd

  with_mutex { dl__check_cmdi_query(input_index, input_length, input_cmd) }
end

#check_path_semantic_security_bypass(file_path, is_custom_code) ⇒ Object

Invoke Path Semantic File Security Bypass

Parameters:

  • file_path (String)

    the absolute file path

  • is_custom_code (Integer)

    is this is being called from customer (user) code or the framework



238
239
240
241
242
# File 'lib/contrast/agent_lib/interface.rb', line 238

def check_path_semantic_security_bypass file_path, is_custom_code
  return unless file_path || is_custom_code

  with_mutex { dl__does_file_bypass_security(file_path, is_custom_code) }
end

#check_sql_query(input_index, input_length, db_type, sql_query) ⇒ Object



224
225
226
227
228
# File 'lib/contrast/agent_lib/interface.rb', line 224

def check_sql_query input_index, input_length, db_type, sql_query
  return unless input_index && input_length && db_type && sql_query

  with_mutex { dl__check_sql_injection_query(input_index, input_length, db_type, sql_query) }
end

#dangerous_path?(path) ⇒ Boolean

Checks if a given shell command is trying to access a dangerous path. This is used for the cmd-injection-semantic-dangerous-paths rule.

Returns false if no dangerous paths are found.

Parameters:

  • path (String)

    path to check.

Returns:

  • (Boolean)


166
167
168
169
170
# File 'lib/contrast/agent_lib/interface.rb', line 166

def dangerous_path? path
  return unless path

  with_mutex { dl__dangerous_path?(path) }
end

#eval_header(header_name, header_value, rule_set, eval_options) ⇒ Contrast::AgentLib::EvalResult?

Evaluates a header for input tracing rules.

NOTE: the only header names used are “custom”, “accept”, and “user-agent”. Header-name-used is part of the output because the accept and user-agent headers get special handling by agent-lib, so they are evaluated twice - once exactly like all other headers and once with the specific header that gets special handling.

Parameters:

  • header_name (String)

    key/name of the header to be evaluated.

  • header_value (String)

    header value

  • rule_set (Integer)

    One of Contrast::AgentLib::Interface::RULE_SET

  • eval_options (Integer)

    0 or 1 from Contrast::AgentLib::Interface::EVAL_OPTIONS

Returns:



199
200
201
202
203
204
205
206
# File 'lib/contrast/agent_lib/interface.rb', line 199

def eval_header header_name, header_value, rule_set, eval_options
  return unless header_name && header_value && rule_set && eval_options

  result = with_mutex { dl__eval_header_input(header_name, header_value, rule_set, eval_options) }
  return EvalResult.new(result) if result

  nil
end

#eval_input(input, input_type, rule_set, eval_options) ⇒ Contrast::AgentLib::EvalResult?

Evaluates an input part for input tracing rules. This should be used for all input parts except headers.

Parameters:

  • input (String)

    input value to be evaluated.

  • input_type (Integer)

    type of the input one of Contrast::AgentLib::Interface::INPUT_SET

  • rule_set (Integer)

    One of Contrast::AgentLib::Interface::RULE_SET

  • eval_options (Integer)

    0 or 1 from Contrast::AgentLib::Interface::EVAL_OPTIONS

Returns:



215
216
217
218
219
220
221
222
# File 'lib/contrast/agent_lib/interface.rb', line 215

def eval_input input, input_type, rule_set, eval_options
  return unless input && input_type && rule_set && eval_options

  result = with_mutex { dl__eval_input(input, input_type, rule_set, eval_options) }
  return EvalResult.new(result) if result

  nil
end

#handle_errorObject

Method to extract last error if any and log it.



142
143
144
145
# File 'lib/contrast/agent_lib/interface.rb', line 142

def handle_error
  @last_error = mutex.synchronize { dl__get_error }
  logger.error('AgentLib encountered exception: ', error: @last_error) unless @last_error.empty?
end

#with_mutex(&block) ⇒ String, ...

Execute calls to Native methods with mutex. If Error is raised from the AgentLib it will be logged. If C error occurs there will be a segfault and termination.

return types, or nil if something terrible happens.

Returns:

  • (String, Boolean, Integer, nil)

    Wrapper method’s

Raises:

  • (StandardError)

    Capture any unforeseen errors.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/contrast/agent_lib/interface.rb', line 125

def with_mutex &block
  return_value = mutex.synchronize(&block)
rescue StandardError => e
  logger.error('AgentLib runtime error', error: e, backtrace: e.backtrace)
  handle_error
ensure
  # Since every method is called with_mutex this is
  # the natural candidate for handling any errors
  # from the AgentLib.
  handle_error
  # The return value is used to set some instance
  # variable state depending on the original return
  # of the wrapper methods.
  return_value
end