Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2799,6 +2799,12 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
{
len = bLen;
}

if (len < 0 || len > data.Length - i)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, len);
}

byte[] stateData = new byte[len];
Buffer.BlockCopy(data, i, stateData, 0, len);
i += len;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2906,6 +2906,10 @@ private TdsOperationStatus TryProcessEnvChange(int tokenLength, TdsParserStateOb
// new value has 4 byte length
return result;
}
if (env._newLength < 0 || env._newLength > TdsEnums.MaxPromoteTransactionLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, env._newLength);
}
// read new value with 4 byte length
env._newBinValue = new byte[env._newLength];
result = stateObj.TryReadByteArray(env._newBinValue, env._newLength);
Expand Down Expand Up @@ -3300,10 +3304,15 @@ private TdsOperationStatus TryProcessFeatureExtAck(TdsParserStateObject stateObj
{
return result;
}
byte[] data = new byte[dataLen];
if (dataLen > 0)
if (dataLen > (uint)TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, dataLen);
}
int dataLength = (int)dataLen;
byte[] data = new byte[dataLength];
if (dataLength > 0)
{
result = stateObj.TryReadByteArray(data, checked((int)dataLen));
result = stateObj.TryReadByteArray(data, dataLength);
if (result != TdsOperationStatus.Done)
{
return result;
Expand Down Expand Up @@ -3623,6 +3632,10 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj,
{
throw SQL.ParsingError();
}
if (length > TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, length);
}
uint seqNum;
TdsOperationStatus result = stateObj.TryReadUInt32(out seqNum);
if (result != TdsOperationStatus.Done)
Expand Down Expand Up @@ -3672,6 +3685,10 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj,
return result;
}
}
if (stateLen < 0 || stateLen > TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, stateLen);
}
byte[] buffer = null;
lock (sdata._delta)
{
Expand Down Expand Up @@ -3888,6 +3905,10 @@ private TdsOperationStatus TryProcessFedAuthInfo(TdsParserStateObject stateObj,
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream length too short for CountOfInfoIDs.");
throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForCountOfInfoIds, tokenLen);
}
if (tokenLen > TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, tokenLen);
}

// read how many FedAuthInfo options there are
uint optionsCount;
Expand Down Expand Up @@ -4361,14 +4382,20 @@ internal TdsOperationStatus TryProcessReturnValue(int length,
}

// always read as sql types
Debug.Assert(valLen < (ulong)(int.MaxValue), "ProcessReturnValue received data size > 2Gb");

int intlen = valLen > (ulong)(int.MaxValue) ? int.MaxValue : (int)valLen;
int intlen;

if (rec.metaType.IsPlp)
{
intlen = int.MaxValue; // If plp data, read it all
}
else if (valLen > (ulong)int.MaxValue)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, unchecked((int)valLen));
}
else
{
intlen = (int)valLen;
}

if (rec.type == SqlDbTypeExtensions.Vector)
{
Expand Down Expand Up @@ -6548,7 +6575,14 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value,

private TdsOperationStatus TryReadSqlDateTime(SqlBuffer value, byte tdsType, int length, byte scale, TdsParserStateObject stateObj)
{
Span<byte> datetimeBuffer = ((uint)length <= 16) ? stackalloc byte[16] : new byte[length];
// DateTimeOffset is the largest datetime type at 10 bytes (5 time + 3 date + 2 offset).
// Reject anything larger to prevent heap allocation from spoofed metadata.
if (length < 0 || length > TdsEnums.MaxDateTimeLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, length);
}

Span<byte> datetimeBuffer = stackalloc byte[TdsEnums.MaxDateTimeLength];
TdsOperationStatus result;

result = stateObj.TryReadByteArray(datetimeBuffer, length);
Expand Down Expand Up @@ -6801,7 +6835,10 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp
case TdsEnums.SQLVECTOR:
{
// Note: Better not come here with plp data!!
Debug.Assert(length <= TdsEnums.MAXSIZE);
if (length < 0 || length > TdsEnums.MAXSIZE)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, length);
}
byte[] b = new byte[length];
result = stateObj.TryReadByteArray(b, length);
if (result != TdsOperationStatus.Done)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2836,6 +2836,12 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
{
len = bLen;
}

if (len < 0 || len > data.Length - i)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, len);
}

byte[] stateData = new byte[len];
Buffer.BlockCopy(data, i, stateData, 0, len);
i += len;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2965,6 +2965,10 @@ private TdsOperationStatus TryProcessEnvChange(int tokenLength, TdsParserStateOb
// new value has 4 byte length
return result;
}
if (env._newLength < 0 || env._newLength > TdsEnums.MaxPromoteTransactionLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, env._newLength);
}
// read new value with 4 byte length
env._newBinValue = new byte[env._newLength];
result = stateObj.TryReadByteArray(env._newBinValue, env._newLength);
Expand Down Expand Up @@ -3359,10 +3363,15 @@ private TdsOperationStatus TryProcessFeatureExtAck(TdsParserStateObject stateObj
{
return result;
}
byte[] data = new byte[dataLen];
if (dataLen > 0)
if (dataLen > (uint)TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, dataLen);
}
int dataLength = (int)dataLen;
byte[] data = new byte[dataLength];
if (dataLength > 0)
{
result = stateObj.TryReadByteArray(data, checked((int)dataLen));
result = stateObj.TryReadByteArray(data, dataLength);
if (result != TdsOperationStatus.Done)
{
return result;
Expand Down Expand Up @@ -3682,6 +3691,10 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj,
{
throw SQL.ParsingErrorLength(ParsingErrorState.SessionStateLengthTooShort, length);
}
if (length > TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, length);
}
uint seqNum;
TdsOperationStatus result = stateObj.TryReadUInt32(out seqNum);
if (result != TdsOperationStatus.Done)
Expand Down Expand Up @@ -3731,6 +3744,10 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj,
return result;
}
}
if (stateLen < 0 || stateLen > TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, stateLen);
}
byte[] buffer = null;
lock (sdata._delta)
{
Expand Down Expand Up @@ -3947,6 +3964,10 @@ private TdsOperationStatus TryProcessFedAuthInfo(TdsParserStateObject stateObj,
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream length too short for CountOfInfoIDs.");
throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForCountOfInfoIds, tokenLen);
}
if (tokenLen > TdsEnums.MaxTokenDataLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, tokenLen);
}

// read how many FedAuthInfo options there are
uint optionsCount;
Expand Down Expand Up @@ -4421,14 +4442,20 @@ internal TdsOperationStatus TryProcessReturnValue(int length,
}

// always read as sql types
Debug.Assert(valLen < (ulong)(int.MaxValue), "ProcessReturnValue received data size > 2Gb");

int intlen = valLen > (ulong)(int.MaxValue) ? int.MaxValue : (int)valLen;
int intlen;

if (rec.metaType.IsPlp)
{
intlen = int.MaxValue; // If plp data, read it all
}
else if (valLen > (ulong)int.MaxValue)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, unchecked((int)valLen));
}
else
{
intlen = (int)valLen;
}

if (rec.type == SqlDbTypeExtensions.Vector)
{
Expand Down Expand Up @@ -6736,7 +6763,14 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value,

private TdsOperationStatus TryReadSqlDateTime(SqlBuffer value, byte tdsType, int length, byte scale, TdsParserStateObject stateObj)
{
Span<byte> datetimeBuffer = ((uint)length <= 16) ? stackalloc byte[16] : new byte[length];
// DateTimeOffset is the largest datetime type at 10 bytes (5 time + 3 date + 2 offset).
// Reject anything larger to prevent heap allocation from spoofed metadata.
if (length < 0 || length > TdsEnums.MaxDateTimeLength)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, length);
}

Span<byte> datetimeBuffer = stackalloc byte[TdsEnums.MaxDateTimeLength];

TdsOperationStatus result = stateObj.TryReadByteArray(datetimeBuffer, length);
if (result != TdsOperationStatus.Done)
Expand Down Expand Up @@ -6993,7 +7027,10 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp
case TdsEnums.SQLVECTOR:
{
// Note: Better not come here with plp data!!
Debug.Assert(length <= TdsEnums.MAXSIZE);
if (length < 0 || length > TdsEnums.MAXSIZE)
{
throw SQL.ParsingErrorLength(ParsingErrorState.CorruptedTdsStream, length);
}
byte[] b = new byte[length];
result = stateObj.TryReadByteArray(b, length);
if (result != TdsOperationStatus.Done)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,10 @@ internal static Exception ParsingErrorLength(ParsingErrorState state, int length
{
return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_ParsingErrorLength, ((int)state).ToString(CultureInfo.InvariantCulture), length));
}
internal static Exception ParsingErrorLength(ParsingErrorState state, uint length)
{
return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_ParsingErrorLength, ((int)state).ToString(CultureInfo.InvariantCulture), length));
}
internal static Exception ParsingErrorStatus(ParsingErrorState state, int status)
{
return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_ParsingErrorStatus, ((int)state).ToString(CultureInfo.InvariantCulture), status));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ internal static class TdsEnums
public const int MAX_PACKET_SIZE = 32768;
public const int MAX_SERVER_USER_NAME = 256; // obtained from luxor

// Maximum allowed data length for token payloads (feature ext ack,
// session state, fedauth info). Prevents a malicious server from causing
// unbounded memory allocation via spoofed token length fields.
internal const int MaxTokenDataLength = 1 << 20; // 1 MB

// Maximum allowed data length for a DTC promote transaction propagation token.
internal const int MaxPromoteTransactionLength = 1 << 16; // 64 KB

// Maximum valid wire size for datetime types (DateTimeOffset = 5 time + 3 date + 2 offset).
internal const int MaxDateTimeLength = 10;

// Severity 0 - 10 indicates informational (non-error) messages
// Severity 11 - 16 indicates errors that can be corrected by user (syntax errors, etc...)
// Severity 17 - 19 indicates failure due to insufficient resources in the server
Expand Down
Loading
Loading