@@ -306,20 +306,39 @@ def inject_data_into_fs(fs, key, net, metadata, admin_password, execute):
306
306
_inject_admin_password_into_fs (admin_password , fs , execute = execute )
307
307
308
308
309
- def _inject_file_into_fs (fs , path , contents ):
310
- absolute_path = os .path .join (fs , path .lstrip ('/' ))
309
+ def _join_and_check_path_within_fs (fs , * args ):
310
+ '''os.path.join() with safety check for injected file paths.
311
+
312
+ Join the supplied path components and make sure that the
313
+ resulting path we are injecting into is within the
314
+ mounted guest fs. Trying to be clever and specifying a
315
+ path with '..' in it will hit this safeguard.
316
+ '''
317
+ absolute_path = os .path .realpath (os .path .join (fs , * args ))
318
+ if not absolute_path .startswith (os .path .realpath (fs ) + '/' ):
319
+ raise exception .Invalid (_ ('injected file path not valid' ))
320
+ return absolute_path
321
+
322
+
323
+ def _inject_file_into_fs (fs , path , contents , append = False ):
324
+ absolute_path = _join_and_check_path_within_fs (fs , path .lstrip ('/' ))
325
+
311
326
parent_dir = os .path .dirname (absolute_path )
312
327
utils .execute ('mkdir' , '-p' , parent_dir , run_as_root = True )
313
- utils .execute ('tee' , absolute_path , process_input = contents ,
314
- run_as_root = True )
328
+
329
+ args = []
330
+ if append :
331
+ args .append ('-a' )
332
+ args .append (absolute_path )
333
+
334
+ kwargs = dict (process_input = contents , run_as_root = True )
335
+
336
+ utils .execute ('tee' , * args , ** kwargs )
315
337
316
338
317
339
def _inject_metadata_into_fs (metadata , fs , execute = None ):
318
- metadata_path = os .path .join (fs , "meta.js" )
319
340
metadata = dict ([(m .key , m .value ) for m in metadata ])
320
-
321
- utils .execute ('tee' , metadata_path ,
322
- process_input = json .dumps (metadata ), run_as_root = True )
341
+ _inject_file_into_fs (fs , 'meta.js' , json .dumps (metadata ))
323
342
324
343
325
344
def _inject_key_into_fs (key , fs , execute = None ):
@@ -328,33 +347,36 @@ def _inject_key_into_fs(key, fs, execute=None):
328
347
key is an ssh key string.
329
348
fs is the path to the base of the filesystem into which to inject the key.
330
349
"""
331
- sshdir = os . path . join (fs , 'root' , '.ssh' )
350
+ sshdir = _join_and_check_path_within_fs (fs , 'root' , '.ssh' )
332
351
utils .execute ('mkdir' , '-p' , sshdir , run_as_root = True )
333
352
utils .execute ('chown' , 'root' , sshdir , run_as_root = True )
334
353
utils .execute ('chmod' , '700' , sshdir , run_as_root = True )
335
- keyfile = os .path .join (sshdir , 'authorized_keys' )
336
- key_data = [
354
+
355
+ keyfile = os .path .join ('root' , '.ssh' , 'authorized_keys' )
356
+
357
+ key_data = '' .join ([
337
358
'\n ' ,
338
359
'# The following ssh key was injected by Nova' ,
339
360
'\n ' ,
340
361
key .strip (),
341
362
'\n ' ,
342
- ]
343
- utils . execute ( 'tee' , '-a' , keyfile ,
344
- process_input = '' . join ( key_data ), run_as_root = True )
363
+ ])
364
+
365
+ _inject_file_into_fs ( fs , keyfile , key_data , append = True )
345
366
346
367
347
368
def _inject_net_into_fs (net , fs , execute = None ):
348
369
"""Inject /etc/network/interfaces into the filesystem rooted at fs.
349
370
350
371
net is the contents of /etc/network/interfaces.
351
372
"""
352
- netdir = os . path . join ( os . path . join ( fs , 'etc' ) , 'network' )
373
+ netdir = _join_and_check_path_within_fs ( fs , 'etc' , 'network' )
353
374
utils .execute ('mkdir' , '-p' , netdir , run_as_root = True )
354
375
utils .execute ('chown' , 'root:root' , netdir , run_as_root = True )
355
376
utils .execute ('chmod' , 755 , netdir , run_as_root = True )
356
- netfile = os .path .join (netdir , 'interfaces' )
357
- utils .execute ('tee' , netfile , process_input = net , run_as_root = True )
377
+
378
+ netfile = os .path .join ('etc' , 'network' , 'interfaces' )
379
+ _inject_file_into_fs (fs , netfile , net )
358
380
359
381
360
382
def _inject_admin_password_into_fs (admin_passwd , fs , execute = None ):
@@ -379,16 +401,15 @@ def _inject_admin_password_into_fs(admin_passwd, fs, execute=None):
379
401
fd , tmp_shadow = tempfile .mkstemp ()
380
402
os .close (fd )
381
403
382
- utils .execute ('cp' , os .path .join (fs , 'etc' , 'passwd' ), tmp_passwd ,
383
- run_as_root = True )
384
- utils .execute ('cp' , os .path .join (fs , 'etc' , 'shadow' ), tmp_shadow ,
385
- run_as_root = True )
404
+ passwd_path = _join_and_check_path_within_fs (fs , 'etc' , 'passwd' )
405
+ shadow_path = _join_and_check_path_within_fs (fs , 'etc' , 'shadow' )
406
+
407
+ utils .execute ('cp' , passwd_path , tmp_passwd , run_as_root = True )
408
+ utils .execute ('cp' , shadow_path , tmp_shadow , run_as_root = True )
386
409
_set_passwd (admin_user , admin_passwd , tmp_passwd , tmp_shadow )
387
- utils .execute ('cp' , tmp_passwd , os .path .join (fs , 'etc' , 'passwd' ),
388
- run_as_root = True )
410
+ utils .execute ('cp' , tmp_passwd , passwd_path , run_as_root = True )
389
411
os .unlink (tmp_passwd )
390
- utils .execute ('cp' , tmp_shadow , os .path .join (fs , 'etc' , 'shadow' ),
391
- run_as_root = True )
412
+ utils .execute ('cp' , tmp_shadow , shadow_path , run_as_root = True )
392
413
os .unlink (tmp_shadow )
393
414
394
415
0 commit comments