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         errors = set()
     60 
     61         # Max procs, max threads, and file max are dependent upon total memory.
     62         # The kernel uses a formula similar to:
     63         #   MemTotal-kb / 128 = max procs
     64         #   MemTotal-kb / 64 = max threads
     65         #   MemTotal-kb / 10 = file_max
     66         # But note that MemTotal changes at the end of initialization.
     67         # The values used below for these settings should give sufficient head
     68         # room for usage and kernel allocation.
     69 
     70         ref_min = {'file_max': 50000,
     71                    'kptr_restrict': 1,
     72                    'max_open': 1024,
     73                    'max_procs': 3000,
     74                    'max_threads': 7000,
     75                    'ngroups_max': 65536,
     76                    'nr_open': 1048576,
     77                    'pid_max': 32768,
     78                    'mmap_min_addr': 65536,
     79                   }
     80 
     81         ref_equal = {'leases': 1,
     82                      'panic': -1,
     83                      'protected_hardlinks': 1,
     84                      'protected_symlinks': 1,
     85                      'ptrace_scope': 1,
     86                      'randomize_va_space': 2,
     87                      'sched_rt_period_us': 1000000,
     88                      'sched_rt_runtime_us': 800000,
     89                      'sysrq': 1,
     90                      'suid-dump': 2,
     91                      'tcp_syncookies': 1,
     92                     }
     93 
     94         refpath = {'file_max': '/proc/sys/fs/file-max',
     95                    'leases': '/proc/sys/fs/leases-enable',
     96                    'max_open': '/proc/self/limits',
     97                    'max_procs': '/proc/self/limits',
     98                    'max_threads': '/proc/sys/kernel/threads-max',
     99                    'mmap_min_addr': '/proc/sys/vm/mmap_min_addr',
    100                    'kptr_restrict': '/proc/sys/kernel/kptr_restrict',
    101                    'ngroups_max': '/proc/sys/kernel/ngroups_max',
    102                    'nr_open': '/proc/sys/fs/nr_open',
    103                    'panic': '/proc/sys/kernel/panic',
    104                    'pid_max': '/proc/sys/kernel/pid_max',
    105                    'protected_hardlinks': '/proc/sys/fs/protected_hardlinks',
    106                    'protected_symlinks': '/proc/sys/fs/protected_symlinks',
    107                    'ptrace_scope': '/proc/sys/kernel/yama/ptrace_scope',
    108                    'randomize_va_space': '/proc/sys/kernel/randomize_va_space',
    109                    'sched_rt_period_us': '/proc/sys/kernel/sched_rt_period_us',
    110                    'sched_rt_runtime_us': '/proc/sys/kernel/sched_rt_runtime_us',
    111                    'suid-dump': '/proc/sys/fs/suid_dumpable',
    112                    'sysrq': '/proc/sys/kernel/sysrq',
    113                    'tcp_syncookies': '/proc/sys/net/ipv4/tcp_syncookies',
    114                   }
    115 
    116         # Adjust arch-specific values.
    117         if utils.get_arch().startswith('arm'):
    118             ref_min['mmap_min_addr'] = 32768
    119 
    120         if utils.get_arch().startswith('aarch64'):
    121             ref_min['mmap_min_addr'] = 32768
    122 
    123         # ARM-compatible limit on x86 if ARC++ is present (b/30146997)
    124         if utils.is_arc_available():
    125             ref_min['mmap_min_addr'] = 32768
    126 
    127         # Adjust version-specific details.
    128         kernel_ver = os.uname()[2]
    129         if utils.compare_versions(kernel_ver, "3.6") < 0:
    130             # Prior to kernel version 3.6, Yama handled link restrictions.
    131             refpath['protected_hardlinks'] = \
    132                 '/proc/sys/kernel/yama/protected_nonaccess_hardlinks'
    133             refpath['protected_symlinks'] = \
    134                 '/proc/sys/kernel/yama/protected_sticky_symlinks'
    135 
    136         # Create osvalue dictionary with the same keys as refpath.
    137         osvalue = {}
    138         for key in refpath:
    139             osvalue[key] = None
    140 
    141         for key in ref_min:
    142             osvalue[key] = self.get_limit(key, refpath[key])
    143             if osvalue[key] < ref_min[key]:
    144                 logging.warning('%s is %d', refpath[key], osvalue[key])
    145                 logging.warning('%s should be at least %d', refpath[key],
    146                              ref_min[key])
    147                 errors.add(key)
    148             else:
    149                 logging.info('%s is %d >= %d', refpath[key], osvalue[key],
    150                                                ref_min[key])
    151 
    152         for key in ref_equal:
    153             osvalue[key] = self.get_limit(key, refpath[key])
    154             if osvalue[key] != ref_equal[key]:
    155                 logging.warning('%s is set to %d', refpath[key], osvalue[key])
    156                 logging.warning('Expected %d', ref_equal[key])
    157                 errors.add(key)
    158             else:
    159                 logging.info('%s is %d', refpath[key], osvalue[key])
    160 
    161         # Look for anything from refpath that wasn't checked yet:
    162         for key in osvalue:
    163             if osvalue[key] == None:
    164                 logging.warning('%s was never checked', key)
    165                 errors.add(key)
    166 
    167         # If self.error is not zero, there were errors.
    168         if len(errors) > 0:
    169             raise error.TestFail('Found incorrect values: %s' %
    170                                  ', '.join(errors))
    171