Skip to content

[6.1.6] Add TDS token data length bounds checks (#4340)#4359

Open
github-actions[bot] wants to merge 1 commit into
release/6.1from
dev/automation/pr-4340-to-6.1.6
Open

[6.1.6] Add TDS token data length bounds checks (#4340)#4359
github-actions[bot] wants to merge 1 commit into
release/6.1from
dev/automation/pr-4340-to-6.1.6

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown

Description

Re-implementation of #4340 (b6c05695a) for the release/6.1 branch layout.

Adds bounds checks to TDS token parsing to prevent unbounded memory allocation from a malicious server spoofing length fields.

Bounds checks added

Location Limit
ENV_PROMOTETRANSACTION reject > 64 KB
TryProcessFeatureExtAck data length reject > 1 MB
TryProcessSessionState total length reject > 1 MB
TryProcessSessionState per-state length reject > 1 MB
TryProcessFedAuthInfo token length reject > 1 MB
TryProcessReturnValue value length reject > int.MaxValue (was silent truncation)
TryReadSqlDateTime length reject > 10 bytes (max DateTimeOffset wire size)
SQLVECTOR/binary read reject > MAXSIZE
SqlInternalConnectionTds session recovery reject overread of state buffer

New constants

  • TdsEnums.MaxTokenDataLength = 1 MB
  • TdsEnums.MaxPromoteTransactionLength = 64 KB
  • TdsEnums.MaxDateTimeLength = 10

New tests (14 total)

  • FeatureExtAckBoundsTests (2 tests) — oversized feature ext ack data
  • TdsTokenBoundsTests (12 tests) — all other bounds checks via simulated TDS server

Test infrastructure additions

  • GenericTdsServer.OnSQLBatchCompleted delegate hook
  • TdsServerFixture xunit fixture class

Files changed

  • src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs
  • src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs
  • src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs
  • src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs
  • src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
  • src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
  • src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTdsServer.cs
  • New: tests/UnitTests/SimulatedServerTests/Fixtures/TdsServerFixture.cs
  • New: tests/UnitTests/SimulatedServerTests/FeatureExtAckBoundsTests.cs
  • New: tests/UnitTests/SimulatedServerTests/TdsTokenBoundsTests.cs

Verification

  • netcore build: 0 errors, 0 warnings
  • netfx build: 0 errors, 0 warnings
  • New bounds tests: 14/14 passed
  • Existing SimulatedServerTests: no regressions (123/123 passed; 1 pre-existing platform-specific skip)

Fixes #4340

@github-actions github-actions Bot added this to the 6.1.6 milestone Jun 11, 2026
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Jun 11, 2026
Re-implementation of b6c0569 for the release/6.1 branch layout.

Adds bounds checks to TDS token parsing to prevent unbounded memory
allocation from a malicious server spoofing length fields:

- ENV_PROMOTETRANSACTION: reject > 64 KB
- FeatureExtAck data: reject > 1 MB
- SessionState total + per-state: reject > 1 MB
- FedAuthInfo: reject > 1 MB
- ReturnValue: reject > int.MaxValue (was silent truncation)
- TryReadSqlDateTime: reject > 10 bytes (max DateTimeOffset wire size)
- SQLVECTOR/binary: reject > MAXSIZE

Also adds bounds check in SqlInternalConnectionTds session recovery
parsing to prevent buffer overread from spoofed state lengths.

New constants: TdsEnums.MaxTokenDataLength (1 MB),
MaxPromoteTransactionLength (64 KB), MaxDateTimeLength (10).

New tests: FeatureExtAckBoundsTests (2 tests),
TdsTokenBoundsTests (12 tests) using simulated TDS server.
@paulmedynski paulmedynski force-pushed the dev/automation/pr-4340-to-6.1.6 branch from 528f903 to 81947eb Compare June 15, 2026 11:17
@paulmedynski paulmedynski changed the title [6.1.6 Cherry-pick - CONFLICTS] Add TDS token data length bounds checks [6.1] Add TDS token data length bounds checks (#4340) Jun 15, 2026
@paulmedynski paulmedynski added the Code Health 💊 Issues/PRs that are targeted to source code quality improvements. label Jun 15, 2026
@paulmedynski paulmedynski moved this from To triage to In progress in SqlClient Board Jun 15, 2026
@paulmedynski

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

@paulmedynski paulmedynski marked this pull request as ready for review June 15, 2026 13:56
@paulmedynski paulmedynski requested a review from a team as a code owner June 15, 2026 13:56
Copilot AI review requested due to automatic review settings June 15, 2026 13:56
@paulmedynski paulmedynski enabled auto-merge (squash) June 15, 2026 13:56
@paulmedynski paulmedynski changed the title [6.1] Add TDS token data length bounds checks (#4340) [6.1.6] Add TDS token data length bounds checks (#4340) Jun 15, 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 TDS token parsing in Microsoft.Data.SqlClient by adding upper-bound validation to length fields read from the wire, preventing unbounded allocations (and related OOB risks) when connected to a malicious or corrupted server.

Changes:

  • Added maximum length constants (1 MB token payload cap, 64 KB promote-transaction cap, 10-byte datetime cap) and enforced them during token parsing.
  • Converted several debug-only assertions into runtime validation that throws SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, ...).
  • Added simulated-server infrastructure and new unit tests covering the new bounds checks.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs Introduces new max-length constants used by the parser.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs Adds ParsingErrorLength overload for uint lengths.
src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs Adds bounds checks to multiple token parsing paths (netcore).
src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs Adds bounds checks to multiple token parsing paths (netfx).
src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs Validates SRECOVERY inner-state lengths before copying state buffers (netcore).
src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs Validates SRECOVERY inner-state lengths before copying state buffers (netfx).
src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTdsServer.cs Adds a hook to mutate SQL batch responses for simulated server tests.
src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/Fixtures/TdsServerFixture.cs New fixture to manage per-test TDS server lifecycle.
src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/FeatureExtAckBoundsTests.cs New tests for FeatureExtAck payload length bounds.
src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/TdsTokenBoundsTests.cs New comprehensive tests for bounds checks across multiple token types.

using Microsoft.SqlServer.TDS.Done;
using Microsoft.SqlServer.TDS.FeatureExtAck;
using Microsoft.SqlServer.TDS.Servers;
using Microsoft.SqlServer.TDS.SessionState;
Comment on lines +8 to +11
/// <summary>
/// An xunit test fixture that manages the lifecycle of a TdsServer.
/// </summary>
public class TdsServerFixture : IDisposable
/// sent to the client. Tests can use this to inject or replace tokens in the
/// response message.
/// </summary>
public Action<TDSMessage> OnSQLBatchCompleted { get; set; }
Comment on lines +82 to +83
Assert.Contains("Error state: 18", ex.Message); // ParsingErrorState.CorruptedTdsStream = 18
Assert.Contains($"Length: {TdsEnums.MaxTokenDataLength + 1}", ex.Message);
// The connection will fail (insufficient data for the claimed length),
// but the failure must NOT be the bounds-check error.
Exception ex = Assert.ThrowsAny<Exception>(connection.Open);
Assert.DoesNotContain("Error state: 18", ex.Message);
Comment on lines +75 to +76
Assert.Contains("Error state: 18", ex.Message); // CorruptedTdsStream
Assert.Contains($"Length: {TdsEnums.MaxTokenDataLength + 1}", ex.Message);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Code Health 💊 Issues/PRs that are targeted to source code quality improvements.

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

4 participants