Skip to content

Cap window_size and distance in glcm_texture (#1257)#1259

Merged
brendancol merged 1 commit into
mainfrom
issue-1257
Apr 25, 2026
Merged

Cap window_size and distance in glcm_texture (#1257)#1259
brendancol merged 1 commit into
mainfrom
issue-1257

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

  • Cap window_size at max(3, min(rows, cols)) and distance at max(1, window_size // 2) in glcm_texture().
  • Without the caps, window_size=1_000_001 on a 10x10 raster ran ~10**14 numba loop iterations (CPU DoS), and the dask backends padded every block by (window_size, window_size) on top of the chunk (memory DoS). See glcm: unbounded window_size and distance enable CPU and memory DoS #1257.
  • levels is already capped at 256, so the per-pixel np.zeros((levels, levels)) matrix is bounded. No change there.
  • Record the sweep result for glcm in .claude/sweep-security-state.json.

Test plan

  • New unit tests reject oversize window_size and oversize distance at the public entrypoint.
  • New unit tests confirm boundary cases (window_size == min(rows, cols), distance == window_size // 2) still work.
  • Existing validation tests updated to use 8x8 rasters so the default window_size=7 does not trip the new cap.
  • pytest xrspatial/tests/test_glcm.py passes (34/34).

Closes #1257.

glcm_texture() validated window_size only as >= 3 and distance only as
>= 1, with no upper bound on either. The numba kernel iterates
range(r-half, r+half+1) for every pixel, so window_size=1_000_001 on a
10x10 raster ran roughly 10**14 loop iterations with every neighbor
failing the interior bounds check -- a CPU-time DoS from one int passed
to the public API. The dask backends additionally use
depth = window_size // 2 + distance for map_overlap padding, so the
same input also caused oversize per-chunk allocations (memory DoS).

Add caps in the public entrypoint:

- window_size <= max(3, min(rows, cols))
- distance <= max(1, window_size // 2)

The floor of 3 / 1 keeps the error messages coherent for very small
rasters (1x1, 2x2) where the existing "must be odd, >= 3" contract
would otherwise become unsatisfiable. One cap covers all four backends
because cupy and dask+cupy call through to the CPU kernel after a
cupy.asnumpy transfer.

levels is already capped at 256 so the per-pixel np.zeros((levels,
levels)) matrix is bounded. No other changes to the kernel.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Apr 24, 2026
@brendancol brendancol merged commit ad7d693 into main Apr 25, 2026
11 checks passed
@brendancol brendancol deleted the issue-1257 branch May 4, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

glcm: unbounded window_size and distance enable CPU and memory DoS

1 participant