1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
# -*- coding: utf-8 -*-
"""
Libxl Migration v2 streams
Record structures as per docs/specs/libxl-migration-stream.pandoc, and
verification routines.
"""
import sys
from struct import calcsize, unpack, unpack_from
from xen.migration.verify import StreamError, RecordError, VerifyBase
from xen.migration.libxc import VerifyLibxc
# Header
HDR_FORMAT = "!QII"
HDR_IDENT = 0x4c6962786c466d74 # "LibxlFmt" in ASCII
HDR_VERSION = 2
HDR_OPT_BIT_ENDIAN = 0
HDR_OPT_BIT_LEGACY = 1
HDR_OPT_LE = (0 << HDR_OPT_BIT_ENDIAN)
HDR_OPT_BE = (1 << HDR_OPT_BIT_ENDIAN)
HDR_OPT_LEGACY = (1 << HDR_OPT_BIT_LEGACY)
HDR_OPT_RESZ_MASK = 0xfffc
# Records
RH_FORMAT = "II"
REC_TYPE_end = 0x00000000
REC_TYPE_libxc_context = 0x00000001
REC_TYPE_emulator_xenstore_data = 0x00000002
REC_TYPE_emulator_context = 0x00000003
REC_TYPE_checkpoint_end = 0x00000004
REC_TYPE_checkpoint_state = 0x00000005
rec_type_to_str = {
REC_TYPE_end : "End",
REC_TYPE_libxc_context : "Libxc context",
REC_TYPE_emulator_xenstore_data : "Emulator xenstore data",
REC_TYPE_emulator_context : "Emulator context",
REC_TYPE_checkpoint_end : "Checkpoint end",
REC_TYPE_checkpoint_state : "Checkpoint state",
}
# emulator_* header
EMULATOR_HEADER_FORMAT = "II"
EMULATOR_ID_unknown = 0x00000000
EMULATOR_ID_qemu_trad = 0x00000001
EMULATOR_ID_qemu_upstream = 0x00000002
emulator_id_to_str = {
EMULATOR_ID_unknown : "Unknown",
EMULATOR_ID_qemu_trad : "Qemu Traditional",
EMULATOR_ID_qemu_upstream : "Qemu Upstream",
}
#
# libxl format
#
LIBXL_QEMU_SIGNATURE = "DeviceModelRecord0002"
LIBXL_QEMU_RECORD_HDR = "=%dsI" % (len(LIBXL_QEMU_SIGNATURE), )
class VerifyLibxl(VerifyBase):
""" Verify a Libxl v2 stream """
def __init__(self, info, read):
VerifyBase.__init__(self, info, read)
def verify(self):
""" Verity a libxl stream """
self.verify_hdr()
while self.verify_record() != REC_TYPE_end:
pass
def verify_hdr(self):
""" Verify a Header """
ident, version, options = self.unpack_exact(HDR_FORMAT)
if ident != HDR_IDENT:
raise StreamError("Bad image id: Expected 0x%x, got 0x%x" %
(HDR_IDENT, ident))
if version != HDR_VERSION:
raise StreamError("Unknown image version: Expected %d, got %d" %
(HDR_VERSION, version))
if options & HDR_OPT_RESZ_MASK:
raise StreamError("Reserved bits set in image options field: 0x%x" %
(options & HDR_OPT_RESZ_MASK))
if ( (sys.byteorder == "little") and
((options & HDR_OPT_BIT_ENDIAN) != HDR_OPT_LE) ):
raise StreamError(
"Stream is not native endianess - unable to validate")
endian = ["little", "big"][options & HDR_OPT_LE]
if options & HDR_OPT_LEGACY:
self.info("Libxl Header: %s endian, legacy converted" % (endian, ))
else:
self.info("Libxl Header: %s endian" % (endian, ))
def verify_record(self):
""" Verify an individual record """
rtype, length = self.unpack_exact(RH_FORMAT)
if rtype not in rec_type_to_str:
raise StreamError("Unrecognised record type %x" % (rtype, ))
self.info("Libxl Record: %s, length %d" %
(rec_type_to_str[rtype], length))
contentsz = (length + 7) & ~7
content = self.rdexact(contentsz)
padding = content[length:]
if padding != b"\x00" * len(padding):
raise StreamError("Padding containing non0 bytes found")
if rtype not in record_verifiers:
raise RuntimeError(
"No verification function for libxl record '%s'" %
rec_type_to_str[rtype])
else:
record_verifiers[rtype](self, content[:length])
return rtype
def verify_record_end(self, content):
""" End record """
if len(content) != 0:
raise RecordError("End record with non-zero length")
def verify_record_libxc_context(self, content):
""" Libxc context record """
if len(content) != 0:
raise RecordError("Libxc context record with non-zero length")
# Verify the libxc stream, as we can't seek forwards through it
VerifyLibxc(self.info, self.read).verify()
def verify_record_emulator_xenstore_data(self, content):
""" Emulator Xenstore Data record """
minsz = calcsize(EMULATOR_HEADER_FORMAT)
if len(content) < minsz:
raise RecordError("Length must be at least %d bytes, got %d" %
(minsz, len(content)))
emu_id, emu_idx = unpack(EMULATOR_HEADER_FORMAT, content[:minsz])
if emu_id not in emulator_id_to_str:
raise RecordError("Unrecognised emulator id 0x%x" % (emu_id, ))
self.info("Emulator Xenstore Data (%s, idx %d)" %
(emulator_id_to_str[emu_id], emu_idx))
# Chop off the emulator header
content = content[minsz:]
if len(content):
if content[-1] != '\x00':
raise RecordError("Data not NUL terminated")
# Split without the final NUL, to get an even number of parts
parts = content[:-1].split("\x00")
if (len(parts) % 2) != 0:
raise RecordError("Expected an even number of strings, got %d" %
(len(parts), ))
for key, val in zip(parts[0::2], parts[1::2]):
self.info(" '%s' = '%s'" % (key, val))
def verify_record_emulator_context(self, content):
""" Emulator Context record """
minsz = calcsize(EMULATOR_HEADER_FORMAT)
if len(content) < minsz:
raise RecordError("Length must be at least %d bytes, got %d" %
(minsz, len(content)))
emu_id, emu_idx = unpack(EMULATOR_HEADER_FORMAT, content[:minsz])
if emu_id not in emulator_id_to_str:
raise RecordError("Unrecognised emulator id 0x%x" % (emu_id, ))
self.info(" Index %d, type %s" % (emu_idx, emulator_id_to_str[emu_id]))
def verify_record_checkpoint_end(self, content):
""" Checkpoint end record """
if len(content) != 0:
raise RecordError("Checkpoint end record with non-zero length")
def verify_record_checkpoint_state(self, content):
""" Checkpoint state """
if len(content) == 0:
raise RecordError("Checkpoint state record with zero length")
record_verifiers = {
REC_TYPE_end:
VerifyLibxl.verify_record_end,
REC_TYPE_libxc_context:
VerifyLibxl.verify_record_libxc_context,
REC_TYPE_emulator_xenstore_data:
VerifyLibxl.verify_record_emulator_xenstore_data,
REC_TYPE_emulator_context:
VerifyLibxl.verify_record_emulator_context,
REC_TYPE_checkpoint_end:
VerifyLibxl.verify_record_checkpoint_end,
REC_TYPE_checkpoint_state:
VerifyLibxl.verify_record_checkpoint_state,
}
|