def get_runner(fuzzer_path, temp_dir=None): """Get a libfuzzer runner.""" use_minijail = environment.get_value('USE_MINIJAIL') build_dir = environment.get_value('BUILD_DIR') dataflow_build_dir = environment.get_value('DATAFLOW_BUILD_DIR') if use_minijail: # Set up chroot and runner. if environment.is_chromeos_system_job(): minijail_chroot = minijail.ChromeOSChroot(build_dir) else: minijail_chroot = minijail.MinijailChroot(base_dir=temp_dir) # While it's possible for dynamic binaries to run without this, they need # to be accessible for symbolization etc. For simplicity we bind BUILD_DIR # to the same location within the chroot, which leaks the directory # structure of CF but this shouldn't be a big deal. minijail_chroot.add_binding( minijail.ChrootBinding(build_dir, build_dir, False)) if dataflow_build_dir: minijail_chroot.add_binding( minijail.ChrootBinding(dataflow_build_dir, dataflow_build_dir, False)) # Also bind the build dir to /out to make it easier to hardcode references # to data files. minijail_chroot.add_binding( minijail.ChrootBinding(build_dir, '/out', False)) minijail_bin = os.path.join(minijail_chroot.directory, 'bin') shell.create_directory(minijail_bin) # Set up /bin with llvm-symbolizer to allow symbolized stacktraces. # Don't copy if it already exists (e.g. ChromeOS chroot jail). llvm_symbolizer_source_path = environment.get_llvm_symbolizer_path() llvm_symbolizer_destination_path = os.path.join( minijail_bin, 'llvm-symbolizer') if not os.path.exists(llvm_symbolizer_destination_path): shutil.copy(llvm_symbolizer_source_path, llvm_symbolizer_destination_path) # copy /bin/sh, necessary for system(). if not environment.is_chromeos_system_job(): # The chroot has its own shell we don't need to copy (and probably # shouldn't because of library differences). shutil.copy(os.path.realpath('/bin/sh'), os.path.join(minijail_bin, 'sh')) runner = MinijailLibFuzzerRunner(fuzzer_path, minijail_chroot) elif environment.platform() == 'FUCHSIA': runner = FuchsiaQemuLibFuzzerRunner(fuzzer_path) else: runner = LibFuzzerRunner(fuzzer_path) return runner
def test_minijail(self): """Test minijail process command.""" with minijail.MinijailChroot() as chroot: runner = minijail.MinijailProcessRunner(chroot, '/bin/ls') self.assertListEqual(runner.get_command(), [ '/sbin/minijail', '-U', '-m', '0 1000 1', '-T', 'static', '-c', '0', '-n', '-v', '-p', '-l', '-I', '-k', 'proc,/proc,proc,1', '-P', chroot.directory, '-b', '%s,/tmp,1' % chroot.tmp_directory, '-b', '/lib,/lib,0', '-b', '/lib64,/lib64,0', '-b', '/usr/lib,/usr/lib,0', '/bin/ls' ])
def test_chroot_bindings(self): """Tests chroot setup with additional bind dirs.""" chroot_directory = None with minijail.MinijailChroot(bindings=[ minijail.ChrootBinding('/foo/bar', '/bar', False), ]) as chroot: chroot_directory = chroot.directory self.assertListEqual( sorted(os.listdir(chroot_directory)), ['bar', 'dev', 'lib', 'lib32', 'lib64', 'proc', 'tmp', 'usr']) self.assertEqual(chroot.get_binding('/foo/bar'), minijail.ChrootBinding('/foo/bar', '/bar', False)) self.assertFalse(os.path.exists(chroot_directory))
def test_minijail_pid(self, mock_tempfile, _): """Test minijail process command writing to pid file.""" mock_tempfile.return_value.name = '/temp_pid' with minijail.MinijailChroot() as chroot: runner = minijail.MinijailProcessRunner(chroot, 'bin/ls') process = runner.run() self.assertListEqual(process.command, [ '/sbin/minijail', '-f', '/temp_pid', '-U', '-m', '0 1000 1', '-T', 'static', '-c', '0', '-n', '-v', '-p', '-l', '-I', '-k', 'proc,/proc,proc,1', '-P', chroot.directory, '-b', '%s,/tmp,1' % chroot.tmp_directory, '-b', '/lib,/lib,0', '-b', '/lib64,/lib64,0', '-b', '/usr/lib,/usr/lib,0', 'bin/ls' ])
def test_minijail_bindings(self): """Test minijail process command with additional bind dirs.""" with minijail.MinijailChroot(bindings=[ minijail.ChrootBinding('/foo/bar', '/bar', True), minijail.ChrootBinding('/foo/barr', '/barr', False), ]) as chroot: runner = minijail.MinijailProcessRunner(chroot, '/bin/ls') self.assertListEqual(runner.get_command(), [ '/sbin/minijail', '-U', '-m', '0 1000 1', '-T', 'static', '-c', '0', '-n', '-v', '-p', '-l', '-I', '-k', 'proc,/proc,proc,1', '-P', chroot.directory, '-b', '%s,/tmp,1' % chroot.tmp_directory, '-b', '/lib,/lib,0', '-b', '/lib64,/lib64,0', '-b', '/usr/lib,/usr/lib,0', '-b', '/foo/bar,/bar,1', '-b', '/foo/barr,/barr,0', '/bin/ls' ])
def test_minijail_env_vars(self, mock_popen): """Test passing of env vars.""" os.environ['ASAN_OPTIONS'] = 'asan_option=1' os.environ['AFL_OPTION'] = 'afl_option=1' os.environ['MSAN_OPTIONS'] = 'msan_option=1' os.environ['UBSAN_OPTIONS'] = 'ubsan_option=1' os.environ['SECRET'] = 'secret' os.environ['OTHER'] = 'other' with minijail.MinijailChroot() as chroot: runner = minijail.MinijailProcessRunner(chroot, 'binary') runner.run(env={'MSAN_OPTIONS': 'override=1', 'NAME': 'VALUE'}) self.assertDictEqual({ 'MSAN_OPTIONS': 'override=1', 'PATH': '/bin:/usr/bin', }, mock_popen.call_args[1]['env'])
def test_chroot(self): """Tests basic chroot setup.""" chroot_directory = None with minijail.MinijailChroot() as chroot: chroot_directory = chroot.directory self.assertListEqual( sorted(os.listdir(chroot_directory)), ['dev', 'lib', 'lib32', 'lib64', 'proc', 'tmp', 'usr']) self.assertEqual( chroot.get_binding(chroot.tmp_directory), minijail.ChrootBinding(chroot.tmp_directory, '/tmp', True)) for directory in ['/lib', '/lib32', '/lib64', '/usr/lib']: self.assertEqual( chroot.get_binding(directory), minijail.ChrootBinding(directory, directory, False)) self.assertIsNone(chroot.get_binding('/usr')) self.assertFalse(os.path.exists(chroot_directory))