1*a03ca8b9SKrzysztof Kosiński#!/usr/bin/env python 2*a03ca8b9SKrzysztof Kosiński# Copyright 2018 The Chromium Authors. All rights reserved. 3*a03ca8b9SKrzysztof Kosiński# Use of this source code is governed by a BSD-style license that can be 4*a03ca8b9SKrzysztof Kosiński# found in the LICENSE file. 5*a03ca8b9SKrzysztof Kosiński 6*a03ca8b9SKrzysztof Kosiński"""Script for generating new binary protobuf seeds for fuzzers. 7*a03ca8b9SKrzysztof Kosiński 8*a03ca8b9SKrzysztof KosińskiCurrently supports creating a single seed binary protobuf of the form 9*a03ca8b9SKrzysztof Kosińskizucchini.fuzzer.FilePair. 10*a03ca8b9SKrzysztof Kosiński""" 11*a03ca8b9SKrzysztof Kosiński 12*a03ca8b9SKrzysztof Kosińskiimport argparse 13*a03ca8b9SKrzysztof Kosińskiimport hashlib 14*a03ca8b9SKrzysztof Kosińskiimport logging 15*a03ca8b9SKrzysztof Kosińskiimport os 16*a03ca8b9SKrzysztof Kosińskiimport platform 17*a03ca8b9SKrzysztof Kosińskiimport subprocess 18*a03ca8b9SKrzysztof Kosińskiimport sys 19*a03ca8b9SKrzysztof Kosiński 20*a03ca8b9SKrzysztof KosińskiABS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__))) 21*a03ca8b9SKrzysztof KosińskiABS_TESTDATA_PATH = os.path.join(ABS_PATH, 'testdata') 22*a03ca8b9SKrzysztof Kosiński 23*a03ca8b9SKrzysztof Kosińskidef parse_args(): 24*a03ca8b9SKrzysztof Kosiński """Parses arguments from command-line.""" 25*a03ca8b9SKrzysztof Kosiński parser = argparse.ArgumentParser() 26*a03ca8b9SKrzysztof Kosiński parser.add_argument('--raw', help='Whether to use Raw Zucchini.', 27*a03ca8b9SKrzysztof Kosiński action='store_true') 28*a03ca8b9SKrzysztof Kosiński parser.add_argument('old_file', help='Old file to generate/apply patch.') 29*a03ca8b9SKrzysztof Kosiński parser.add_argument('new_file', help='New file to generate patch from.') 30*a03ca8b9SKrzysztof Kosiński parser.add_argument('patch_file', help='Patch filename to use.') 31*a03ca8b9SKrzysztof Kosiński parser.add_argument('output_file', help='File to write binary protobuf to.') 32*a03ca8b9SKrzysztof Kosiński return parser.parse_args() 33*a03ca8b9SKrzysztof Kosiński 34*a03ca8b9SKrzysztof Kosiński 35*a03ca8b9SKrzysztof Kosińskidef gen(old_file, new_file, patch_file, output_file, is_raw, is_win): 36*a03ca8b9SKrzysztof Kosiński """Generates a new patch and binary encodes a protobuf pair.""" 37*a03ca8b9SKrzysztof Kosiński # Create output directory if missing. 38*a03ca8b9SKrzysztof Kosiński output_dir = os.path.dirname(output_file) 39*a03ca8b9SKrzysztof Kosiński if not os.path.exists(output_dir): 40*a03ca8b9SKrzysztof Kosiński os.makedirs(output_dir) 41*a03ca8b9SKrzysztof Kosiński 42*a03ca8b9SKrzysztof Kosiński # Handle Windows executable names. 43*a03ca8b9SKrzysztof Kosiński zucchini = 'zucchini' 44*a03ca8b9SKrzysztof Kosiński protoc = 'protoc' 45*a03ca8b9SKrzysztof Kosiński if is_win: 46*a03ca8b9SKrzysztof Kosiński zucchini += '.exe' 47*a03ca8b9SKrzysztof Kosiński protoc += '.exe' 48*a03ca8b9SKrzysztof Kosiński 49*a03ca8b9SKrzysztof Kosiński zuc_cmd = [os.path.abspath(zucchini), '-gen'] 50*a03ca8b9SKrzysztof Kosiński if is_raw: 51*a03ca8b9SKrzysztof Kosiński zuc_cmd.append('-raw') 52*a03ca8b9SKrzysztof Kosiński # Generate a new patch. 53*a03ca8b9SKrzysztof Kosiński ret = subprocess.call(zuc_cmd + [old_file, new_file, patch_file], 54*a03ca8b9SKrzysztof Kosiński stdout=subprocess.PIPE, 55*a03ca8b9SKrzysztof Kosiński stderr=subprocess.PIPE) 56*a03ca8b9SKrzysztof Kosiński if ret: 57*a03ca8b9SKrzysztof Kosiński logging.error('Patch generation failed for ({}, {})'.format(old_file, 58*a03ca8b9SKrzysztof Kosiński new_file)) 59*a03ca8b9SKrzysztof Kosiński return ret 60*a03ca8b9SKrzysztof Kosiński # Binary encode the protobuf pair. 61*a03ca8b9SKrzysztof Kosiński ret = subprocess.call([sys.executable, 62*a03ca8b9SKrzysztof Kosiński os.path.join(ABS_PATH, 'create_seed_file_pair.py'), 63*a03ca8b9SKrzysztof Kosiński os.path.abspath(protoc), old_file, patch_file, 64*a03ca8b9SKrzysztof Kosiński output_file]) 65*a03ca8b9SKrzysztof Kosiński os.remove(patch_file) 66*a03ca8b9SKrzysztof Kosiński return ret 67*a03ca8b9SKrzysztof Kosiński 68*a03ca8b9SKrzysztof Kosiński 69*a03ca8b9SKrzysztof Kosińskidef main(): 70*a03ca8b9SKrzysztof Kosiński args = parse_args() 71*a03ca8b9SKrzysztof Kosiński return gen(os.path.join(ABS_TESTDATA_PATH, args.old_file), 72*a03ca8b9SKrzysztof Kosiński os.path.join(ABS_TESTDATA_PATH, args.new_file), 73*a03ca8b9SKrzysztof Kosiński os.path.abspath(args.patch_file), 74*a03ca8b9SKrzysztof Kosiński os.path.abspath(args.output_file), 75*a03ca8b9SKrzysztof Kosiński args.raw, 76*a03ca8b9SKrzysztof Kosiński platform.system() == 'Windows') 77*a03ca8b9SKrzysztof Kosiński 78*a03ca8b9SKrzysztof Kosiński 79*a03ca8b9SKrzysztof Kosińskiif __name__ == '__main__': 80*a03ca8b9SKrzysztof Kosiński sys.exit(main()) 81*a03ca8b9SKrzysztof Kosiński 82