Skip to content

Conversation

jepler
Copy link
Contributor

@jepler jepler commented Sep 1, 2025

Summary

Frequently, allocations are sized based on a computation like base_size + count * entry_size or just count * entry_size.

If an integer overflow occurs in computation and is not checked for, this can lead to success with a smaller-than-intended allocation, followed by out-of-bounds access to the buffer. This is the underlying cause of #17925.

Add a utility function mp_compute_size_overflow to compute base_size + count * entry_size and use it in previously identified contexts:

  • the m_new and m_renew family of macros, which know the type and count of the objects they allocate
  • list, str, and tuple BINARY_OP_MULTIPLY, which create repetitions of a sequence.

In the latter case, note that overflow can occur in the a first step (when calculating the new count of elements) or in a second step (when calculating the number of bytes).

mp_compute_size_overflow doesn't directly raise an exception; instead, it returns SIZE_MAX, assuming no allocation of exactly SIZE_MAX can ever succeed. The existing code paths either return NULL or raise an exception, just as before.

The exception path will show an incorrect attempted allocation size e.g., 4294967295, in this case.

  • Look for alternatives that would reduce code growth
  • Fix natmod building
  • Implement a pathway for "non-gcc" compilers
  • Try to identify any other pathways that could have overflows of this type
  • Add tests that explicitly exercise the overflow paths

Closes: #17925

Testing

I'm relying on CI testing to find any regressions introduced by this change.

Trade-offs and Alternatives

The main alternative is to do nothing and accept that these constructs can cause crashes or wrong behavior. I have not identified any specific non-crashing behavior, but overflows of this type have been recognized as having security impacts as in e.g.,https://seclists.org/bugtraq/2002/Aug/91

@jepler jepler force-pushed the allocation-overflow branch from 809c468 to 5cfd078 Compare September 1, 2025 02:02
@jepler jepler marked this pull request as draft September 1, 2025 02:03
Copy link

github-actions bot commented Sep 1, 2025

Code size report:

   bare-arm:  +248 +0.437% 
minimal x86:  +566 +0.300% 
   unix x64:  +744 +0.087% standard
      stm32:  +248 +0.063% PYBV10
     mimxrt:  +256 +0.068% TEENSY40
        rp2:  +520 +0.056% RPI_PICO_W
       samd:  +224 +0.082% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:  +178 +0.039% VIRT_RV32

Frequently, allocations are sized based on a computation
like `base_size + count * entry_size`.

If an integer overflow occurs in computation and is not checked
for, this can lead to success with a smaller-than-intended
allocation, followed by out-of-bounds access to the buffer.

Add a utility function `mp_compute_size_overflow` to compute
`base_size + count * entry_size` and use it in previously identified
contexts:
 * the m_new and m_renew family of macros, which know the type
   and count of the objects they allocate
 * list, str, and tuple BINARY_OP_MULTIPLY, which create repetitions
   of a sequence.

In the latter case, note that overflow can occur in the a first
step (when calculating the new *count of elements*) or in
a second step (when calculating the *number of bytes*).

`mp_compute_size_overflow` doesn't directly raise an exception;
instead, it returns SIZE_MAX, assuming no allocation of exactly
SIZE_MAX can ever succeed. The existing code paths either return
NULL or raise an exception, just as before.

At the current time none of the paths with m_malloc_with_finaliser
(mp_obj_malloc_var_with_finaliser) seem to have an uncontrolled
size parameter.

The exception path will show an incorrect attempted allocation size
e.g., 4294967295, in this case.

Signed-off-by: Jeff Epler <jepler@gmail.com>
@jepler jepler force-pushed the allocation-overflow branch from 5cfd078 to 2444b9c Compare September 1, 2025 13:52
Signed-off-by: Jeff Epler <jepler@gmail.com>
This probably only saves code when MICROPY_MEM_STATS is enabled.

Signed-off-by: Jeff Epler <jepler@gmail.com>
These are still prone to overflow.

Signed-off-by: Jeff Epler <jepler@gmail.com>
Copy link

codecov bot commented Sep 1, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.39%. Comparing base (704c70c) to head (10b5623).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #18020   +/-   ##
=======================================
  Coverage   98.38%   98.39%           
=======================================
  Files         171      171           
  Lines       22296    22306   +10     
=======================================
+ Hits        21937    21947   +10     
  Misses        359      359           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jepler jepler force-pushed the allocation-overflow branch from 3cc00a2 to b7ffce8 Compare September 1, 2025 19:42
Signed-off-by: Jeff Epler <jepler@gmail.com>
@jepler jepler force-pushed the allocation-overflow branch from b7ffce8 to d518e7f Compare September 1, 2025 22:56
Signed-off-by: Jeff Epler <jepler@gmail.com>
@jepler
Copy link
Contributor Author

jepler commented Sep 1, 2025

natmod doesn't actually check for overflows, but it does build again.

@jepler jepler marked this pull request as ready for review September 1, 2025 23:56
@jepler
Copy link
Contributor Author

jepler commented Sep 2, 2025

This is an interesting, if 10+ year old, review of programming errors in memory allocators, focusing on overflows: https://kqueue.org/blog/2012/03/05/memory-allocator-security-revisited/

While several allocators investigated there had problems with allocations of SIZE_MAX returning non-NULL, the usual micropython allocator works properly in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

hard crash when producing a large string via "*"
1 participant