1*6d5e9372SMaria Kustova# Fuzzing functions for qcow2 fields 2*6d5e9372SMaria Kustova# 3*6d5e9372SMaria Kustova# Copyright (C) 2014 Maria Kustova <maria.k@catit.be> 4*6d5e9372SMaria Kustova# 5*6d5e9372SMaria Kustova# This program is free software: you can redistribute it and/or modify 6*6d5e9372SMaria Kustova# it under the terms of the GNU General Public License as published by 7*6d5e9372SMaria Kustova# the Free Software Foundation, either version 2 of the License, or 8*6d5e9372SMaria Kustova# (at your option) any later version. 9*6d5e9372SMaria Kustova# 10*6d5e9372SMaria Kustova# This program is distributed in the hope that it will be useful, 11*6d5e9372SMaria Kustova# but WITHOUT ANY WARRANTY; without even the implied warranty of 12*6d5e9372SMaria Kustova# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*6d5e9372SMaria Kustova# GNU General Public License for more details. 14*6d5e9372SMaria Kustova# 15*6d5e9372SMaria Kustova# You should have received a copy of the GNU General Public License 16*6d5e9372SMaria Kustova# along with this program. If not, see <http://www.gnu.org/licenses/>. 17*6d5e9372SMaria Kustova# 18*6d5e9372SMaria Kustova 19*6d5e9372SMaria Kustovaimport random 20*6d5e9372SMaria Kustova 21*6d5e9372SMaria Kustova 22*6d5e9372SMaria KustovaUINT8 = 0xff 23*6d5e9372SMaria KustovaUINT32 = 0xffffffff 24*6d5e9372SMaria KustovaUINT64 = 0xffffffffffffffff 25*6d5e9372SMaria Kustova# Most significant bit orders 26*6d5e9372SMaria KustovaUINT32_M = 31 27*6d5e9372SMaria KustovaUINT64_M = 63 28*6d5e9372SMaria Kustova# Fuzz vectors 29*6d5e9372SMaria KustovaUINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1, 30*6d5e9372SMaria Kustova UINT8] 31*6d5e9372SMaria KustovaUINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1, 32*6d5e9372SMaria Kustova UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32] 33*6d5e9372SMaria KustovaUINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4, 34*6d5e9372SMaria Kustova UINT64/2 - 1, UINT64/2, UINT64/2 + 1, UINT64 - 1, 35*6d5e9372SMaria Kustova UINT64] 36*6d5e9372SMaria KustovaSTRING_V = ['%s%p%x%d', '.1024d', '%.2049d', '%p%p%p%p', '%x%x%x%x', 37*6d5e9372SMaria Kustova '%d%d%d%d', '%s%s%s%s', '%99999999999s', '%08x', '%%20d', '%%20n', 38*6d5e9372SMaria Kustova '%%20x', '%%20s', '%s%s%s%s%s%s%s%s%s%s', '%p%p%p%p%p%p%p%p%p%p', 39*6d5e9372SMaria Kustova '%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', 40*6d5e9372SMaria Kustova '%s x 129', '%x x 257'] 41*6d5e9372SMaria Kustova 42*6d5e9372SMaria Kustova 43*6d5e9372SMaria Kustovadef random_from_intervals(intervals): 44*6d5e9372SMaria Kustova """Select a random integer number from the list of specified intervals. 45*6d5e9372SMaria Kustova 46*6d5e9372SMaria Kustova Each interval is a tuple of lower and upper limits of the interval. The 47*6d5e9372SMaria Kustova limits are included. Intervals in a list should not overlap. 48*6d5e9372SMaria Kustova """ 49*6d5e9372SMaria Kustova total = reduce(lambda x, y: x + y[1] - y[0] + 1, intervals, 0) 50*6d5e9372SMaria Kustova r = random.randint(0, total - 1) + intervals[0][0] 51*6d5e9372SMaria Kustova for x in zip(intervals, intervals[1:]): 52*6d5e9372SMaria Kustova r = r + (r > x[0][1]) * (x[1][0] - x[0][1] - 1) 53*6d5e9372SMaria Kustova return r 54*6d5e9372SMaria Kustova 55*6d5e9372SMaria Kustova 56*6d5e9372SMaria Kustovadef random_bits(bit_ranges): 57*6d5e9372SMaria Kustova """Generate random binary mask with ones in the specified bit ranges. 58*6d5e9372SMaria Kustova 59*6d5e9372SMaria Kustova Each bit_ranges is a list of tuples of lower and upper limits of bit 60*6d5e9372SMaria Kustova positions will be fuzzed. The limits are included. Random amount of bits 61*6d5e9372SMaria Kustova in range limits will be set to ones. The mask is returned in decimal 62*6d5e9372SMaria Kustova integer format. 63*6d5e9372SMaria Kustova """ 64*6d5e9372SMaria Kustova bit_numbers = [] 65*6d5e9372SMaria Kustova # Select random amount of random positions in bit_ranges 66*6d5e9372SMaria Kustova for rng in bit_ranges: 67*6d5e9372SMaria Kustova bit_numbers += random.sample(range(rng[0], rng[1] + 1), 68*6d5e9372SMaria Kustova random.randint(0, rng[1] - rng[0] + 1)) 69*6d5e9372SMaria Kustova val = 0 70*6d5e9372SMaria Kustova # Set bits on selected positions to ones 71*6d5e9372SMaria Kustova for bit in bit_numbers: 72*6d5e9372SMaria Kustova val |= 1 << bit 73*6d5e9372SMaria Kustova return val 74*6d5e9372SMaria Kustova 75*6d5e9372SMaria Kustova 76*6d5e9372SMaria Kustovadef truncate_string(strings, length): 77*6d5e9372SMaria Kustova """Return strings truncated to specified length.""" 78*6d5e9372SMaria Kustova if type(strings) == list: 79*6d5e9372SMaria Kustova return [s[:length] for s in strings] 80*6d5e9372SMaria Kustova else: 81*6d5e9372SMaria Kustova return strings[:length] 82*6d5e9372SMaria Kustova 83*6d5e9372SMaria Kustova 84*6d5e9372SMaria Kustovadef validator(current, pick, choices): 85*6d5e9372SMaria Kustova """Return a value not equal to the current selected by the pick 86*6d5e9372SMaria Kustova function from choices. 87*6d5e9372SMaria Kustova """ 88*6d5e9372SMaria Kustova while True: 89*6d5e9372SMaria Kustova val = pick(choices) 90*6d5e9372SMaria Kustova if not val == current: 91*6d5e9372SMaria Kustova return val 92*6d5e9372SMaria Kustova 93*6d5e9372SMaria Kustova 94*6d5e9372SMaria Kustovadef int_validator(current, intervals): 95*6d5e9372SMaria Kustova """Return a random value from intervals not equal to the current. 96*6d5e9372SMaria Kustova 97*6d5e9372SMaria Kustova This function is useful for selection from valid values except current one. 98*6d5e9372SMaria Kustova """ 99*6d5e9372SMaria Kustova return validator(current, random_from_intervals, intervals) 100*6d5e9372SMaria Kustova 101*6d5e9372SMaria Kustova 102*6d5e9372SMaria Kustovadef bit_validator(current, bit_ranges): 103*6d5e9372SMaria Kustova """Return a random bit mask not equal to the current. 104*6d5e9372SMaria Kustova 105*6d5e9372SMaria Kustova This function is useful for selection from valid values except current one. 106*6d5e9372SMaria Kustova """ 107*6d5e9372SMaria Kustova return validator(current, random_bits, bit_ranges) 108*6d5e9372SMaria Kustova 109*6d5e9372SMaria Kustova 110*6d5e9372SMaria Kustovadef string_validator(current, strings): 111*6d5e9372SMaria Kustova """Return a random string value from the list not equal to the current. 112*6d5e9372SMaria Kustova 113*6d5e9372SMaria Kustova This function is useful for selection from valid values except current one. 114*6d5e9372SMaria Kustova """ 115*6d5e9372SMaria Kustova return validator(current, random.choice, strings) 116*6d5e9372SMaria Kustova 117*6d5e9372SMaria Kustova 118*6d5e9372SMaria Kustovadef selector(current, constraints, validate=int_validator): 119*6d5e9372SMaria Kustova """Select one value from all defined by constraints. 120*6d5e9372SMaria Kustova 121*6d5e9372SMaria Kustova Each constraint produces one random value satisfying to it. The function 122*6d5e9372SMaria Kustova randomly selects one value satisfying at least one constraint (depending on 123*6d5e9372SMaria Kustova constraints overlaps). 124*6d5e9372SMaria Kustova """ 125*6d5e9372SMaria Kustova def iter_validate(c): 126*6d5e9372SMaria Kustova """Apply validate() only to constraints represented as lists. 127*6d5e9372SMaria Kustova 128*6d5e9372SMaria Kustova This auxiliary function replaces short circuit conditions not supported 129*6d5e9372SMaria Kustova in Python 2.4 130*6d5e9372SMaria Kustova """ 131*6d5e9372SMaria Kustova if type(c) == list: 132*6d5e9372SMaria Kustova return validate(current, c) 133*6d5e9372SMaria Kustova else: 134*6d5e9372SMaria Kustova return c 135*6d5e9372SMaria Kustova 136*6d5e9372SMaria Kustova fuzz_values = [iter_validate(c) for c in constraints] 137*6d5e9372SMaria Kustova # Remove current for cases it's implicitly specified in constraints 138*6d5e9372SMaria Kustova # Duplicate validator functionality to prevent decreasing of probability 139*6d5e9372SMaria Kustova # to get one of allowable values 140*6d5e9372SMaria Kustova # TODO: remove validators after implementation of intelligent selection 141*6d5e9372SMaria Kustova # of fields will be fuzzed 142*6d5e9372SMaria Kustova try: 143*6d5e9372SMaria Kustova fuzz_values.remove(current) 144*6d5e9372SMaria Kustova except ValueError: 145*6d5e9372SMaria Kustova pass 146*6d5e9372SMaria Kustova return random.choice(fuzz_values) 147*6d5e9372SMaria Kustova 148*6d5e9372SMaria Kustova 149*6d5e9372SMaria Kustovadef magic(current): 150*6d5e9372SMaria Kustova """Fuzz magic header field. 151*6d5e9372SMaria Kustova 152*6d5e9372SMaria Kustova The function just returns the current magic value and provides uniformity 153*6d5e9372SMaria Kustova of calls for all fuzzing functions. 154*6d5e9372SMaria Kustova """ 155*6d5e9372SMaria Kustova return current 156*6d5e9372SMaria Kustova 157*6d5e9372SMaria Kustova 158*6d5e9372SMaria Kustovadef version(current): 159*6d5e9372SMaria Kustova """Fuzz version header field.""" 160*6d5e9372SMaria Kustova constraints = UINT32_V + [ 161*6d5e9372SMaria Kustova [(2, 3)], # correct values 162*6d5e9372SMaria Kustova [(0, 1), (4, UINT32)] 163*6d5e9372SMaria Kustova ] 164*6d5e9372SMaria Kustova return selector(current, constraints) 165*6d5e9372SMaria Kustova 166*6d5e9372SMaria Kustova 167*6d5e9372SMaria Kustovadef backing_file_offset(current): 168*6d5e9372SMaria Kustova """Fuzz backing file offset header field.""" 169*6d5e9372SMaria Kustova constraints = UINT64_V 170*6d5e9372SMaria Kustova return selector(current, constraints) 171*6d5e9372SMaria Kustova 172*6d5e9372SMaria Kustova 173*6d5e9372SMaria Kustovadef backing_file_size(current): 174*6d5e9372SMaria Kustova """Fuzz backing file size header field.""" 175*6d5e9372SMaria Kustova constraints = UINT32_V 176*6d5e9372SMaria Kustova return selector(current, constraints) 177*6d5e9372SMaria Kustova 178*6d5e9372SMaria Kustova 179*6d5e9372SMaria Kustovadef cluster_bits(current): 180*6d5e9372SMaria Kustova """Fuzz cluster bits header field.""" 181*6d5e9372SMaria Kustova constraints = UINT32_V + [ 182*6d5e9372SMaria Kustova [(9, 20)], # correct values 183*6d5e9372SMaria Kustova [(0, 9), (20, UINT32)] 184*6d5e9372SMaria Kustova ] 185*6d5e9372SMaria Kustova return selector(current, constraints) 186*6d5e9372SMaria Kustova 187*6d5e9372SMaria Kustova 188*6d5e9372SMaria Kustovadef size(current): 189*6d5e9372SMaria Kustova """Fuzz image size header field.""" 190*6d5e9372SMaria Kustova constraints = UINT64_V 191*6d5e9372SMaria Kustova return selector(current, constraints) 192*6d5e9372SMaria Kustova 193*6d5e9372SMaria Kustova 194*6d5e9372SMaria Kustovadef crypt_method(current): 195*6d5e9372SMaria Kustova """Fuzz crypt method header field.""" 196*6d5e9372SMaria Kustova constraints = UINT32_V + [ 197*6d5e9372SMaria Kustova 1, 198*6d5e9372SMaria Kustova [(2, UINT32)] 199*6d5e9372SMaria Kustova ] 200*6d5e9372SMaria Kustova return selector(current, constraints) 201*6d5e9372SMaria Kustova 202*6d5e9372SMaria Kustova 203*6d5e9372SMaria Kustovadef l1_size(current): 204*6d5e9372SMaria Kustova """Fuzz L1 table size header field.""" 205*6d5e9372SMaria Kustova constraints = UINT32_V 206*6d5e9372SMaria Kustova return selector(current, constraints) 207*6d5e9372SMaria Kustova 208*6d5e9372SMaria Kustova 209*6d5e9372SMaria Kustovadef l1_table_offset(current): 210*6d5e9372SMaria Kustova """Fuzz L1 table offset header field.""" 211*6d5e9372SMaria Kustova constraints = UINT64_V 212*6d5e9372SMaria Kustova return selector(current, constraints) 213*6d5e9372SMaria Kustova 214*6d5e9372SMaria Kustova 215*6d5e9372SMaria Kustovadef refcount_table_offset(current): 216*6d5e9372SMaria Kustova """Fuzz refcount table offset header field.""" 217*6d5e9372SMaria Kustova constraints = UINT64_V 218*6d5e9372SMaria Kustova return selector(current, constraints) 219*6d5e9372SMaria Kustova 220*6d5e9372SMaria Kustova 221*6d5e9372SMaria Kustovadef refcount_table_clusters(current): 222*6d5e9372SMaria Kustova """Fuzz refcount table clusters header field.""" 223*6d5e9372SMaria Kustova constraints = UINT32_V 224*6d5e9372SMaria Kustova return selector(current, constraints) 225*6d5e9372SMaria Kustova 226*6d5e9372SMaria Kustova 227*6d5e9372SMaria Kustovadef nb_snapshots(current): 228*6d5e9372SMaria Kustova """Fuzz number of snapshots header field.""" 229*6d5e9372SMaria Kustova constraints = UINT32_V 230*6d5e9372SMaria Kustova return selector(current, constraints) 231*6d5e9372SMaria Kustova 232*6d5e9372SMaria Kustova 233*6d5e9372SMaria Kustovadef snapshots_offset(current): 234*6d5e9372SMaria Kustova """Fuzz snapshots offset header field.""" 235*6d5e9372SMaria Kustova constraints = UINT64_V 236*6d5e9372SMaria Kustova return selector(current, constraints) 237*6d5e9372SMaria Kustova 238*6d5e9372SMaria Kustova 239*6d5e9372SMaria Kustovadef incompatible_features(current): 240*6d5e9372SMaria Kustova """Fuzz incompatible features header field.""" 241*6d5e9372SMaria Kustova constraints = [ 242*6d5e9372SMaria Kustova [(0, 1)], # allowable values 243*6d5e9372SMaria Kustova [(0, UINT64_M)] 244*6d5e9372SMaria Kustova ] 245*6d5e9372SMaria Kustova return selector(current, constraints, bit_validator) 246*6d5e9372SMaria Kustova 247*6d5e9372SMaria Kustova 248*6d5e9372SMaria Kustovadef compatible_features(current): 249*6d5e9372SMaria Kustova """Fuzz compatible features header field.""" 250*6d5e9372SMaria Kustova constraints = [ 251*6d5e9372SMaria Kustova [(0, UINT64_M)] 252*6d5e9372SMaria Kustova ] 253*6d5e9372SMaria Kustova return selector(current, constraints, bit_validator) 254*6d5e9372SMaria Kustova 255*6d5e9372SMaria Kustova 256*6d5e9372SMaria Kustovadef autoclear_features(current): 257*6d5e9372SMaria Kustova """Fuzz autoclear features header field.""" 258*6d5e9372SMaria Kustova constraints = [ 259*6d5e9372SMaria Kustova [(0, UINT64_M)] 260*6d5e9372SMaria Kustova ] 261*6d5e9372SMaria Kustova return selector(current, constraints, bit_validator) 262*6d5e9372SMaria Kustova 263*6d5e9372SMaria Kustova 264*6d5e9372SMaria Kustovadef refcount_order(current): 265*6d5e9372SMaria Kustova """Fuzz number of refcount order header field.""" 266*6d5e9372SMaria Kustova constraints = UINT32_V 267*6d5e9372SMaria Kustova return selector(current, constraints) 268*6d5e9372SMaria Kustova 269*6d5e9372SMaria Kustova 270*6d5e9372SMaria Kustovadef header_length(current): 271*6d5e9372SMaria Kustova """Fuzz number of refcount order header field.""" 272*6d5e9372SMaria Kustova constraints = UINT32_V + [ 273*6d5e9372SMaria Kustova 72, 274*6d5e9372SMaria Kustova 104, 275*6d5e9372SMaria Kustova [(0, UINT32)] 276*6d5e9372SMaria Kustova ] 277*6d5e9372SMaria Kustova return selector(current, constraints) 278*6d5e9372SMaria Kustova 279*6d5e9372SMaria Kustova 280*6d5e9372SMaria Kustovadef bf_name(current): 281*6d5e9372SMaria Kustova """Fuzz the backing file name.""" 282*6d5e9372SMaria Kustova constraints = [ 283*6d5e9372SMaria Kustova truncate_string(STRING_V, len(current)) 284*6d5e9372SMaria Kustova ] 285*6d5e9372SMaria Kustova return selector(current, constraints, string_validator) 286*6d5e9372SMaria Kustova 287*6d5e9372SMaria Kustova 288*6d5e9372SMaria Kustovadef ext_magic(current): 289*6d5e9372SMaria Kustova """Fuzz magic field of a header extension.""" 290*6d5e9372SMaria Kustova constraints = UINT32_V 291*6d5e9372SMaria Kustova return selector(current, constraints) 292*6d5e9372SMaria Kustova 293*6d5e9372SMaria Kustova 294*6d5e9372SMaria Kustovadef ext_length(current): 295*6d5e9372SMaria Kustova """Fuzz length field of a header extension.""" 296*6d5e9372SMaria Kustova constraints = UINT32_V 297*6d5e9372SMaria Kustova return selector(current, constraints) 298*6d5e9372SMaria Kustova 299*6d5e9372SMaria Kustova 300*6d5e9372SMaria Kustovadef bf_format(current): 301*6d5e9372SMaria Kustova """Fuzz backing file format in the corresponding header extension.""" 302*6d5e9372SMaria Kustova constraints = [ 303*6d5e9372SMaria Kustova truncate_string(STRING_V, len(current)), 304*6d5e9372SMaria Kustova truncate_string(STRING_V, (len(current) + 7) & ~7) # Fuzz padding 305*6d5e9372SMaria Kustova ] 306*6d5e9372SMaria Kustova return selector(current, constraints, string_validator) 307*6d5e9372SMaria Kustova 308*6d5e9372SMaria Kustova 309*6d5e9372SMaria Kustovadef feature_type(current): 310*6d5e9372SMaria Kustova """Fuzz feature type field of a feature name table header extension.""" 311*6d5e9372SMaria Kustova constraints = UINT8_V 312*6d5e9372SMaria Kustova return selector(current, constraints) 313*6d5e9372SMaria Kustova 314*6d5e9372SMaria Kustova 315*6d5e9372SMaria Kustovadef feature_bit_number(current): 316*6d5e9372SMaria Kustova """Fuzz bit number field of a feature name table header extension.""" 317*6d5e9372SMaria Kustova constraints = UINT8_V 318*6d5e9372SMaria Kustova return selector(current, constraints) 319*6d5e9372SMaria Kustova 320*6d5e9372SMaria Kustova 321*6d5e9372SMaria Kustovadef feature_name(current): 322*6d5e9372SMaria Kustova """Fuzz feature name field of a feature name table header extension.""" 323*6d5e9372SMaria Kustova constraints = [ 324*6d5e9372SMaria Kustova truncate_string(STRING_V, len(current)), 325*6d5e9372SMaria Kustova truncate_string(STRING_V, 46) # Fuzz padding (field length = 46) 326*6d5e9372SMaria Kustova ] 327*6d5e9372SMaria Kustova return selector(current, constraints, string_validator) 328