cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

qcow2.py (4555B)


      1#!/usr/bin/env python3
      2#
      3# Manipulations with qcow2 image
      4#
      5# Copyright (C) 2012 Red Hat, Inc.
      6#
      7# This program is free software; you can redistribute it and/or modify
      8# it under the terms of the GNU General Public License as published by
      9# the Free Software Foundation; either version 2 of the License, or
     10# (at your option) any later version.
     11#
     12# This program is distributed in the hope that it will be useful,
     13# but WITHOUT ANY WARRANTY; without even the implied warranty of
     14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15# GNU General Public License for more details.
     16#
     17# You should have received a copy of the GNU General Public License
     18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
     19#
     20
     21import sys
     22
     23from qcow2_format import (
     24    QcowHeader,
     25    QcowHeaderExtension
     26)
     27
     28
     29is_json = False
     30
     31
     32def cmd_dump_header(fd):
     33    h = QcowHeader(fd)
     34    h.dump(is_json)
     35    print()
     36    h.dump_extensions(is_json)
     37
     38
     39def cmd_dump_header_exts(fd):
     40    h = QcowHeader(fd)
     41    h.dump_extensions(is_json)
     42
     43
     44def cmd_set_header(fd, name, value):
     45    try:
     46        value = int(value, 0)
     47    except ValueError:
     48        print("'%s' is not a valid number" % value)
     49        sys.exit(1)
     50
     51    fields = (field[2] for field in QcowHeader.fields)
     52    if name not in fields:
     53        print("'%s' is not a known header field" % name)
     54        sys.exit(1)
     55
     56    h = QcowHeader(fd)
     57    h.__dict__[name] = value
     58    h.update(fd)
     59
     60
     61def cmd_add_header_ext(fd, magic, data):
     62    try:
     63        magic = int(magic, 0)
     64    except ValueError:
     65        print("'%s' is not a valid magic number" % magic)
     66        sys.exit(1)
     67
     68    h = QcowHeader(fd)
     69    h.extensions.append(QcowHeaderExtension.create(magic,
     70                                                   data.encode('ascii')))
     71    h.update(fd)
     72
     73
     74def cmd_add_header_ext_stdio(fd, magic):
     75    data = sys.stdin.read()
     76    cmd_add_header_ext(fd, magic, data)
     77
     78
     79def cmd_del_header_ext(fd, magic):
     80    try:
     81        magic = int(magic, 0)
     82    except ValueError:
     83        print("'%s' is not a valid magic number" % magic)
     84        sys.exit(1)
     85
     86    h = QcowHeader(fd)
     87    found = False
     88
     89    for ex in h.extensions:
     90        if ex.magic == magic:
     91            found = True
     92            h.extensions.remove(ex)
     93
     94    if not found:
     95        print("No such header extension")
     96        return
     97
     98    h.update(fd)
     99
    100
    101def cmd_set_feature_bit(fd, group, bit):
    102    try:
    103        bit = int(bit, 0)
    104        if bit < 0 or bit >= 64:
    105            raise ValueError
    106    except ValueError:
    107        print("'%s' is not a valid bit number in range [0, 64)" % bit)
    108        sys.exit(1)
    109
    110    h = QcowHeader(fd)
    111    if group == 'incompatible':
    112        h.incompatible_features |= 1 << bit
    113    elif group == 'compatible':
    114        h.compatible_features |= 1 << bit
    115    elif group == 'autoclear':
    116        h.autoclear_features |= 1 << bit
    117    else:
    118        print("'%s' is not a valid group, try "
    119              "'incompatible', 'compatible', or 'autoclear'" % group)
    120        sys.exit(1)
    121
    122    h.update(fd)
    123
    124
    125cmds = [
    126    ['dump-header', cmd_dump_header, 0,
    127     'Dump image header and header extensions'],
    128    ['dump-header-exts', cmd_dump_header_exts, 0,
    129     'Dump image header extensions'],
    130    ['set-header', cmd_set_header, 2, 'Set a field in the header'],
    131    ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'],
    132    ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1,
    133     'Add a header extension, data from stdin'],
    134    ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'],
    135    ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
    136]
    137
    138
    139def main(filename, cmd, args):
    140    fd = open(filename, "r+b")
    141    try:
    142        for name, handler, num_args, desc in cmds:
    143            if name != cmd:
    144                continue
    145            elif len(args) != num_args:
    146                usage()
    147                return
    148            else:
    149                handler(fd, *args)
    150                return
    151        print("Unknown command '%s'" % cmd)
    152    finally:
    153        fd.close()
    154
    155
    156def usage():
    157    print("Usage: %s <file> <cmd> [<arg>, ...] [<key>, ...]" % sys.argv[0])
    158    print("")
    159    print("Supported commands:")
    160    for name, handler, num_args, desc in cmds:
    161        print("    %-20s - %s" % (name, desc))
    162    print("")
    163    print("Supported keys:")
    164    print("    %-20s - %s" % ('-j', 'Dump in JSON format'))
    165
    166
    167if __name__ == '__main__':
    168    if len(sys.argv) < 3:
    169        usage()
    170        sys.exit(1)
    171
    172    is_json = '-j' in sys.argv
    173    if is_json:
    174        sys.argv.remove('-j')
    175
    176    main(sys.argv[1], sys.argv[2], sys.argv[3:])