Skip to content

pySCG: BUG in CWE-191, lambda is not adding hours but every time.localtime() type including year, day etc #835

Open
@myteron

Description

@myteron

noncompliant02.py code example in the README.md does not match the file and is also doing the wrong thing.

https://github.com/ossf/wg-best-practices-os-developers/blob/main/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/README.md

# current code in 02.py:
currtime = [tm for tm in time.localtime()]
print(currtime)
# here what it does:
currtime = [print(tm) for tm in time.localtime()]

# here what it should be doing to add hours:
currtime = [print(tm) for tm in time.localtime().tm_hour]

All x02 code examples would not work when given a input within range such as 12 hours in the future starting from 11:28 ends in ValueError: hour out of range.

the code in the noncompliant02.py file is closer to reality but very obscure the actually issue occurs when using time.asctime()

alternative example02.py code:

# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Compliant Code Example"""

from datetime import datetime, timedelta
import re
import sys


def get_time_in_future(hours_in_future: int):
    """Gets the time n hours in the future"""
    # TODO: input sanitation
    # TODO: proper logging

    currtime = datetime.now()
    return currtime + timedelta(hours=hours_in_future)


#####################
# attempting to exploit above code example
#####################
print("-------- adding 23**5 ---------")
print(get_time_in_future(23**5))
print("=" * 60)
print("-------- adding 23**74 ---------")
print(get_time_in_future(23**74))

Example output:

-------- adding 23**5 ---------
2759-06-28 14:59:08.021771
============================================================
-------- adding 23**74 ---------
Traceback (most recent call last):
  File "example02.py", line 26, in <module>
    print(get_time_in_future(23**74))
  File "example02.py", line 16, in get_time_in_future
    return currtime + timedelta(hours=hours_in_future)
OverflowError: Python int too large to convert to C int

Once cleaned up we end up with re-throwing.
That is a unsatisfactory as a compliant solution. Naturally we should be guarding boundaries before we hit them. There are a few of those:

from datetime import datetime, timedelta
sometime = datetime.fromtimestamp(0)
hours_list = [
    70389526,
    70389527,
    24000000001,
    51539700001,
    -17259889,
    -17259890,
    -23999999999,
    -51539699999,
]
for hours in hours_list:
    try:
        result = sometime + timedelta(hours=hours)
        print(f"{hours} OK, datetime='{result}'")
    except Exception as exception:
        print(f"{hours} {repr(exception)}")

example output:

70389526 OK, datetime='9999-12-31 23:00:00'
70389527 OverflowError('date value out of range')
24000000001 OverflowError('days=1000000000; must have magnitude <= 999999999')
51539700001 OverflowError('Python int too large to convert to C int')
-17259889 OK, datetime='0001-01-01 00:00:00'
-17259890 OverflowError('date value out of range')
-23999999999 OverflowError('days=-1000000000; must have magnitude <= 999999999')
-51539699999 OverflowError('Python int too large to convert to C int')

Specifically:

  • date value out of range
  • OverflowError('Python int too large to convert to C int')
  • 'days=1000000000; must have magnitude <= 999999999')

Unfortunately the first date value out of range is a moving target that changes according to start datetime in use. When we start with datetime.fromtimestamp(0) or '1970-01-01 01:00:00we have the 'date value out of range' in beyond-17259889and70389526`. Those numbers change depending on the datetime we start with.

The Python int too large to convert to C int beyond -23999999999 and 24000000001 is more predictable.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions