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@chromium.org (Kelly Lucas)' 8 9import logging 10import os 11 12from autotest_lib.client.bin import utils, test 13from autotest_lib.client.common_lib import error 14 15 16class 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 # Adjust version-specific details. 124 kernel_ver = os.uname()[2] 125 if utils.compare_versions(kernel_ver, "3.6") < 0: 126 # Prior to kernel version 3.6, Yama handled link restrictions. 127 refpath['protected_hardlinks'] = \ 128 '/proc/sys/kernel/yama/protected_nonaccess_hardlinks' 129 refpath['protected_symlinks'] = \ 130 '/proc/sys/kernel/yama/protected_sticky_symlinks' 131 132 # Create osvalue dictionary with the same keys as refpath. 133 osvalue = {} 134 for key in refpath: 135 osvalue[key] = None 136 137 for key in ref_min: 138 osvalue[key] = self.get_limit(key, refpath[key]) 139 if osvalue[key] < ref_min[key]: 140 logging.warning('%s is %d', refpath[key], osvalue[key]) 141 logging.warning('%s should be at least %d', refpath[key], 142 ref_min[key]) 143 errors.add(key) 144 else: 145 logging.info('%s is %d >= %d', refpath[key], osvalue[key], 146 ref_min[key]) 147 148 for key in ref_equal: 149 osvalue[key] = self.get_limit(key, refpath[key]) 150 if osvalue[key] != ref_equal[key]: 151 logging.warning('%s is set to %d', refpath[key], osvalue[key]) 152 logging.warning('Expected %d', ref_equal[key]) 153 errors.add(key) 154 else: 155 logging.info('%s is %d', refpath[key], osvalue[key]) 156 157 # Look for anything from refpath that wasn't checked yet: 158 for key in osvalue: 159 if osvalue[key] == None: 160 logging.warning('%s was never checked', key) 161 errors.add(key) 162 163 # If self.error is not zero, there were errors. 164 if len(errors) > 0: 165 raise error.TestFail('Found incorrect values: %s' % 166 ', '.join(errors)) 167