Home | History | Annotate | Download | only in security_Minijail0
      1 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import glob
      6 import logging
      7 import os
      8 import re
      9 import shutil
     10 import tempfile
     11 
     12 from autotest_lib.client.bin import test, utils
     13 from autotest_lib.client.common_lib import error
     14 
     15 class security_Minijail0(test.test):
     16     version = 1
     17 
     18 
     19     def is_64bit(self):
     20         return os.path.isdir('/lib64')
     21 
     22 
     23     def get_test_option(self, handle, name):
     24         setup = ''
     25         for l in handle.readlines():
     26             m = re.match('^# %s: (.*)' % name, l.strip())
     27             if m:
     28                 setup = m.group(1)
     29         return setup
     30 
     31 
     32     def run_test(self, path, static):
     33         # Tests are shell scripts with a magic comment line of the form '# args:
     34         # <stuff>' in them. The <stuff> is substituted in here as minijail0
     35         # arguments. They can also optionally contain a magic comment of the
     36         # form '# setup: <stuff>', in which case <stuff> is executed as a shell
     37         # command before running the test.
     38         # Another optional magic comment of the form '# expected_ugid <uid>
     39         # <gid>' is used when entering a new user namespace, where <uid> and
     40         # <gid> are the expected uid and gid 'outside' the user namespace. If
     41         # expected_ugid is set, a temporary directory is created, and a
     42         # temporary file is passed to tests as first argument. Tests should
     43         # 'touch' that file and its uid/gid will be checked outside the user
     44         # namespace.
     45         #
     46         # If '%T' is present in either of the above magic comments, a temporary
     47         # directory is created, and its name is substituted for '%T' in both of
     48         # them.
     49         # If '%S' is present in either of the above magic comments, it is
     50         # replaced with src folder of these tests.
     51         args = self.get_test_option(file(path), 'args')
     52         setup = self.get_test_option(file(path), 'setup')
     53         args64 = self.get_test_option(file(path), 'args64')
     54         args32 = self.get_test_option(file(path), 'args32')
     55         expugid = self.get_test_option(file(path), 'expected_ugid').split(" ")
     56 
     57         td = None
     58         if setup:
     59             if '%T' in setup:
     60                 td = tempfile.mkdtemp()
     61                 setup = setup.replace('%T', td)
     62             if '%S' in setup:
     63                 setup = setup.replace('%S', self.srcdir)
     64             utils.system(setup)
     65 
     66         if self.is_64bit() and args64:
     67             args = args + ' ' + args64
     68 
     69         if (not self.is_64bit()) and args32:
     70             args = args + ' ' + args32
     71 
     72         if '%T' in args:
     73             td = td or tempfile.mkdtemp()
     74             args = args.replace('%T', td)
     75         if '%S' in args:
     76             args = args.replace('%S', self.srcdir)
     77 
     78         userns_td = None
     79         userns_file = ''
     80         if len(expugid) == 2:
     81             expuid, expgid = expugid
     82             userns_td = tempfile.mkdtemp()
     83             os.chmod(userns_td, 0777)
     84             userns_file = userns_td + '/userns'
     85 
     86         if static:
     87             ret = utils.system('/sbin/minijail0 %s %s/staticbashexec %s %s'
     88                                 % (args, self.srcdir, path, userns_file),
     89                                 ignore_status=True)
     90         else:
     91             ret = utils.system('/sbin/minijail0 %s /bin/bash %s %s'
     92                                 % (args, path, userns_file),
     93                                 ignore_status=True)
     94         if ret == 0 and len(expugid) == 2:
     95             stat = os.stat(userns_file)
     96             if str(stat.st_uid) != expuid or str(stat.st_gid) != expgid:
     97                 ret = 1
     98 
     99         if td:
    100             # The test better not have polluted our mount namespace :).
    101             shutil.rmtree(td)
    102         if userns_td:
    103             shutil.rmtree(userns_td)
    104         return ret
    105 
    106 
    107     def setup(self):
    108         os.chdir(self.srcdir)
    109         utils.make()
    110 
    111 
    112     def run_once(self):
    113         failed = []
    114         ran = 0
    115         for p in glob.glob('%s/test-*' % self.srcdir):
    116             name = os.path.basename(p)
    117             logging.info('Running: %s', name)
    118             if self.run_test(p, static=False):
    119                 failed.append(name)
    120             ran += 1
    121             if name != 'test-caps':
    122                 if self.run_test(p, static=True):
    123                     failed.append(name + ' static')
    124                 ran += 1
    125         if ran == 0:
    126             failed.append("No tests found to run from %s!" % (self.srcdir))
    127         if failed:
    128             logging.error('Failed: %s', failed)
    129             raise error.TestFail('Failed: %s' % failed)
    130