Skip to content

Guard morphology kernel allocations against oversized kernels #1256

Description

@brendancol

Summary

The public morphology API (morph_erode, morph_dilate, morph_opening, morph_closing, morph_gradient, morph_white_tophat, morph_black_tophat) takes a user-supplied kernel argument. The only checks are 2D shape, uint8 dtype, and odd dimensions. Kernel size drives the padded input allocation on every backend, with no cap.

Problem

In xrspatial/morphology.py:

  • _morph_numpy (around line 152): np.pad(arr, ((hy, hy), (hx, hx)), ...) builds a padded float64 array of shape (rows + ky - 1, cols + kx - 1).
  • _morph_cupy (around line 245): same pattern on the GPU via cp.pad.
  • Dask paths call map_overlap(..., depth=(hy, hx)), which grows per-chunk memory by the same factor.

A kernel like np.ones((99999, 99999), dtype=np.uint8) on a 1000x1000 raster will ask the process for roughly 80 GB of padded float64 memory with no warning. bilateral.py (#1236), convolution.py (#1241), and bump.py (#1231) have already fixed this class of issue with an _available_memory_bytes() guard.

Proposed fix

  1. Add a local _available_memory_bytes() helper copied from convolution.py. It reads /proc/meminfo, falls back to psutil, then to a 2 GB default.
  2. Add _check_kernel_memory(rows, cols, ky, kx) that raises MemoryError if the padded float64 array would exceed 50% of available RAM. The message should name the kernel shape, the raster shape, and suggest a smaller kernel.
  3. Call the check inside _dispatch() after _validate_kernel so every public entry point is covered across all four backends.

Impact

Severity: HIGH (Cat 1, Unbounded Allocation / DoS). Found during the morphology security sweep on 2026-04-24. Nobody passes a kernel larger than their raster in practice, so the guard should not affect real workflows.

Tests

Add a test that patches _available_memory_bytes to a tiny value and checks that morph_erode raises MemoryError with an informative message when a large kernel is passed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghigh-priorityinput-validationInput validation and error messagesoomOut-of-memory risk with large datasets

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions