diff --git a/CWE-664/CWE-400/README.md b/CWE-664/CWE-400/README.md new file mode 100644 index 0000000..d2ea79e --- /dev/null +++ b/CWE-664/CWE-400/README.md @@ -0,0 +1,107 @@ +# CWE-400: Uncontrolled Resource Consumption + +Canceling the task in a thread pool only prevents it from being executed if it has not started yet. For the task to be interruptible, it must handle the `threading.Event` flag. + +## Non-Compliant Code Example + +Tasks can be submitted to the ThreadPoolExecutor by calling `submit()`. Submitted tasks can be canceled by calling `cancel()` on the Future object returned by `submit()`. Calling this method will return True and stop the task from being executed if it has not started yet. However, if its execution has already started, calling `cancel()` will instead return False and will not stop the task [[Python 3.10.4 docs on threading.Event]](https://docs.python.org/3/library/threading.html#event-objects). + +[*noncompliant01.py:*](noncompliant01.py) + +```py +""" Non-compliant Code Example """ +import time +from concurrent.futures import ThreadPoolExecutor + + +def take_time(x): + print(f"Started Task: {x}") + # Simulate work + for i in range(10): + time.sleep(1) + print(f"Completed Task: {x}") + + +def run_thread(_executor, var): + future = _executor.submit(take_time, var) + return future + + +def interrupt(future): + print(future.cancel()) + print(f"Interrupted: {future}") + + +##################### +# Exploiting above code example +##################### + + +with ThreadPoolExecutor() as executor: + task = run_thread(executor, "A") + interrupt(task) + +``` + +## Compliant Solution + +Tasks submitted to the ThreadPoolExecutor can be interrupted by setting a thread-safe flag, such as `threading.Event` [[Python 3.10.4 docs on threading.Event]](https://docs.python.org/3/library/threading.html#event-objects). An Event object should be passed as an argument to the submitted task. From within the task function, we need to manually check the flag status by calling `event.is_set()` and handling the interruption. In order to set the Event flag, we can call `event.set()` on the event object. + +[*compliant01.py:*](compliant01.py) + +```py +""" Compliant Code Example """ +import time +from concurrent.futures import ThreadPoolExecutor +from threading import Event + + +def take_time(x, _event): + print(f"Started Task: {x}") + # Simulate work + for _ in range(10): + if _event.is_set(): + print(f"Interrupted Task: {x}") + # Save partial results + return + time.sleep(1) + print(f"Completed Task: {x}") + + +def run_thread(_executor, var): + e = Event() + future = _executor.submit(take_time, var, e) + return future, e + + +def interrupt(future, e): + """Cancel the task, just in case it is not yet running, and set the Event flag""" + future.cancel() + e.set() + + +##################### +# Exploiting above code example +##################### + + +with ThreadPoolExecutor() as executor: + task, event = run_thread(executor, "A") + interrupt(task, event) + +``` + +## Related Guidelines + +||| +|:---|:---| +|[MITRE CWE](http://cwe.mitre.org/)|Pillar [CWE-664: Improper Control of a Resource Through its Lifetime (4.13) (mitre.org)](https://cwe.mitre.org/data/definitions/664.html)| +|[MITRE CWE](http://cwe.mitre.org/)|Class [CWE-400: Uncontrolled Resource Consumption (4.12)](https://cwe.mitre.org/data/definitions/400.html)| +|[SEI CERT Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[TPS02-J. Ensure that tasks submitted to a thread pool are interruptible](https://wiki.sei.cmu.edu/confluence/display/java/TPS02-J.+Ensure+that+tasks+submitted+to+a+thread+pool+are+interruptible)| + +## Bibliography + +||| +|:---|:---| +|[[Python 3.10.4 docs Future.cancel]](https://docs.python.org/3/library/concurrent.futures.html)|concurrent.futures — Launching parallel tasks — Python 3.10.4 documentation. Available from: \[Last Accessed May 2024]| +|[[Python 3.10.4 docs on threading.Event]](https://docs.python.org/3/library/threading.html#event-objects)|threading — Thread-based parallelism - Event Objects. Available from: \[Last Accessed May 2024]| diff --git a/README.md b/README.md index 3bb4a92..7b2ce9f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ It is **not production code** and requires code-style or python best practices t |:-----------------------------------------------------------------------------------------------------------------------------------------------|:----| |[CWE-134: Use of Externally-Controlled Format String](CWE-664/CWE-134/.)|[CVE-2022-27177](https://www.cvedetails.com/cve/CVE-2022-27177/),
CVSSv3.1: **9.8**,
EPSS:**00.37**(01.12.2023)| |[CWE-197: Numeric Truncation Error](CWE-664/CWE-197/.)|| -|[CWE-400: Uncontrolled Resource Consumption](CWE-664/CWE-400/.)|| +|[CWE-400: Uncontrolled Resource Consumption](CWE-664/CWE-400/README.md)|| |[CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)](CWE-664/CWE-409/.)|| |[CWE-410: Insufficient Resource Pool](CWE-664/CWE-410/.)|| |[CWE-502: Deserialization of Untrusted Data)](CWE-664/CWE-502/.)||