Home | History | Annotate | Download | only in platform_OSLimits
      1 #!/usr/bin/python
      2 #
      3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 __author__ = 'kdlucas (at] chromium.org (Kelly Lucas)'
      8 
      9 import logging
     10 import os
     11 
     12 from autotest_lib.client.bin import utils, test
     13 from autotest_lib.client.common_lib import error
     14 
     15 
     16 class platform_OSLimits(test.test):
     17     """
     18     Verify os limitations are set to correct levels.
     19     """
     20     version = 1
     21 
     22     def get_limit(self, key, path):
     23         """
     24         Find and return values held in path.
     25 
     26         Args:
     27             key: dictionary key of os limit.
     28             path: pathname of file with current value.
     29         Returns:
     30             value found in path. If it's a number we'll convert to integer.
     31         """
     32 
     33         value = None
     34         # Most files have only one value, but if there are multiple values we
     35         # will handle it differently. Determine this from the key.
     36 
     37         multivals = ['max_open', 'max_procs']
     38         limits = {'max_open': 'Max open files',
     39                   'max_procs': 'Max processes',
     40                  }
     41 
     42         if key in multivals:
     43             output = utils.read_file(path)
     44             lines = output.splitlines()
     45             for line in lines:
     46                 if limits[key] in line:
     47                     fields = line.split(limits[key])
     48                     vals = fields[1].split()
     49                     value = (vals[0])
     50         else:
     51             value = (utils.read_one_line(path))
     52 
     53         if value == 'unlimited':
     54             return value
     55         else:
     56             return int(value)
     57 
     58     def run_once(self):
     59         """
     60         The actual test.
     61         """
     62         errors = set()
     63 
     64         # Max procs, max threads, and file max are dependent upon total memory.
     65         # The kernel uses a formula similar to:
     66         #   MemTotal-kb / 128 = max procs
     67         #   MemTotal-kb / 64 = max threads
     68         #   MemTotal-kb / 10 = file_max
     69         # But note that MemTotal changes at the end of initialization.
     70         # The values used below for these settings should give sufficient head
     71         # room for usage and kernel allocation.
     72 
     73         ref_min = {'file_max': 50000,
     74                    'kptr_restrict': 1,
     75                    'max_open': 1024,
     76                    'max_procs': 3000,
     77                    'max_threads': 7000,
     78                    'ngroups_max': 65536,
     79                    'nr_open': 1048576,
     80                    'pid_max': 32768,
     81                    'mmap_min_addr': 32768,
     82                   }
     83 
     84         ref_equal = {'leases': 1,
     85                      'panic': -1,
     86                      'protected_hardlinks': 1,
     87                      'protected_symlinks': 1,
     88                      'ptrace_scope': 1,
     89                      'randomize_va_space': 2,
     90                      'sched_rt_period_us': 1000000,
     91                      'sched_rt_runtime_us': 800000,
     92                      'sysrq': 1,
     93                      'suid-dump': 2,
     94                      'tcp_syncookies': 1,
     95                     }
     96 
     97         refpath = {'file_max': '/proc/sys/fs/file-max',
     98                    'leases': '/proc/sys/fs/leases-enable',
     99                    'max_open': '/proc/self/limits',
    100                    'max_procs': '/proc/self/limits',
    101                    'max_threads': '/proc/sys/kernel/threads-max',
    102                    'mmap_min_addr': '/proc/sys/vm/mmap_min_addr',
    103                    'kptr_restrict': '/proc/sys/kernel/kptr_restrict',
    104                    'ngroups_max': '/proc/sys/kernel/ngroups_max',
    105                    'nr_open': '/proc/sys/fs/nr_open',
    106                    'panic': '/proc/sys/kernel/panic',
    107                    'pid_max': '/proc/sys/kernel/pid_max',
    108                    'protected_hardlinks': '/proc/sys/fs/protected_hardlinks',
    109                    'protected_symlinks': '/proc/sys/fs/protected_symlinks',
    110                    'ptrace_scope': '/proc/sys/kernel/yama/ptrace_scope',
    111                    'randomize_va_space': '/proc/sys/kernel/randomize_va_space',
    112                    'sched_rt_period_us': '/proc/sys/kernel/sched_rt_period_us',
    113                    'sched_rt_runtime_us': '/proc/sys/kernel/sched_rt_runtime_us',
    114                    'suid-dump': '/proc/sys/fs/suid_dumpable',
    115                    'sysrq': '/proc/sys/kernel/sysrq',
    116                    'tcp_syncookies': '/proc/sys/net/ipv4/tcp_syncookies',
    117                   }
    118 
    119         # Adjust version-specific details.
    120         kernel_ver = os.uname()[2]
    121         if utils.compare_versions(kernel_ver, "3.6") < 0:
    122             # Prior to kernel version 3.6, Yama handled link restrictions.
    123             refpath['protected_hardlinks'] = \
    124                 '/proc/sys/kernel/yama/protected_nonaccess_hardlinks'
    125             refpath['protected_symlinks'] = \
    126                 '/proc/sys/kernel/yama/protected_sticky_symlinks'
    127 
    128         # Create osvalue dictionary with the same keys as refpath.
    129         osvalue = {}
    130         for key in refpath:
    131             osvalue[key] = None
    132 
    133         for key in ref_min:
    134             osvalue[key] = self.get_limit(key, refpath[key])
    135             if osvalue[key] < ref_min[key]:
    136                 logging.warning('%s is %d', refpath[key], osvalue[key])
    137                 logging.warning('%s should be at least %d', refpath[key],
    138                              ref_min[key])
    139                 errors.add(key)
    140             else:
    141                 logging.info('%s is %d >= %d', refpath[key], osvalue[key],
    142                                                ref_min[key])
    143 
    144         for key in ref_equal:
    145             osvalue[key] = self.get_limit(key, refpath[key])
    146             if osvalue[key] != ref_equal[key]:
    147                 logging.warning('%s is set to %d', refpath[key], osvalue[key])
    148                 logging.warning('Expected %d', ref_equal[key])
    149                 errors.add(key)
    150             else:
    151                 logging.info('%s is %d', refpath[key], osvalue[key])
    152 
    153         # Look for anything from refpath that wasn't checked yet:
    154         for key in osvalue:
    155             if osvalue[key] == None:
    156                 logging.warning('%s was never checked', key)
    157                 errors.add(key)
    158 
    159         # If self.error is not zero, there were errors.
    160         if len(errors) > 0:
    161             raise error.TestFail('Found incorrect values: %s' %
    162                                  ', '.join(errors))
    163