25
25
from taskflow import task
26
26
27
27
from glance .async_ import utils
28
+ from glance .common import format_inspector
28
29
from glance .i18n import _ , _LI
29
30
30
31
LOG = logging .getLogger (__name__ )
@@ -87,8 +88,40 @@ def _execute(self, action, file_path, **kwargs):
87
88
'target' : target_format }
88
89
self .dest_path = dest_path
89
90
91
+ source_format = action .image_disk_format
92
+ inspector_cls = format_inspector .get_inspector (source_format )
93
+ if not inspector_cls :
94
+ # We cannot convert from disk_format types that qemu-img doesn't
95
+ # support (like iso, ploop, etc). The ones it supports overlaps
96
+ # with the ones we have inspectors for, so reject conversion for
97
+ # any format we don't have an inspector for.
98
+ raise RuntimeError (
99
+ 'Unable to convert from format %s' % source_format )
100
+
101
+ # Use our own cautious inspector module (if we have one for this
102
+ # format) to make sure a file is the format the submitter claimed
103
+ # it is and that it passes some basic safety checks _before_ we run
104
+ # qemu-img on it.
105
+ # See https://bugs.launchpad.net/nova/+bug/2059809 for details.
106
+ try :
107
+ inspector = inspector_cls .from_file (src_path )
108
+ if not inspector .safety_check ():
109
+ LOG .error ('Image failed %s safety check; aborting conversion' ,
110
+ source_format )
111
+ raise RuntimeError ('Image has disallowed configuration' )
112
+ except RuntimeError :
113
+ raise
114
+ except format_inspector .ImageFormatError as e :
115
+ LOG .error ('Image claimed to be %s format failed format '
116
+ 'inspection: %s' , source_format , e )
117
+ raise RuntimeError ('Image format detection failed' )
118
+ except Exception as e :
119
+ LOG .exception ('Unknown error inspecting image format: %s' , e )
120
+ raise RuntimeError ('Unable to inspect image' )
121
+
90
122
try :
91
123
stdout , stderr = putils .trycmd ("qemu-img" , "info" ,
124
+ "-f" , source_format ,
92
125
"--output=json" ,
93
126
src_path ,
94
127
prlimit = utils .QEMU_IMG_PROC_LIMITS ,
@@ -105,13 +138,10 @@ def _execute(self, action, file_path, **kwargs):
105
138
raise RuntimeError (stderr )
106
139
107
140
metadata = json .loads (stdout )
108
- try :
109
- source_format = metadata ['format' ]
110
- except KeyError :
111
- msg = ("Failed to do introspection as part of image "
112
- "conversion for %(iid)s: Source format not reported" )
113
- LOG .error (msg , {'iid' : self .image_id })
114
- raise RuntimeError (msg )
141
+ if metadata .get ('format' ) != source_format :
142
+ LOG .error ('Image claiming to be %s reported as %s by qemu-img' ,
143
+ source_format , metadata .get ('format' , 'unknown' ))
144
+ raise RuntimeError ('Image metadata disagrees about format' )
115
145
116
146
virtual_size = metadata .get ('virtual-size' , 0 )
117
147
action .set_image_attribute (virtual_size = virtual_size )
@@ -121,6 +151,14 @@ def _execute(self, action, file_path, **kwargs):
121
151
raise RuntimeError (
122
152
'QCOW images with backing files are not allowed' )
123
153
154
+ try :
155
+ data_file = metadata ['format-specific' ]['data' ]['data-file' ]
156
+ except KeyError :
157
+ data_file = None
158
+ if data_file is not None :
159
+ raise RuntimeError (
160
+ 'QCOW images with data-file set are not allowed' )
161
+
124
162
if metadata .get ('format' ) == 'vmdk' :
125
163
create_type = metadata .get (
126
164
'format-specific' , {}).get (
0 commit comments