On Fri, 07/04 15:39, Maria Kustova wrote: > Layout submodule of qcow2 package creates a random valid image, randomly > selects some amount of its fields, fuzzes them and write the fuzzed image to > the file. > Now only header and header extensions are generated, a remaining file is > filled > by zeroes. > > v1 -> v2: > * Added support of fuzzer configurations. > * Created general Image class: > ** fixed mixed defs/classes module style > ** internalized all functions related to image generation > ** simplified internal image representation > > Signed-off-by: Maria Kustova <mari...@catit.be> > --- > tests/image-fuzzer/qcow2/layout.py | 319 > +++++++++++++++++++++++++++++++++++++ > 1 file changed, 319 insertions(+) > create mode 100644 tests/image-fuzzer/qcow2/layout.py > > diff --git a/tests/image-fuzzer/qcow2/layout.py > b/tests/image-fuzzer/qcow2/layout.py > new file mode 100644 > index 0000000..d6fc1ab > --- /dev/null > +++ b/tests/image-fuzzer/qcow2/layout.py > @@ -0,0 +1,319 @@ > +# Generator of fuzzed qcow2 images > +# > +# Copyright (C) 2014 Maria Kustova <mari...@catit.be> > +# > +# This program is free software: you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation, either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program. If not, see <http://www.gnu.org/licenses/>. > +# > + > +import random > +import struct > +import qcow2.fuzz > + > +MAX_IMAGE_SIZE = 10*2**20 > +# Standard sizes > +UINT32_S = 4 > +UINT64_S = 8 > + > +# Percentage of fields will be fuzzed > +BIAS = random.uniform(0.2, 0.5) > + > + > +class Field(object): > + """Atomic image element (field) > + > + The class represents an image field as quadruple of a data format > + of value necessary for its packing to binary form, an offset from > + the beginning of the image, a value and a name. > + > + The field can be iterated as a list [format, offset, value] > + """ > + __slots__ = ('fmt', 'offset', 'value', 'name') > + > + def __init__(self, fmt, offset, val, name): > + self.fmt = fmt > + self.offset = offset > + self.value = val > + self.name = name > + > + def __iter__(self): > + return (x for x in [self.fmt, self.offset, self.value]) > + > + def __repr__(self): > + return "Field(fmt='%s', offset=%d, value=%s, name=%s)" % \ > + (self.fmt, self.offset, str(self.value), self.name) > + > + > +class FieldsList(object): > + """List of fields > + > + The class allows access to a field in the list by its name and joins > + several list in one via in-place addition > + """ > + def __init__(self, meta_data=None): > + if meta_data is None: > + self.data = [] > + else: > + self.data = [Field(f[0], f[1], f[2], f[3]) > + for f in meta_data] > + > + def __getitem__(self, name): > + return [x for x in self.data if x.name == name] > + > + def __iter__(self): > + return (x for x in self.data) > + > + def __iadd__(self, other): > + self.data += other.data > + return self > + > + def __len__(self): > + return len(self.data) > + > + > +class Image(object): > + """ Qcow2 image object > + > + This class allows to create valid qcow2 images with random structure, > + fuzz them via external qcow2.fuzz module and write to files. > + """ > + @staticmethod > + def _size_params(): > + """Generate a random file size aligned to a random correct cluster > size > + """ > + cluster_bits = random.randrange(9, 21) > + cluster_size = 1 << cluster_bits > + # Minimal image size is equal to 5 clusters as for qcow2 empty image > + # created by qemu-img > + file_size = random.randrange(5*cluster_size, MAX_IMAGE_SIZE + 1, > + cluster_size) > + return [cluster_bits, file_size] > + > + @staticmethod > + def _header(cluster_bits, img_size): > + """Generate a random valid header""" > + meta_header = [ > + ['>4s', 0, "QFI\xfb", 'magic'], > + ['>I', 4, random.randint(2, 3), 'version'], > + ['>Q', 8, 0, 'backing_file_offset'], > + ['>I', 16, 0, 'backing_file_size'], > + ['>I', 20, cluster_bits, 'cluster_bits'], > + ['>Q', 24, img_size, 'size'], > + ['>I', 32, 0, 'crypt_method'], > + ['>I', 36, 0, 'l1_size'], > + ['>Q', 40, 0, 'l1_table_offset'], > + ['>Q', 48, 0, 'refcount_table_offset'], > + ['>I', 56, 0, 'refcount_table_clusters'], > + ['>I', 60, 0, 'nb_snapshots'], > + ['>Q', 64, 0, 'snapshots_offset'], > + ['>Q', 72, 0, 'incompatible_features'], > + ['>Q', 80, 0, 'compatible_features'], > + ['>Q', 88, 0, 'autoclear_features'], > + # From the e-mail thread for [PATCH] docs: Define refcount_bits > + # value: Only refcount_order = 4 is supported by QEMU at the > moment
Better to refer docs/specs/qcow2.txt instead of an email thread, since it's already merged. Fam > + ['>I', 96, 4, 'refcount_order'], > + ['>I', 100, 0, 'header_length'] > + ]