Merge pull request #3198 from mpg/fix-overflow-benchmark-2.16

[backport 2.16] Fix arithmetic overflow in benchmark
diff --git a/.pylintrc b/.pylintrc
index 168e0b7..08c114a 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -40,7 +40,27 @@
 max-module-lines=2000
 
 [MESSAGES CONTROL]
-disable=
+# * locally-disabled, locally-enabled: If we disable or enable a message
+#   locally, it's by design. There's no need to clutter the Pylint output
+#   with this information.
+# * logging-format-interpolation: Pylint warns about things like
+#   ``log.info('...'.format(...))``. It insists on ``log.info('...', ...)``.
+#   This is of minor utility (mainly a performance gain when there are
+#   many messages that use formatting and are below the log level).
+#   Some versions of Pylint (including 1.8, which is the version on
+#   Ubuntu 18.04) only recognize old-style format strings using '%',
+#   and complain about something like ``log.info('{}', foo)`` with
+#   logging-too-many-args (Pylint supports new-style formatting if
+#   declared globally with logging_format_style under [LOGGING] but
+#   this requires Pylint >=2.2).
+# * no-else-return: Allow the perfectly reasonable idiom
+#    if condition1:
+#        return value1
+#    else:
+#        return value2
+# * unnecessary-pass: If we take the trouble of adding a line with "pass",
+#   it's because we think the code is clearer that way.
+disable=locally-disabled,locally-enabled,logging-format-interpolation,no-else-return,unnecessary-pass
 
 [REPORTS]
 # Don't diplay statistics. Just the facts.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 9c2e365..176e885 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -514,6 +514,12 @@
         return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
 
+    /* Do not accept max_pathlen equal to INT_MAX to avoid a signed integer
+     * overflow, which is an undefined behavior. */
+    if( *max_pathlen == INT_MAX )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_INVALID_LENGTH );
+
     (*max_pathlen)++;
 
     return( 0 );
diff --git a/scripts/abi_check.py b/scripts/abi_check.py
index e19f2c0..c2aca50 100755
--- a/scripts/abi_check.py
+++ b/scripts/abi_check.py
@@ -29,7 +29,7 @@
 import xml.etree.ElementTree as ET
 
 
-class AbiChecker(object):
+class AbiChecker:
     """API and ABI checker."""
 
     def __init__(self, old_version, new_version, configuration):
diff --git a/tests/data_files/server1_pathlen_int_max-1.crt b/tests/data_files/server1_pathlen_int_max-1.crt
new file mode 100644
index 0000000..4944844
--- /dev/null
+++ b/tests/data_files/server1_pathlen_int_max-1.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSDCCAjCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/
+uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD
+d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf
+CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr
+lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
+bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
+o1YwVDASBgNVHRMECzAJAQH/AgR////+MB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIs
+Pai9Q1kCpjAfBgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG
+9w0BAQUFAAOCAQEAfuvq7FomQTSJmGInVwQjQddgoXpnmCZ97TpVq7jHLCFADowQ
+jeiAsxmD8mwAQqw/By0U2PSmQcS7Vrn7Le0nFKNRYYrtpx5rsTFJzS/tQsgCe0Pf
+zhiBgD1Dhw6PWAPmy+JlvhJF7REmFsM8KHQd0xSvJzB1gLN9FVlnd87C73bdDJZQ
+Zdn977+Sn5anAFGHDWeKo8GYaYGnPBQqkX0Q2EKWR7yrwcKMogOevxELogB0jRj3
+L+nBpz7mO2J6XQ85ip+tLWAGCEHo0omAIQorAoCSqtLiaz47HxOdNK0hnM7V5k8P
+05AVhxDa3WqZ9FmMaDc8j8XqmOgKYVMC4/WS0g==
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server1_pathlen_int_max.crt b/tests/data_files/server1_pathlen_int_max.crt
new file mode 100644
index 0000000..517e0d6
--- /dev/null
+++ b/tests/data_files/server1_pathlen_int_max.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSDCCAjCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/
+uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD
+d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf
+CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr
+lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
+bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
+o1YwVDASBgNVHRMECzAJAQH/AgR/////MB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIs
+Pai9Q1kCpjAfBgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG
+9w0BAQUFAAOCAQEAe5jPPMyWrKYGljJH2uh1gEh7KoYhmGIUfYu5A8Z2ou04yFZh
+LDyWJnkE/qpNaIw3kPuoyGBTtADYzttPvxretUmaMyteOQe8DK/mmr8vl+gb54ZP
+2jUE+R27Jp5GSGfl20LNVTBkKJloSyDaVzPI3ozje2lAsXsil8NTKbVJtfjZ9un+
+mGrpywSV7RpZC2PznGFdqQehwwnOscz0cVeMQqGcMRH3D5Bk2SjVexCaPu47QSyE
+fNm6cATiNHjw/2dg5Aue7e4K+R6le+xY3Qy85Fq/lKDeMmbrJRrNyJ9lblCeihUd
+qhkAEPelpaq5ZRM6cYJQoo0Ak64j4svjOZeF0g==
+-----END CERTIFICATE-----
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index dd8f510..4e49515 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1409,15 +1409,6 @@
     unset gdb_disable_aslr
 }
 
-support_check_python_files () {
-    # Find the installed version of Pylint. Installed as a distro package this can
-    # be pylint3 and as a PEP egg, pylint.
-    if type pylint >/dev/null 2>/dev/null || type pylint3 >/dev/null 2>/dev/null; then
-        true;
-    else
-        false;
-    fi
-}
 component_check_python_files () {
     msg "Lint: Python scripts"
     record_status tests/scripts/check-python-files.sh
diff --git a/tests/scripts/check-files.py b/tests/scripts/check-files.py
index 255bed8..f8d9261 100755
--- a/tests/scripts/check-files.py
+++ b/tests/scripts/check-files.py
@@ -17,7 +17,7 @@
 import sys
 
 
-class FileIssueTracker(object):
+class FileIssueTracker:
     """Base class for file-wide issue tracking.
 
     To implement a checker that processes a file as a whole, inherit from
@@ -37,20 +37,31 @@
         self.files_with_issues = {}
 
     def should_check_file(self, filepath):
+        """Whether the given file name should be checked.
+
+        Files whose name ends with a string listed in ``self.files_exemptions``
+        will not be checked.
+        """
         for files_exemption in self.files_exemptions:
             if filepath.endswith(files_exemption):
                 return False
         return True
 
     def check_file_for_issue(self, filepath):
+        """Check the specified file for the issue that this class is for.
+
+        Subclasses must implement this method.
+        """
         raise NotImplementedError
 
     def record_issue(self, filepath, line_number):
+        """Record that an issue was found at the specified location."""
         if filepath not in self.files_with_issues.keys():
             self.files_with_issues[filepath] = []
         self.files_with_issues[filepath].append(line_number)
 
     def output_file_issues(self, logger):
+        """Log all the locations where the issue was found."""
         if self.files_with_issues.values():
             logger.info(self.heading)
             for filename, lines in sorted(self.files_with_issues.items()):
@@ -70,6 +81,10 @@
     """
 
     def issue_with_line(self, line, filepath):
+        """Check the specified line for the issue that this class is for.
+
+        Subclasses must implement this method.
+        """
         raise NotImplementedError
 
     def check_file_line(self, filepath, line, line_number):
@@ -77,6 +92,10 @@
             self.record_issue(filepath, line_number)
 
     def check_file_for_issue(self, filepath):
+        """Check the lines of the specified file.
+
+        Subclasses must implement the ``issue_with_line`` method.
+        """
         with open(filepath, "rb") as f:
             for i, line in enumerate(iter(f.readline, b"")):
                 self.check_file_line(filepath, line, i + 1)
@@ -169,7 +188,7 @@
         return False
 
 
-class IntegrityChecker(object):
+class IntegrityChecker:
     """Sanity-check files under the current directory."""
 
     def __init__(self, log_file):
diff --git a/tests/scripts/check-python-files.sh b/tests/scripts/check-python-files.sh
index 6b864d2..cd18518 100755
--- a/tests/scripts/check-python-files.sh
+++ b/tests/scripts/check-python-files.sh
@@ -9,15 +9,10 @@
 # Run 'pylint' on Python files for programming errors and helps enforcing
 # PEP8 coding standards.
 
-# Find the installed version of Pylint. Installed as a distro package this can
-# be pylint3 and as a PEP egg, pylint. We prefer pylint over pylint3
-if type pylint >/dev/null 2>/dev/null; then
-    PYLINT=pylint
-elif type pylint3 >/dev/null 2>/dev/null; then
-    PYLINT=pylint3
+if type python3 >/dev/null 2>/dev/null; then
+    PYTHON=python3
 else
-    echo 'Pylint was not found.'
-    exit 1
+    PYTHON=python
 fi
 
-$PYLINT -j 2 scripts/*.py tests/scripts/*.py
+$PYTHON -m pylint -j 2 scripts/*.py tests/scripts/*.py
diff --git a/tests/scripts/generate_test_code.py b/tests/scripts/generate_test_code.py
index 1fff099..21f816e 100755
--- a/tests/scripts/generate_test_code.py
+++ b/tests/scripts/generate_test_code.py
@@ -208,7 +208,7 @@
     pass
 
 
-class FileWrapper(io.FileIO, object):
+class FileWrapper(io.FileIO):
     """
     This class extends built-in io.FileIO class with attribute line_no,
     that indicates line number for the line that is read.
@@ -402,8 +402,7 @@
     :param inp_str: Input string with macros delimited by ':'.
     :return: list of dependencies
     """
-    dependencies = [dep for dep in map(validate_dependency,
-                                       inp_str.split(':'))]
+    dependencies = list(map(validate_dependency, inp_str.split(':')))
     return dependencies
 
 
diff --git a/tests/scripts/mbedtls_test.py b/tests/scripts/mbedtls_test.py
index 8f24435..709bb1a 100755
--- a/tests/scripts/mbedtls_test.py
+++ b/tests/scripts/mbedtls_test.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+
 # Greentea host test script for Mbed TLS on-target test suite testing.
 #
 # Copyright (C) 2018, Arm Limited, All Rights Reserved
@@ -46,7 +48,7 @@
     pass
 
 
-class TestDataParser(object):
+class TestDataParser:
     """
     Parses test name, dependencies, test function name and test parameters
     from the data file.
@@ -260,7 +262,7 @@
             data_bytes += bytearray(dependencies)
         data_bytes += bytearray([function_id, len(parameters)])
         for typ, param in parameters:
-            if typ == 'int' or typ == 'exp':
+            if typ in ('int', 'exp'):
                 i = int(param, 0)
                 data_bytes += b'I' if typ == 'int' else b'E'
                 self.align_32bit(data_bytes)
diff --git a/tests/scripts/test_generate_test_code.py b/tests/scripts/test_generate_test_code.py
index 6d7113e..c8e8c5c 100755
--- a/tests/scripts/test_generate_test_code.py
+++ b/tests/scripts/test_generate_test_code.py
@@ -294,7 +294,7 @@
         self.assertEqual(code, expected)
 
 
-class StringIOWrapper(StringIO, object):
+class StringIOWrapper(StringIO):
     """
     file like class to mock file object in tests.
     """
@@ -1127,9 +1127,8 @@
 dhm_selftest:
 """
         stream = StringIOWrapper('test_suite_ut.function', data)
-        tests = [(name, test_function, dependencies, args)
-                 for name, test_function, dependencies, args in
-                 parse_test_data(stream)]
+        # List of (name, function_name, dependencies, args)
+        tests = list(parse_test_data(stream))
         test1, test2, test3, test4 = tests
         self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
         self.assertEqual(test1[1], 'dhm_do_dhm')
@@ -1170,9 +1169,8 @@
 
 """
         stream = StringIOWrapper('test_suite_ut.function', data)
-        tests = [(name, function_name, dependencies, args)
-                 for name, function_name, dependencies, args in
-                 parse_test_data(stream)]
+        # List of (name, function_name, dependencies, args)
+        tests = list(parse_test_data(stream))
         test1, test2 = tests
         self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
         self.assertEqual(test1[1], 'dhm_do_dhm')
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 91f8ac9..2c52d08 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1166,6 +1166,14 @@
 depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
 x509parse_crt:"30819f30819ca0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba314301230100603551d130101010406300402010102":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA
 
+X509 Certificate ASN1 (inv extBasicConstraint, pathlen is INT_MAX)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_SHA1_C
+x509parse_crt_file:"data_files/server1_pathlen_int_max.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_INVALID_LENGTH
+
+X509 Certificate ASN1 (pathlen is INT_MAX-1)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_SHA1_C
+x509parse_crt_file:"data_files/server1_pathlen_int_max-1.crt":0
+
 X509 Certificate ASN1 (TBSCertificate v3, ext BasicContraint tag, octet len mismatch)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
 x509parse_crt:"3081a230819fa0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba317301530130603551d130101010409300702010102010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH