Skip to content

Guard morphology kernel allocations against oversized kernels #1256

@brendancol

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfocal toolsFocal statistics and hotspot analysishigh-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