xref: /qemu/tests/image-fuzzer/qcow2/fuzz.py (revision 6d5e9372f6d968cbee1d6708198abd087db07260)
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