module Fuzz


fuzzr.rb - TAOX11 Fuzzer bases

Author: Martin Corino

Copyright © Remedy IT Expertise BV



version.rb - TAOX11 fuzz checker

Author: Martin Corino

Copyright © Remedy IT Expertise BV


Constants

FUZZRC
FUZZRC_GLOBAL
FUZZ_ROOT
FUZZ_VERSION
FUZZ_VERSION_MAJOR
FUZZ_VERSION_MINOR
FUZZ_VERSION_RELEASE
OPTIONS

Public Class Methods

apply_fix?() click to toggle source
# File lib/fuzz/fuzz.rb, line 136
def self.apply_fix?
  options.apply_fix || false
end
excluded?(object) click to toggle source
# File lib/fuzz/fuzz.rb, line 148
def self.excluded?(object)
  excludes.any? { |excl| (object.fullpath =~ /#{excl}/) }
end
excludes() click to toggle source
# File lib/fuzz/fuzz.rb, line 144
def self.excludes
  options.config[:excludes] || []
end
fuzzers() click to toggle source

fuzzer registration

# File lib/fuzz/fuzz.rb, line 71
def fuzzers
  @fuzzers ||= {}
end
fzzr_excluded?(fzzr) click to toggle source
# File lib/fuzz/fuzz.rb, line 85
def fzzr_excluded?(fzzr)
  options.config[:fzzr_excludes].include?(fzzr.fuzz_id.to_sym)
end
fzzr_included?(fzzr) click to toggle source
# File lib/fuzz/fuzz.rb, line 89
def fzzr_included?(fzzr)
  !fzzr_excluded?(fzzr)
end
get_fzzr(id) click to toggle source
# File lib/fuzz/fuzz.rb, line 81
def get_fzzr(id)
  fuzzers[id]
end
handle_object(object) click to toggle source
# File lib/fuzz/fuzz.rb, line 312
def self.handle_object(object)
  log_verbose(%Q{Handling #{object}})
  fzzrs = select_fzzrs(object)
  no_fixes_allowed = false
  rc = fzzrs.inject(true) do |result, fzzr|
    log_verbose(%Q{+ Running fuzzer #{fzzr.fuzz_id}})
    begin
      if fzzr.run(object, options.apply_fix)
        result
      else
        log_verbose(%Q{+ Error from fuzzer #{fzzr.fuzz_id}})
        false
      end
    rescue
      log_error(%Q{EXCEPTION CAUGHT running fuzzer #{fzzr.fuzz_id} on #{object} - #{$!}\n#{$!.backtrace.join("\n")}})
      no_fixes_allowed = true
      break ## immediately stop handling this object, rc will remain false
    end
  end
  unless no_fixes_allowed
    if Fuzz.apply_fix? && object.changed?
      rc = update_file_object(object) && rc
    end
  end
  rc ? true : false
end
includes() click to toggle source
# File lib/fuzz/fuzz.rb, line 56
def includes
  unless @include_re
    @include_re = []
    # @include_re << "\\.(#{Fuzz::FileObject.extensions.join('|')})$"
    # @include_re << "#{Fuzz::FileObject.filenames.join('|')}$"
    @include_re << "\\.(#{options.config[:exts].join('|')})$"
    @include_re << "#{options.config[:filenames].join('|')}$"
  end
  @include_re
end
init_optparser() click to toggle source

parse commandline arguments

# File lib/fuzz/fuzz.rb, line 155
def self.init_optparser
  script_name = File.basename($0)
  if not script_name =~ /fuzz/
    script_name = "ruby "+$0
  end

  options.optparser = opts = OptionParser.new
  opts.banner = "Usage: #{script_name} [options] [glob [glob]]\n\n"
  opts.separator "\n--- [General options] ---\n\n"
  opts.on('-t', '--filetype', '=EXT', String,
          'Defines an alternative filetype to search and scan. Can be specified multiple times.',
          "Default: #{Fuzz::FileObject.extensions.join('|')}") { |v|
            (options.user_config[:exts] ||= []) << v
          }
  opts.on('-f', '--file', '=NAME', String,
          'Defines an alternative filename to search and scan. Can be specified multiple times.',
          "Default: #{Fuzz::FileObject.filenames.join('|')}") { |v|
            (options.user_config[:filenames] ||= []) << v
          }
  opts.on('-a', '--add-files',
          'Add custom filenames and/or filetype extensions to default list instead of replacing defaults.',
          'Default: false') { |v|
            options.user_config[:add_files] = true
          }
  opts.on('-S', '--no-symlinks',
          'Do not follow symlinks.',
          'Default: follow symlinks') { |v|
            options.user_config[:follow_symlink] = false
          }
  opts.on('-P', '--fzzr-path', '=PATH',
          'Adds search path for Fuzzers.',
          "Default: loaded from ~/#{FUZZRC} and/or ./#{FUZZRC}") { |v|
            (options.user_config[:fzzr_paths] ||= []) << v.to_s
          }
  opts.on('-B', '--blacklist', '=FZZRID',
          'Adds Fuzzer ID to list of fuzzers to exclude from Fuzz check.',
          'Default: none') { |v|
            (options.user_config[:fzzr_excludes] ||= []) << v.to_sym
          }
  opts.on('-X', '--exclude', '=MASK',
          'Adds path mask (regular expression) to list to exclude from Fuzz check.',
          'Default: none') { |v|
            (options.user_config[:excludes] ||= []) << v
          }
  opts.on('-c', '--config', '=FUZZRC',
          'Load config from FUZZRC file.',
          "Default:  ~/#{FUZZRC} and/or ./#{FUZZRC}") { |v|
    options.add_config(v)
  }
  opts.on('--write-config', '=[FUZZRC]',
          'Write config to file and exit.',
          "Default: ./#{FUZZRC}") { |v|
    options.user_config.save(String === v ? v : FUZZRC)
    exit
  }
  opts.on('--show-config',
          'Display config settings and exit.') { |v|
    options.load_config
    puts YAML.dump(options.config.__send__ :table)
    exit
  }

  opts.separator ''
  opts.on('-o', '--output', '=FILE', String,
          'Specifies filename to write Fuzz messages to.',
          'Default: stderr') { |v|
            options.output = v
          }
  opts.on('-p', '--apply-fix',
          'Apply fixes (if any) for Fuzz errors.',
          'Default: false') { |v|
            options.apply_fix = true
          }
  opts.on('-n', '--no-recurse',
          'Prevents directory recursion in file selection.',
          'Default: recurse') { |v|
            options.recurse = false
          }
  opts.on('-v', '--verbose',
          'Run with increased verbosity level. Repeat to increase more.',
          'Default: 1') { |v| options.verbose += 1 }

  opts.separator ''
  opts.on('-L', '--list',
          'List available Fuzzers and exit.') {
    options.load_config
    load_fuzzers
    puts "TAOX11 fuzz checker #{FUZZ_VERSION_MAJOR}.#{FUZZ_VERSION_MINOR}.#{FUZZ_VERSION_RELEASE}"
    puts FUZZ_COPYRIGHT
    puts('%-30s %s' % %w{Fuzzer Description})
    puts(('-' * 30)+' '+('-' * 48))
    fuzzers.values.each { |fzzr| puts('%-30s %s' % [fzzr.fuzz_id, fzzr.description]) }
    puts
    exit
  }

  opts.separator ""
  opts.on('-V', '--version',
          'Show version information and exit.') {
    puts "TAOX11 fuzz checker #{FUZZ_VERSION_MAJOR}.#{FUZZ_VERSION_MINOR}.#{FUZZ_VERSION_RELEASE}"
    puts FUZZ_COPYRIGHT
    exit
  }
  opts.on('-h', '--help',
          'Show this help message.') {
    options.load_config
    load_fuzzers
    puts opts;
    puts;
    exit
  }

  opts.separator "\n--- [Fuzzer options] ---\n\n"
end
iterate_paths(paths) click to toggle source
# File lib/fuzz/fuzz.rb, line 339
def self.iterate_paths(paths)
  paths.inject(true) do |result, path|
    if File.readable?(path) && (!File.symlink?(path) || follow_symlink?)
      if File.directory?(path)
        rc = handle_object(dirobj = Fuzz::DirObject.new(path))
        log_verbose(%Q{Iterating #{path}})
        if options.recurse && !excluded?(dirobj)
          rc = iterate_paths(Dir.glob(File.join(path, '*'))) && rc
        end
        rc
      elsif File.file?(path)
        handle_object(Fuzz::FileObject.new(path))
      else
        true
      end
    else
      log_warning(File.readable?(path) ? %Q{Cannot read #{path}} : %Q{Cannot follow symlink #{path}})
      false
    end && result
  end
end
load_config() click to toggle source
# File lib/fuzz/fuzz.rb, line 52
def load_config
  options.load_config
end
load_fuzzers() click to toggle source

load fuzzers

# File lib/fuzz/fuzz.rb, line 96
def load_fuzzers
  # standard fuzzers included in Gem
  unless loaded_fzzr_paths.include?(_p = File.join(FUZZ_ROOT, 'fuzzers'))
    Dir.glob(File.join(_p, '*.rb')).each do |fnm|
      require fnm
    end
    loaded_fzzr_paths << _p
  end
  # configured fuzzers
  options.config[:fzzr_paths].each do |fzzrpath|
    unless loaded_fzzr_paths.include?(_p = File.expand_path(fzzrpath))
      Dir.glob(File.join(_p, '*.rb')).each do |fnm|
        require fnm
      end
      loaded_fzzr_paths << _p
    end
  end
end
log_verbose(msg) click to toggle source

Backwards compatibility

# File lib/fuzz/fuzz.rb, line 124
def self.log_verbose(msg)
  log_info(msg) if verbose?
end
options() click to toggle source
# File lib/fuzz/fuzz.rb, line 44
def options
  Fuzz::OPTIONS
end
parse_args(argv) click to toggle source
# File lib/fuzz/fuzz.rb, line 270
def self.parse_args(argv)
  options.optparser.parse!(argv)
end
register_fzzr(fzzr) click to toggle source
# File lib/fuzz/fuzz.rb, line 75
def register_fzzr(fzzr)
  raise "Duplicate fuzzer registration: #{fzzr.fuzz_id}" if fuzzers.has_key?(fzzr.fuzz_id)
  fuzzers[fzzr.fuzz_id] = fzzr
  fzzr.setup(options.optparser) if options.optparser && fzzr.respond_to?(:setup) && fzzr_included?(fzzr)
end
reporter() click to toggle source
# File lib/fuzz/fuzz.rb, line 35
def reporter
  @reporter ||= Fuzz::Reporter.new
end
reporter=(rep)
Alias for: set_reporter
reset() click to toggle source
# File lib/fuzz/fuzz.rb, line 48
def reset
  options.reset
end
root_path() click to toggle source
# File lib/fuzz/fuzz.rb, line 22
def self.root_path
  f = File.expand_path(__FILE__)
  f = File.expand_path(File.readlink(f)) if File.symlink?(f)
  File.dirname(f)
end
run() click to toggle source
# File lib/fuzz/fuzz.rb, line 384
def self.run
  init_optparser

  # parse arguments
  parse_args(ARGV)

  # load config (if any)
  options.load_config

  # load fuzzers
  load_fuzzers

  run_fzzrs(ARGV)
end
run_fzzrs(argv) click to toggle source
# File lib/fuzz/fuzz.rb, line 361
def self.run_fzzrs(argv)
  options.config[:exts].concat(Fuzz::FileObject.extensions) if options.config[:exts].empty? || options.config[:add_files]
  options.config[:filenames].concat(Fuzz::FileObject.filenames) if options.config[:filenames].empty? || options.config[:add_files]

  options.config[:exts].uniq!
  options.config[:filenames].uniq!

  f_close_output = false
  if String === options.output
    options.output = File.open(options.output, 'w')
    f_close_output = true
  end
  begin
    # determin files/paths to test
    paths = argv.collect { |a| Dir.glob(a) }.flatten.uniq
    paths = Dir.glob('*') if paths.empty?
    # scan all determined objects
    return iterate_paths(paths)
  ensure
    options.output.close if f_close_output
  end
end
select_fzzrs(object) click to toggle source
# File lib/fuzz/fuzz.rb, line 274
def self.select_fzzrs(object)
  fuzzers.values.collect { |fzzr| (fzzr_included?(fzzr) && fzzr.applies_to?(object)) ? fzzr : nil }.compact
end
set_reporter(rep) click to toggle source
# File lib/fuzz/fuzz.rb, line 39
def set_reporter(rep)
  @reporter = rep
end
Also aliased as: reporter=
update_file_object(fo) click to toggle source
# File lib/fuzz/fuzz.rb, line 278
def self.update_file_object(fo)
  if File.writable?(fo.fullpath)
    log_verbose(%Q{Updating #{fo}...})
    ftmp = Tempfile.new(fo.name)
    log_verbose(%Q{+ Writing temp file #{ftmp.path}...})
    fo.lines.each { |ln| ftmp.print ln }
    ftmp.close(false) # close but do NOT unlink
    log_verbose(%Q{+ Replacing #{fo} with #{ftmp.path}})
    # create temporary backup
    ftmp2 = Tempfile.new(fo.name)
    ftmp2_name = ftmp2.path.dup
    ftmp2.close(true)
    mv(fo.fullpath, ftmp2_name)
    # replace original
    begin
      mv(ftmp.path, fo.fullpath)
      # preserve file mode
      chmod(File.lstat(ftmp2_name).mode, fo.fullpath)
    rescue
      log_error(%Q{FAILED updating #{fo}: #{$!}})
      # restore backup
      mv(ftmp2_name, fo.fullpath)
      raise
    end
    # remove backup
    File.unlink(ftmp2_name)
    log_verbose(%Q{Finished updating #{fo}.})
    return true
  else
    log_error(%Q{NO_ACCESS - cannot update #{fo}})
    return false
  end
end
verbosity() click to toggle source

Option methods

# File lib/fuzz/fuzz.rb, line 132
def self.verbosity
  options.verbose
end

Private Class Methods

loaded_fzzr_paths() click to toggle source
# File lib/fuzz/fuzz.rb, line 117
def loaded_fzzr_paths
  @loaded_fuzzr_paths ||= []
end