Skip to content

Fix potential issues in WPF Native Code #11797

Open
himgoyalmicro wants to merge 2 commits into
dotnet:mainfrom
himgoyalmicro:fixing_pixel_shader
Open

Fix potential issues in WPF Native Code #11797
himgoyalmicro wants to merge 2 commits into
dotnet:mainfrom
himgoyalmicro:fixing_pixel_shader

Conversation

@himgoyalmicro

@himgoyalmicro himgoyalmicro commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #11782
Fixes #11783
Fixes #11784

Description

Fix potential issues in WPF Native Code

Microsoft Reviewers: Open in CodeFlow

This PR addresses multiple MSRC-reported security vulnerabilities in WPF's native rendering pipeline by adding bounds checks and overflow protection to prevent out-of-bounds writes and heap corruption.

## Changes

### 1. Pixel Shader bytecode validation

**File:** `WpfGfx/core/fxjit/PixelShader/pstrans.cpp`

- Reject excessively large shader bytecode (> 1MB) to prevent integer overflow in allocation calculations
- Validate sampler register numbers against `PSTR_MAX_TEXTURE_SAMPLERS` before array indexing
- Validate input register numbers against `PSTR_MAX_NUMINPUTREG` before use
- Validate texture register numbers against `PSTR_MAX_NUMTEXTUREREG` before use
- Cap source parameter count at `PSTR_MAX_NUMSRCPARAMS` to prevent OOB writes
- Validate sampler stage index before use in texture lookup paths
- Gracefully fail with `E_FAIL` instead of corrupting heap memory

### 2. GuidelineCollection heap overflow fix

**File:** `WpfGfx/core/common/guidelinecollection.cpp`

- Add safe integer multiplication (`UIntMult`/`UIntAdd`) for allocation size calculation in `CSnappingFrame::PushFrame`
- Prevents heap corruption when `uCountX + uCountY` would cause `sizeof(float) * uCount * 2` to overflow

### 3. System.Printing gradient band overflow fix

**File:** `System.Printing/CPP/src/GDIExporter/gdirt.cpp`

- Cap gradient group range to 10,000 in `FillLinearGradient` to prevent integer overflow in band/vertex/index calculations
- Returns `E_NOTIMPL` for excessively large gradient ranges

## Opt-out Switches

All fixes are gated behind AppContext switches for servicing safety:

## Testing

- Validated with crafted malicious pixel shader bytecode PoCs that previously caused OOB heap writes
- Verified that well-formed shaders and documents continue to render correctly
- Confirmed opt-out switches disable the checks when set

## Risk

**Low.** All changes add early-exit validation before existing code paths. No behavioral change for valid inputs. 


----
#### AI description  (iteration 1)
#### PR Classification
Security bug fix adding bounds checking and validation to prevent integer overflow vulnerabilities in WPF pixel shader and printing components.

#### PR Summary
This PR implements comprehensive bounds checking and validation to protect against buffer overflows and integer overflow attacks in WPF's pixel shader processing and printing subsystems. The changes introduce AppContext switches that allow disabling these protections for compatibility, with protections enabled by default.

- `pstrans.cpp`: Added validation for bytecode size limits (max 1MB), source parameter counts, register numbers (sampler, input, texture), and DCL token counts to prevent buffer overflows in pixel shader processing
- `guidelinecollection.cpp`: Added integer overflow protection when calculating allocation sizes for snapping frame float data arrays
- `PrintingSwitches.h` and `WpfGfxSwitches.h` (new files): Introduced AppContext switches `Switch.MS.Internal.Printing.DisablePrintingB...
This PR addresses multiple vulnerabilities where WPF's restrictive/unsafe XAML loading path could be bypassed, allowing attacker-controlled XAML to instantiate dangerous types (e.g., `ObjectDataProvider` → `Process.Start`) and achieve Remote Code Execution.

## Changes

### 1. Async XamlReader.LoadAsync taint propagation fix

**File:** `System/Windows/Markup/XamlReader.cs`

The synchronous `WpfXamlLoader` propagates `IsUnsafe = true` to nested-load-capable objects (`ResourceDictionary`, `Frame`, `NavigationWindow`) when loaded under `RestrictiveXamlXmlReader`. The asynchronous `LoadAsync` path was missing this propagation, allowing a first-stage async-loaded `ResourceDictionary` to load second-stage unrestricted XAML via its `Source` property.

**Fix:** Add the same taint propagation in `LoadAsync`'s `AfterBeginInitHandler`:

```csharp
if (_textReader is RestrictiveXamlXmlReader && args != null)
{
    if (args.Instance is ResourceDictionary rd)
        rd.IsUnsafe = true;
    else if (args.Instance is Frame frame)
        frame.NavigationService.IsUnsafe = true;
    else if (args.Instance is NavigationWindow nw)
        nw.NavigationService.IsUnsafe = true;
}
```

### 2. FixedPage NavigateUri → NavigationService unsafe taint

**File:** `System/Windows/Navigation/NavigationService.cs`

When navigation originates from a FixedPage element (Path, Canvas, Glyphs, or FixedPage) carrying `FixedPage.NavigateUri`, the target content could be attacker-controlled XAML within an XPS package. The `NavigationService` was not marked as unsafe in this path, allowing the XAML loader to process the content without restrictions.

**Fix:** Detect FixedPage-origin navigation in `OnRequestNavigate` and set `IsUnsafe = true` before the navigation proceeds.

### 3. XAML deserialization bypass in Undo and Clipboard paths

**Files:**
- `MS/Internal/Ink/ClipboardProcessor.cs`
- `System/Windows/Documents/TextTreeDeleteContentUndoUnit.cs`

Both the clipboard paste (InkCanvas) and text undo code paths call `XamlReader.Load` to deserialize stored XAML without the restrictive reader. An attacker who can influence clipboard content or trigger undo of crafted content could instantiate arbitrary types.

**Fix:** Pass `useRestrictiveXamlReader: true` to `XamlReader.Load` in both paths.

## Attack Scenarios Addressed

| Vector | Before | After |
|--------|--------|-------|
| XPS document with Frame → async ResourceDictionary → ObjectDataProvider | RCE | Blocked by restrictive reader |
| XPS FixedPage NavigateUri → attacker XAML part | RCE | Blocked (NavigationService marked unsafe) |
| Clipboard/Undo XAML deserialization with gadget types | RCE | Blocked by restrictive reader |

## Testing

- Validated with PoC: XPS package exploiting async taint gap on .NET 10(previously vulnerable) now blocks payload
- Verified synchronous restrictive path remains unaffected
- Confirmed normal XPS rendering, clipboard, and undo operations continue to work

## Risk

**Low.** The changes enforce the...
@himgoyalmicro
himgoyalmicro requested review from a team and Copilot July 20, 2026 09:29
@himgoyalmicro
himgoyalmicro requested a review from a team as a code owner July 20, 2026 09:29
@dotnet-policy-service dotnet-policy-service Bot added the PR metadata: Label to tag PRs, to facilitate with triage label Jul 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens WPF’s native rendering / printing code and managed XAML loading/navigation paths against malicious or malformed inputs (notably attacker-controlled XAML scenarios), aligning with the security advisories linked in #11782 / #11783 / #11784.

Changes:

  • Add bounds/range checks in WpfGfx native code paths (pixel shader translation, guideline frame allocations) guarded by an AppContext switch.
  • Add a new System.Printing AppContext switch and cap gradient group ranges to avoid overflow in GDI gradient fill calculations.
  • Treat certain navigation/XAML load scenarios as “unsafe” and route through the restrictive XAML reader; enable restrictive loading for undo/clipboard-related XAML roundtrips.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/fxjit/PixelShader/pstrans.cpp Adds bytecode size and token/register bounds checks to avoid overflows / OOB access during pixel shader translation.
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/fxjit/PixelShader/precomp.h Includes WpfGfxSwitches so new bounds-check protections can be toggled.
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/guidelinecollection.cpp Uses overflow-checked size computations for CSnappingFrame allocation when protections are enabled.
src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/GDIExporter/gdirt.cpp Caps gradient group range (with switch) to prevent overflows in band/vertex/index computations.
src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/inc/PrintingSwitches.h Adds an AppContext-backed switch to disable printing bounds-check protection.
src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/inc/GDIExporter/precomp.hpp Includes PrintingSwitches.h for use by the GDI exporter.
src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Navigation/NavigationService.cs Marks NavigationService as unsafe when navigation originates from FixedPage NavigateUri scenarios.
src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlReader.cs Propagates “unsafe” state when using RestrictiveXamlXmlReader to ResourceDictionary / Frame / NavigationWindow.
src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextTreeDeleteContentUndoUnit.cs Switches undo-object rehydration to use the restrictive XAML reader.
src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Ink/ClipboardProcessor.cs Switches InkCanvas copy rehydration to use the restrictive XAML reader.
Comments suppressed due to low confidence (2)

src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Ink/ClipboardProcessor.cs:345

  • XamlReader.Load(..., useRestrictiveXamlReader: true) can return null (if the restrictive reader skips the root) or throw (e.g., XamlObjectWriterException). As written, this can cause AddChild(newElement) / UpdateElementBounds to throw, breaking copy. Handle null/parse failures and return false so CopySelectedData can fall back to ISF-only copy.
                        string xml = XamlWriter.Save(elements[i]);

                        UIElement newElement = XamlReader.Load(new XmlTextReader(new StringReader(xml)), useRestrictiveXamlReader: true) as UIElement;
                        ((IAddChild)inkCanvas).AddChild(newElement);

                        // Now we tranform the element.
                        inkCanvasSelection.UpdateElementBounds(elements[i], newElement, transform);
                    }

src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextTreeDeleteContentUndoUnit.cs:373

  • With the restrictive XAML reader enabled, load failures may surface as System.Xaml.XamlObjectWriterException (not just XamlParseException). Without catching it, undo could throw instead of falling back to the placeholder Grid.

Consider catching XamlObjectWriterException the same way as XamlParseException so failures remain non-fatal.

                    try
                    {
                        embeddedObject = (DependencyObject)XamlReader.Load(new XmlTextReader(new StringReader(_xml)), useRestrictiveXamlReader: true);
                    }
                    catch (XamlParseException e)
                    {
                        Invariant.Assert(e != null); // Placed here for debugging convenience - to be able to see the exception.
                    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1550 to +1557
if (!PrintingSwitches::IsPrintingBoundsCheckProtectionDisabled())
{
const int MaximumGradientGroupRange = 10000;
if ((lastGroupIndex - firstGroupIndex) > MaximumGradientGroupRange)
{
return E_NOTIMPL;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR metadata: Label to tag PRs, to facilitate with triage

Projects

None yet

2 participants