Skip to content

Commit 4ceb5c7

Browse files
authored
Merge pull request #547 from myteron/pyCode2GitHub_CWE-191
pyDoc2GitHub CWE-191
2 parents 99150f0 + 9a1f0d0 commit 4ceb5c7

File tree

8 files changed

+292
-1
lines changed

8 files changed

+292
-1
lines changed
Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,187 @@
11
# CWE-191, Integer Underflow (Wrap or Wraparound)
22

3-
PLACEHOLDER for # CWE-1335: Promote readability and compatibility by using mathematical written code with arithmetic operations instead of bit-wise operations link
3+
Ensure that integer overflow is properly handled in order to avoid unexpected behavior. Python data types can be divided into two categories:
4+
5+
- Built-in types such as `int`, `float`, or `complex` [[Python 2024]](https://docs.python.org/3.9/library/stdtypes.html). These types are provided by classes and are protected against overflows.
6+
7+
- Primitive types share issues known from `C` , or `C++` and appear in `Python` to:
8+
- interact with the operating system modules such as `time`.
9+
- to be memory efficiency using modules such as `numpy` or `ctype`.
10+
11+
Developers should follow the `C` guidelines when using or interacting wth `C` type variables.
12+
13+
## Non-Compliant Code Example
14+
15+
Using a `numpy.int64` can cause an unintentional flip of its sign when reaching the maximum number that can be stored as demonstrated in `noncompliant01.py`.
16+
17+
*[noncompliant01.py](noncompliant01.py):*
18+
19+
```python
20+
""" Non-compliant Code Example """
21+
22+
import numpy
23+
24+
a = numpy.int64(numpy.iinfo(numpy.int64).max)
25+
print(a + 1) # RuntimeWarning and continues
26+
print()
27+
b = numpy.int64(numpy.iinfo(numpy.int64).max + 1) # OverflowError and stops
28+
print(b) # we will never reach this
29+
```
30+
31+
Adding `+1` to `9223372036854775807` results in a negative number `-9223372036854775808` and throws a `RuntimeWarning` but continues.
32+
33+
An attempt to create `int` from a too big number causes an `OverflowError` and stops.
34+
35+
> [!NOTE]
36+
> It has been observed that different results may occur depending on the version of `numpy`. For reference, we are using `numpy 1.23.1` and Python `3.9.12.`
37+
38+
## Compliant Solution
39+
40+
The `compliant01.py` code detects the integer overflow by catching the appropriate Exception.
41+
42+
*[compliant01.py](compliant01.py):*
43+
44+
```python
45+
""" Compliant Code Example """
46+
47+
import warnings
48+
import numpy
49+
50+
warnings.filterwarnings("error")
51+
a = numpy.int64(numpy.iinfo(numpy.int64).max)
52+
with warnings.catch_warnings():
53+
try:
54+
print(a + 1)
55+
except Warning as _:
56+
print("Failed to increment " + str(a) + " due to overflow error")
57+
# RuntimeWarning and continues
58+
59+
try:
60+
b = numpy.int64(numpy.iinfo(numpy.int64).max + 1) # OverflowError and stops
61+
except OverflowError as e:
62+
print("Failed to assign value to B due to overflow error")
63+
```
64+
65+
## Non-Compliant Code Example
66+
67+
The `noncompliant02.py` example tries to use `time.localtime()` to get `x` hours in the future but causes integer overflow as the given Python `int` is too large to convert to `C long`. This is possible because `time` implements C representations of integers with all the security vulnerabilities as if you were using `C`.
68+
69+
*[noncompliant02.py](noncompliant02.py):*
70+
71+
```python
72+
""" Non-compliant Code Example """
73+
74+
import time
75+
76+
77+
def get_time_in_future(hours_in_future):
78+
"""Gets the time n hours in the future"""
79+
currtime = [tm for tm in time.localtime()]
80+
currtime[3] = currtime[3] + hours_in_future
81+
if currtime[3] + hours_in_future > 24:
82+
currtime[3] = currtime[3] - 24
83+
return time.asctime(tuple(currtime)).split(" ")[3]
84+
85+
86+
#####################
87+
# exploiting above code example
88+
#####################
89+
print(get_time_in_future(23**74))
90+
```
91+
92+
## Compliant Solution
93+
94+
This `compliant02.py` solution handles `OverflowError` Exception when a too large value is given to `get_time_in_future`.
95+
96+
*[compliant02.py](compliant02.py):*
97+
98+
```python
99+
""" Compliant Code Example """
100+
101+
import time
102+
103+
104+
def get_time_in_future(hours_in_future):
105+
"""Gets the time n hours in the future"""
106+
try:
107+
currtime = list(time.localtime())
108+
currtime[3] = currtime[3] + hours_in_future
109+
if currtime[3] + hours_in_future > 24:
110+
currtime[3] = currtime[3] - 24
111+
return time.asctime(tuple(currtime)).split(" ")[3]
112+
except OverflowError as _:
113+
return "Number too large to set time in future " + str(hours_in_future)
114+
115+
116+
#####################
117+
# attempting to exploit above code example
118+
#####################
119+
print(get_time_in_future(23**74))
120+
```
121+
122+
## Non-Compliant Code Example
123+
124+
The `noncompliant03.py` code example results in a `OverflowError: math range error`. This is due to `math.exp` being a `C` implementation behind the scenes for better performance. So while it returns a `Python float` it does use `C` type of variables internally for the calculation in `mathmodule.c` [[cpython 2024]](https://github.com/python/cpython/blob/main/Modules/mathmodule.c).
125+
126+
*[noncompliant03.py](noncompliant03.py):*
127+
128+
```python
129+
""" Non-compliant Code Example """
130+
131+
import math
132+
133+
134+
def calculate_exponential_value(number):
135+
"""Return 'E' raised to the power of different numbers:"""
136+
return math.exp(number)
137+
138+
139+
#####################
140+
# attempting to exploit above code example
141+
#####################
142+
print(calculate_exponential_value(1000))
143+
144+
```
145+
146+
## Compliant Solution
147+
148+
This `compliant03.py` solution detects the `integer` overflow by catching the appropriate Exception on overflow:
149+
150+
*[compliant03.py](compliant03.py):*
151+
152+
```python
153+
""" Compliant Code Example """
154+
import math
155+
156+
157+
def calculate_exponential_value(number):
158+
"""Return 'E' raised to the power of different numbers:"""
159+
try:
160+
return math.exp(number)
161+
except OverflowError as _:
162+
return "Number " + str(number) + " caused an integer overflow"
163+
164+
165+
#####################
166+
# attempting to exploit above code example
167+
#####################
168+
print(calculate_exponential_value(710))
169+
```
170+
171+
## Related Guidelines
172+
173+
|||
174+
|:---|:---|
175+
|[SEI CERT C Coding Standard](https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard)|[INT32-C. Ensure that operations on signed integers do not result in overflow](https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow)|
176+
|[SEI CERT Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[NUM00-J. Detect or prevent integer overflow](https://wiki.sei.cmu.edu/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow)|
177+
|ISO/IEC TR 24772:2010|Wrap-around Error [XYY]|
178+
|[MITRE CWE Pillar](http://cwe.mitre.org/)|[CWE-682: Incorrect Calculation](https://cwe.mitre.org/data/definitions/682.html)|
179+
|[MITRE CWE Base](http://cwe.mitre.org/)|[CWE-191, Integer Underflow (Wrap or Wraparound)](http://cwe.mitre.org/data/definitions/191.html)|
180+
|[MITRE CWE Base](http://cwe.mitre.org/)|[CWE-190, Integer Overflow or Wraparound](http://cwe.mitre.org/data/definitions/190.html)|
181+
182+
## Bibliography
183+
184+
|||
185+
|:---|:---|
186+
|[[Python 2024]](https://docs.python.org/3.9/library/stdtypes.html)|Format String Syntax. Available from: <https://docs.python.org/3.9/library/stdtypes.html> \[Accessed 20 June 2024]|
187+
|[[cpython 2024]](https://github.com/python/cpython/blob/main/Modules/mathmodule.c)|mathmodule.c. Available from: <https://github.com/python/cpython/blob/main/Modules/mathmodule.c)> \[Accessed 20 June 2024]|
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Compliant Code Example """
4+
5+
import warnings
6+
import numpy
7+
8+
warnings.filterwarnings("error")
9+
a = numpy.int64(numpy.iinfo(numpy.int64).max)
10+
with warnings.catch_warnings():
11+
try:
12+
print(a + 1)
13+
except Warning as _:
14+
print("Failed to increment " + str(a) + " due to overflow error")
15+
# RuntimeWarning and continues
16+
17+
try:
18+
b = numpy.int64(numpy.iinfo(numpy.int64).max + 1) # OverflowError and stops
19+
except OverflowError as e:
20+
print("Failed to assign value to B due to overflow error")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Compliant Code Example """
4+
5+
import time
6+
7+
8+
def get_time_in_future(hours_in_future):
9+
"""Gets the time n hours in the future"""
10+
try:
11+
currtime = list(time.localtime())
12+
currtime[3] = currtime[3] + hours_in_future
13+
if currtime[3] + hours_in_future > 24:
14+
currtime[3] = currtime[3] - 24
15+
return time.asctime(tuple(currtime)).split(" ")[3]
16+
except OverflowError as _:
17+
return "Number too large to set time in future " + str(hours_in_future)
18+
19+
20+
#####################
21+
# attempting to exploit above code example
22+
#####################
23+
print(get_time_in_future(23**74))
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
""" Compliant Code Example """
2+
import math
3+
4+
5+
def calculate_exponential_value(number):
6+
"""Return 'E' raised to the power of different numbers:"""
7+
try:
8+
return math.exp(number)
9+
except OverflowError as _:
10+
return "Number " + str(number) + " caused an integer overflow"
11+
12+
13+
#####################
14+
# attempting to exploit above code example
15+
#####################
16+
print(calculate_exponential_value(710))
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Non-compliant Code Example """
4+
5+
import numpy
6+
7+
a = numpy.int64(numpy.iinfo(numpy.int64).max)
8+
print(a + 1) # RuntimeWarning and continues
9+
print()
10+
b = numpy.int64(numpy.iinfo(numpy.int64).max + 1) # OverflowError and stops
11+
print(b) # we will never reach this
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Non-compliant Code Example """
4+
5+
import time
6+
7+
8+
def get_time_in_future(hours_in_future):
9+
"""Gets the time n hours in the future"""
10+
currtime = list(time.localtime())
11+
currtime[3] = currtime[3] + hours_in_future
12+
if currtime[3] + hours_in_future > 24:
13+
currtime[3] = currtime[3] - 24
14+
return time.asctime(tuple(currtime)).split(" ")[3]
15+
16+
17+
#####################
18+
# exploiting above code example
19+
#####################
20+
print(get_time_in_future(23**74))
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Non-compliant Code Example """
4+
5+
import math
6+
7+
8+
def calculate_exponential_value(number):
9+
"""Return 'E' raised to the power of different numbers:"""
10+
return math.exp(number)
11+
12+
13+
#####################
14+
# attempting to exploit above code example
15+
#####################
16+
print(calculate_exponential_value(1000))

docs/Secure-Coding-Guide-for-Python/readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ It is **not production code** and requires code-style or python best practices t
5555

5656
|[CWE-682: Incorrect Calculation](https://cwe.mitre.org/data/definitions/682.html)|Prominent CVE|
5757
|:---------------------------------------------------------------------------------------------------------------|:----|
58+
|[CWE-191: Integer Underflow (Wrap or Wraparound)](CWE-682/CWE-191/README.md)||
5859
|[CWE-1335: Promote readability and compatibility by using mathematical written code with arithmetic operations instead of bit-wise operations](CWE-682/CWE-1335/01/README.md)||
5960
|[CWE-1339: Insufficient Precision or Accuracy of a Real Number](CWE-682/CWE-1339/.) ||
6061

0 commit comments

Comments
 (0)