diff --git a/NuGet.config b/NuGet.config
index d474e8b0488..1d25316eeab 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -5,7 +5,7 @@
-
+
diff --git a/eng/Version.Details.props b/eng/Version.Details.props
index 56cfdd14afe..3216095b0db 100644
--- a/eng/Version.Details.props
+++ b/eng/Version.Details.props
@@ -8,14 +8,14 @@ This file should be imported by eng/Versions.props
15.9.20
15.9.20
- 10.0.0-beta.26257.101
- 10.0.0-beta.26257.101
- 10.0.0-beta.26257.101
- 10.0.0-beta.26257.101
- 10.0.9-servicing.26257.101
+ 10.0.0-beta.26272.117
+ 10.0.0-beta.26272.117
+ 10.0.0-beta.26272.117
+ 10.0.0-beta.26272.117
+ 10.0.9-servicing.26272.117
10.0.9
- 10.0.9-servicing.26257.101
- 10.0.9-servicing.26257.101
+ 10.0.9-servicing.26272.117
+ 10.0.9-servicing.26272.117
8.0.0-beta.23409.2
8.0.0-beta.23409.2
10.0.9
@@ -25,7 +25,7 @@ This file should be imported by eng/Versions.props
10.0.9
10.0.9
10.0.9
- 10.0.9-servicing.26257.101
+ 10.0.9-servicing.26272.117
10.0.9
10.0.9
10.0.9
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index bd3020f9d56..0b4fa3d505a 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,26 +1,26 @@
-
+
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://dev.azure.com/dnceng/internal/_git/dotnet-wpf-int
@@ -28,51 +28,51 @@
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
https://github.com/dotnet/dotnet
@@ -84,25 +84,25 @@
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
-
+
https://github.com/dotnet/dotnet
- dc6e7082d768b79e69b16e8fd146a509dfa6130d
+ d4d18f3a6b721b12a0589b26db5b9226f18447a1
diff --git a/eng/common/core-templates/steps/source-index-stage1-publish.yml b/eng/common/core-templates/steps/source-index-stage1-publish.yml
index e9a694afa58..6e7666b4dcf 100644
--- a/eng/common/core-templates/steps/source-index-stage1-publish.yml
+++ b/eng/common/core-templates/steps/source-index-stage1-publish.yml
@@ -14,8 +14,8 @@ steps:
workingDirectory: $(Agent.TempDirectory)
- script: |
- $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version ${{parameters.sourceIndexProcessBinlogPackageVersion}} --add-source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools
- $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version ${{parameters.sourceIndexUploadPackageVersion}} --add-source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version ${{parameters.sourceIndexProcessBinlogPackageVersion}} --source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version ${{parameters.sourceIndexUploadPackageVersion}} --source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools
displayName: "Source Index: Download netsourceindex Tools"
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
workingDirectory: $(Agent.TempDirectory)
diff --git a/eng/common/darc-init.ps1 b/eng/common/darc-init.ps1
index e3374310563..a5be41db690 100644
--- a/eng/common/darc-init.ps1
+++ b/eng/common/darc-init.ps1
@@ -29,11 +29,11 @@ function InstallDarcCli ($darcVersion, $toolpath) {
Write-Host "Installing Darc CLI version $darcVersion..."
Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
if (-not $toolpath) {
- Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity -g"
- & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g
+ Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --source '$arcadeServicesSource' -v $verbosity -g"
+ & "$dotnet" tool install $darcCliPackageName --version $darcVersion --source "$arcadeServicesSource" -v $verbosity -g
}else {
- Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity --tool-path '$toolpath'"
- & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath"
+ Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --source '$arcadeServicesSource' -v $verbosity --tool-path '$toolpath'"
+ & "$dotnet" tool install $darcCliPackageName --version $darcVersion --source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath"
}
}
diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh
index e889f439b8d..e6ba4ee28c1 100755
--- a/eng/common/darc-init.sh
+++ b/eng/common/darc-init.sh
@@ -73,9 +73,9 @@ function InstallDarcCli {
echo "Installing Darc CLI version $darcVersion..."
echo "You may need to restart your command shell if this is the first dotnet tool you have installed."
if [ -z "$toolpath" ]; then
- echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g)
+ echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --source "$arcadeServicesSource" -v $verbosity -g)
else
- echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath")
+ echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath")
fi
}
diff --git a/eng/common/post-build/redact-logs.ps1 b/eng/common/post-build/redact-logs.ps1
index 472d5bb562c..c1e4104b79a 100644
--- a/eng/common/post-build/redact-logs.ps1
+++ b/eng/common/post-build/redact-logs.ps1
@@ -48,8 +48,8 @@ try {
Write-Host "Installing Binlog redactor CLI..."
Write-Host "'$dotnet' new tool-manifest"
& "$dotnet" new tool-manifest
- Write-Host "'$dotnet' tool install $packageName --local --add-source '$PackageFeed' -v $verbosity --version $BinlogToolVersion"
- & "$dotnet" tool install $packageName --local --add-source "$PackageFeed" -v $verbosity --version $BinlogToolVersion
+ Write-Host "'$dotnet' tool install $packageName --local --source '$PackageFeed' -v $verbosity --version $BinlogToolVersion"
+ & "$dotnet" tool install $packageName --local --source "$PackageFeed" -v $verbosity --version $BinlogToolVersion
if (Test-Path $TokensFilePath) {
Write-Host "Adding additional sensitive data for redaction from file: " $TokensFilePath
diff --git a/eng/common/templates/steps/vmr-sync.yml b/eng/common/templates/steps/vmr-sync.yml
index eb619c50268..cdc6a28ff1f 100644
--- a/eng/common/templates/steps/vmr-sync.yml
+++ b/eng/common/templates/steps/vmr-sync.yml
@@ -45,11 +45,11 @@ steps:
workingDirectory: ${{ parameters.vmrPath }}
- script: |
- ./eng/common/vmr-sync.sh \
- --vmr ${{ parameters.vmrPath }} \
- --tmp $(Agent.TempDirectory) \
- --azdev-pat '$(dn-bot-all-orgs-code-r)' \
- --ci \
+ ./eng/common/vmr-sync.sh \
+ --vmr ${{ parameters.vmrPath }} \
+ --tmp $(Agent.TempDirectory) \
+ --azdev-pat '$(AzdoToken)' \
+ --ci \
--debug
if [ "$?" -ne 0 ]; then
@@ -67,11 +67,11 @@ steps:
condition: eq(variables['Agent.OS'], 'Windows_NT')
- powershell: |
- ./eng/common/vmr-sync.ps1 `
- -vmr ${{ parameters.vmrPath }} `
- -tmp $(Agent.TempDirectory) `
- -azdevPat '$(dn-bot-all-orgs-code-r)' `
- -ci `
+ ./eng/common/vmr-sync.ps1 `
+ -vmr ${{ parameters.vmrPath }} `
+ -tmp $(Agent.TempDirectory) `
+ -azdevPat '$(AzdoToken)' `
+ -ci `
-debugOutput
if ($LASTEXITCODE -ne 0) {
diff --git a/global.json b/global.json
index 231c3ea53ab..f225568d19f 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "10.0.107",
+ "version": "10.0.108",
"allowPrerelease": true,
"rollForward": "latestFeature",
"paths": [
@@ -10,7 +10,7 @@
"errorMessage": "The required .NET SDK wasn't found. Please run ./eng/common/dotnet.cmd/sh to install it."
},
"tools": {
- "dotnet": "10.0.107",
+ "dotnet": "10.0.108",
"runtimes": {
"dotnet/x64": [
"$(MicrosoftNETCorePlatformsVersion)"
@@ -24,8 +24,8 @@
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.26257.101",
- "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.26257.101",
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.26272.117",
+ "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.26272.117",
"Microsoft.Build.NoTargets": "3.7.56"
},
"native-tools": {
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp
index 00ec1e7b5a4..a6bce80485d 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp
@@ -22,6 +22,8 @@
#include "ttferror.h" /* for error codes */
#include "ttmem.h"
#include "automap.h"
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
int16 MortAutoMap(TTFACC_FILEBUFFERINFO * pInputBufferInfo, /* ttfacc info */
@@ -41,6 +43,11 @@ int16 errCode = NO_ERROR;
ulOffset = TTTableOffset( pInputBufferInfo, MORT_TAG );
ulLength = TTTableLength( pInputBufferInfo, MORT_TAG );
ulLastOffset = ulOffset+ulLength;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulLastOffset < ulOffset) /* overflow check */
+ return ERR_GENERIC;
+ }
if (ulOffset == DIRECTORY_ERROR || ulLength == 0) /* nothing to map, we're done */
return NO_ERROR;
@@ -68,7 +75,7 @@ int16 errCode = NO_ERROR;
/* Static function to syncronize the Keep Glyph List with the Coverage list */
/* (add in values if necessary) */
/* ------------------------------------------------------------------- */
-static int16 UpdateKeepWithCoverage(TTFACC_FILEBUFFERINFO * pInputBufferInfo, uint8 * pabKeepGlyphs, uint16 usnGlyphs, uint16 fKeepFlag, uint32 ulBaseOffset, uint32 ulCoverageOffset, uint16 *pArray, uint16 usLookupType, uint16 usSubstFormat)
+static int16 UpdateKeepWithCoverage(TTFACC_FILEBUFFERINFO * pInputBufferInfo, uint8 * pabKeepGlyphs, uint16 usnGlyphs, uint16 fKeepFlag, uint32 ulBaseOffset, uint32 ulCoverageOffset, uint16 *pArray, uint16 usArrayCount, uint16 usLookupType, uint16 usSubstFormat)
{
uint32 ulOffset;
uint16 usCoverageFormat;
@@ -82,6 +89,7 @@ GSUBRANGERECORD *pRangeRecordArray = NULL;
uint16 i, j, k, l;
uint16 usBytesRead;
uint32 ulBytesRead;
+uint32 ulAllocSize;
int16 errCode = NO_ERROR;
if ((ulCoverageOffset == 0) || (pArray == NULL))
@@ -97,7 +105,16 @@ int16 errCode = NO_ERROR;
return errCode;
ulOffset += usBytesRead;
usCount = Coverage1.GlyphCount;
- pGlyphIDArray = (uint16 *)Mem_Alloc(usCount * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)usCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ pGlyphIDArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pGlyphIDArray = (uint16 *)Mem_Alloc(usCount * sizeof(uint16));
+ }
if (pGlyphIDArray == NULL)
return ERR_MEM;
if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pGlyphIDArray, WORD_CONTROL, ulOffset, &ulBytesRead, usCount, sizeof(uint16)) )!= NO_ERROR)
@@ -111,7 +128,16 @@ int16 errCode = NO_ERROR;
return errCode;
ulOffset += usBytesRead;
usCount = Coverage2.CoverageRangeCount;
- pRangeRecordArray = (GSUBRANGERECORD *)Mem_Alloc(usCount * SIZEOF_GSUBRANGERECORD);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)usCount, (uint32)SIZEOF_GSUBRANGERECORD, &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ pRangeRecordArray = (GSUBRANGERECORD *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pRangeRecordArray = (GSUBRANGERECORD *)Mem_Alloc(usCount * SIZEOF_GSUBRANGERECORD);
+ }
if (pRangeRecordArray == NULL)
return ERR_MEM;
if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *) pRangeRecordArray, GSUBRANGERECORD_CONTROL, ulOffset, &ulBytesRead, usCount, SIZEOF_GSUBRANGERECORD) )!= NO_ERROR)
@@ -154,11 +180,28 @@ int16 errCode = NO_ERROR;
case GSUBSingleLookupType:
if (usSubstFormat == 1)
{
- if ((usGlyphID + (int16) *pArray) < usnGlyphs && pabKeepGlyphs[usGlyphID + (int16) *pArray] == 0)
- pabKeepGlyphs[usGlyphID + (int16) *pArray] = (uint8)(fKeepFlag + 1);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ int32 sTargetGlyphID = (int32)usGlyphID + (int16) *pArray;
+ if (sTargetGlyphID >= 0 && sTargetGlyphID < usnGlyphs && pabKeepGlyphs[sTargetGlyphID] == 0)
+ pabKeepGlyphs[sTargetGlyphID] = (uint8)(fKeepFlag + 1);
+ }
+ else
+ {
+ if ((usGlyphID + (int16) *pArray) < usnGlyphs && pabKeepGlyphs[usGlyphID + (int16) *pArray] == 0)
+ pabKeepGlyphs[usGlyphID + (int16) *pArray] = (uint8)(fKeepFlag + 1);
+ }
}
else
{
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usGlyphCount >= usArrayCount)
+ {
+ errCode = ERR_INVALID_GSUB;
+ break;
+ }
+ }
if (pArray[usGlyphCount] < usnGlyphs && pabKeepGlyphs[pArray[usGlyphCount]] == 0)
pabKeepGlyphs[pArray[usGlyphCount]] = (uint8)(fKeepFlag + 1);
}
@@ -168,13 +211,33 @@ int16 errCode = NO_ERROR;
uint16 usSequenceGlyphCount;
uint16 *pausGlyphID = NULL;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usGlyphCount >= usArrayCount)
+ {
+ errCode = ERR_INVALID_GSUB;
+ break;
+ }
+ }
if (pArray[usGlyphCount] == 0)
break;
ulOffset = ulBaseOffset + pArray[usGlyphCount];
if ((errCode = ReadWord( pInputBufferInfo, &usSequenceGlyphCount, ulOffset ) )!= NO_ERROR)
break;
ulOffset += sizeof(uint16);
- pausGlyphID = (uint16 *)Mem_Alloc(usSequenceGlyphCount * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)usSequenceGlyphCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pausGlyphID = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pausGlyphID = (uint16 *)Mem_Alloc(usSequenceGlyphCount * sizeof(uint16));
+ }
if (pausGlyphID == NULL)
{
errCode = ERR_MEM;
@@ -197,13 +260,33 @@ int16 errCode = NO_ERROR;
uint16 usAlternateGlyphCount;
uint16 *pausGlyphID = NULL;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usGlyphCount >= usArrayCount)
+ {
+ errCode = ERR_INVALID_GSUB;
+ break;
+ }
+ }
if (pArray[usGlyphCount] == 0)
break;
ulOffset = ulBaseOffset + pArray[usGlyphCount];
if ((errCode = ReadWord( pInputBufferInfo, &usAlternateGlyphCount, ulOffset ) )!= NO_ERROR)
break;
ulOffset += sizeof(uint16);
- pausGlyphID = (uint16 *)Mem_Alloc(usAlternateGlyphCount * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)usAlternateGlyphCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pausGlyphID = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pausGlyphID = (uint16 *)Mem_Alloc(usAlternateGlyphCount * sizeof(uint16));
+ }
if (pausGlyphID == NULL)
{
errCode = ERR_MEM;
@@ -229,13 +312,33 @@ int16 errCode = NO_ERROR;
uint16 *pausLigatureOffsetArray = NULL;
GSUBLIGATURE GSUBLigature;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usGlyphCount >= usArrayCount)
+ {
+ errCode = ERR_INVALID_GSUB;
+ break;
+ }
+ }
if (pArray[usGlyphCount] == 0)
break;
ulOffset = ulBaseOffset + pArray[usGlyphCount];
if ((errCode = ReadWord( pInputBufferInfo, &usLigatureCount, ulOffset ) )!= NO_ERROR)
break;
ulOffset += sizeof(uint16);
- pausLigatureOffsetArray = (uint16 *)Mem_Alloc(usLigatureCount * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)usLigatureCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pausLigatureOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pausLigatureOffsetArray = (uint16 *)Mem_Alloc(usLigatureCount * sizeof(uint16));
+ }
if (pausLigatureOffsetArray == NULL)
{
errCode = ERR_MEM;
@@ -247,7 +350,14 @@ int16 errCode = NO_ERROR;
{
if (pausLigatureOffsetArray[l] == 0)
continue;
- ulOffset = ulBaseOffset + (pArray)[usGlyphCount] + pausLigatureOffsetArray[l];
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ ulOffset = ulBaseOffset + (uint32)(pArray)[usGlyphCount] + (uint32)pausLigatureOffsetArray[l];
+ }
+ else
+ {
+ ulOffset = ulBaseOffset + (pArray)[usGlyphCount] + pausLigatureOffsetArray[l];
+ }
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBLigature, SIZEOF_GSUBLIGATURE, GSUBLIGATURE_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
{
Mem_Free (pausLigatureOffsetArray);
@@ -260,7 +370,30 @@ int16 errCode = NO_ERROR;
usLigatureGlyphID = GSUBLigature.GlyphID;
if (usLigatureGlyphID >= usnGlyphs || pabKeepGlyphs[usLigatureGlyphID] != 0)
continue; /* already in list, go to next ligature */
- pausCompGlyphID = (uint16 *)Mem_Alloc((usLigatureCompCount - 1) * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usLigatureCompCount < 2) /* need at least 2 components; 0 or 1 means no comp array */
+ {
+ if (usLigatureCompCount == 1 && pabKeepGlyphs[usLigatureGlyphID] == 0)
+ pabKeepGlyphs[usLigatureGlyphID] = (uint8)(fKeepFlag+1);
+ continue;
+ }
+ }
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)(usLigatureCompCount - 1), (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ {
+ Mem_Free (pausLigatureOffsetArray);
+ Mem_Free(pGlyphIDArray);
+ Mem_Free(pRangeRecordArray);
+ return ERR_MEM;
+ }
+ pausCompGlyphID = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pausCompGlyphID = (uint16 *)Mem_Alloc((usLigatureCompCount - 1) * sizeof(uint16));
+ }
if (pausCompGlyphID == NULL)
{
Mem_Free (pausLigatureOffsetArray);
@@ -385,6 +518,7 @@ uint32 ulCurrentOffset;
uint32 ulLangSysOffset;
uint16 usMaxLookupCount;
uint32 ulOffset;
+uint32 ulAllocSize;
uint16 i, j, k;
uint16 usBytesRead;
uint32 ulBytesRead;
@@ -420,7 +554,20 @@ int16 errCode = NO_ERROR;
uint16 *SubstTableOffsetArray = NULL;
ulOffset = ulHeaderOffset + GSUBHeader.LookupListOffset;
- pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(SIZEOF_GSUBLOOKUPLIST + usMaxLookupCount * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)usMaxLookupCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK ||
+ UIntAdd32(ulAllocSize, (uint32)SIZEOF_GSUBLOOKUPLIST, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(SIZEOF_GSUBLOOKUPLIST + usMaxLookupCount * sizeof(uint16));
+ }
if (pGSUBLookupList == NULL)
{
errCode = ERR_MEM;
@@ -449,7 +596,19 @@ int16 errCode = NO_ERROR;
if (GSUBLookup.LookupType == GSUBContextLookupType) /* not looking for context lookups */
continue;
usSubTableCount = GSUBLookup.SubTableCount;
- SubstTableOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usSubTableCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)sizeof(uint16), (uint32)usSubTableCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ SubstTableOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ SubstTableOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usSubTableCount);
+ }
if (SubstTableOffsetArray == NULL)
{
errCode = ERR_MEM;
@@ -481,7 +640,7 @@ int16 errCode = NO_ERROR;
GSUBSINGLESUBSTFORMAT1 GSUBSubstTable;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBSINGLESUBSTFORMAT1, GSUBSINGLESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )== NO_ERROR)
- errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , (uint16 *) &(GSUBSubstTable.DeltaGlyphID), GSUBLookup.LookupType, Format);
+ errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , (uint16 *) &(GSUBSubstTable.DeltaGlyphID), 1, GSUBLookup.LookupType, Format);
break;
}
case 2:
@@ -493,14 +652,26 @@ int16 errCode = NO_ERROR;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBSINGLESUBSTFORMAT2, GSUBSINGLESUBSTFORMAT2_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
break;
usGlyphCount = GSUBSubstTable.GlyphCount;
- pGlyphIDArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usGlyphCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)sizeof(uint16), (uint32)usGlyphCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pGlyphIDArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pGlyphIDArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usGlyphCount);
+ }
if (pGlyphIDArray == NULL)
{
errCode = ERR_MEM;
break;
}
if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pGlyphIDArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usGlyphCount, sizeof(uint16)) )== NO_ERROR)
- errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pGlyphIDArray, GSUBLookup.LookupType, Format);
+ errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pGlyphIDArray, usGlyphCount, GSUBLookup.LookupType, Format);
Mem_Free(pGlyphIDArray);
break;
}
@@ -522,14 +693,26 @@ int16 errCode = NO_ERROR;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBMULTIPLESUBSTFORMAT1, GSUBMULTIPLESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
break;
usCount = GSUBSubstTable.SequenceCount;
- pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)sizeof(uint16), (uint32)usCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
+ }
if (pOffsetArray == NULL)
{
errCode = ERR_MEM;
break;
}
if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR)
- errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format);
+ errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, usCount, GSUBLookup.LookupType, Format);
Mem_Free(pOffsetArray);
break;
}
@@ -544,14 +727,26 @@ int16 errCode = NO_ERROR;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBALTERNATESUBSTFORMAT1, GSUBALTERNATESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
break;
usCount = GSUBSubstTable.AlternateSetCount;
- pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)sizeof(uint16), (uint32)usCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
+ }
if (pOffsetArray == NULL)
{
errCode = ERR_MEM;
break;
}
if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR)
- errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format);
+ errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, usCount, GSUBLookup.LookupType, Format);
Mem_Free(pOffsetArray);
break;
}
@@ -566,14 +761,26 @@ int16 errCode = NO_ERROR;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBLIGATURESUBSTFORMAT1, GSUBLIGATURESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
break;
usCount = GSUBSubstTable.LigatureSetCount;
- pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)sizeof(uint16), (uint32)usCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ pOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
+ }
if (pOffsetArray == NULL)
{
errCode = ERR_MEM;
break;
}
if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR)
- errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format);
+ errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, usCount, GSUBLookup.LookupType, Format);
Mem_Free(pOffsetArray);
break;
}
@@ -606,7 +813,19 @@ int16 errCode = NO_ERROR;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&JSTFHeader, SIZEOF_JSTFHEADER, JSTFHEADER_CONTROL, ulHeaderOffset, &usBytesRead ) )!= NO_ERROR)
break;
- ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(SIZEOF_JSTFSCRIPTRECORD * JSTFHeader.ScriptCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)SIZEOF_JSTFSCRIPTRECORD, (uint32)JSTFHeader.ScriptCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(SIZEOF_JSTFSCRIPTRECORD * JSTFHeader.ScriptCount);
+ }
if (ScriptRecordArray == NULL)
{
errCode = ERR_MEM;
@@ -631,7 +850,19 @@ int16 errCode = NO_ERROR;
if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&JSTFExtenderGlyph, SIZEOF_JSTFEXTENDERGLYPH, JSTFEXTENDERGLYPH_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
break;
- GlyphIDArray = (uint16 *)Mem_Alloc((sizeof(uint16) * JSTFExtenderGlyph.ExtenderGlyphCount));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ULongMult32((uint32)sizeof(uint16), (uint32)JSTFExtenderGlyph.ExtenderGlyphCount, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ GlyphIDArray = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ GlyphIDArray = (uint16 *)Mem_Alloc((sizeof(uint16) * JSTFExtenderGlyph.ExtenderGlyphCount));
+ }
if (GlyphIDArray == NULL)
{
errCode = ERR_MEM;
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h
index 7fe53745b72..47382236a54 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h
@@ -138,4 +138,18 @@ ULongSub(
return hr;
}
+
+//
+// Convenience wrappers for the codebase's uint32 type (unsigned long).
+// These forward to the UINT/ULONG versions above, bridging the type mismatch.
+//
+static __inline HRESULT UIntAdd32(uint32 a, uint32 b, uint32 *pResult)
+{
+ return UIntAdd((UINT)a, (UINT)b, (UINT *)pResult);
+}
+static __inline HRESULT ULongMult32(uint32 a, uint32 b, uint32 *pResult)
+{
+ return ULongMult((ULONG)a, (ULONG)b, (ULONG *)pResult);
+}
+
#endif //__INTSAFE_PRIVATE_COPY_H
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp
index 6ea0dde0f34..d25c606011c 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp
@@ -148,6 +148,8 @@ Thanks,
#include "ttferror.h" /* for error codes */
#include "ttfdelta.h"
#include "sfntoff.h"
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
#define WIN_ANSI_MIDDLEDOT 0xB7
#define WIN_ANSI_BULLET 0x2219
@@ -176,7 +178,18 @@ USHORT usHighByte;
{
if (usFirstChar >= 0xf000)
{
- if (*ppulKeepSymbolCodeList = (CHAR_ID *)Mem_Alloc(usCharListCount * sizeof(CHAR_ID)))
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usCharListCount, (uint32)sizeof(CHAR_ID), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ *ppulKeepSymbolCodeList = (CHAR_ID *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ *ppulKeepSymbolCodeList = (CHAR_ID *)Mem_Alloc(usCharListCount * sizeof(CHAR_ID));
+ }
+ if (*ppulKeepSymbolCodeList)
{
/* In user range -> this is a symbol font so go ahead offseting it */
usHighByte = (unsigned short)(usFirstChar & 0xff00);
@@ -220,7 +233,18 @@ int16 EnsureNonEmptyGlyfTable(
uint32 * aulLoca;
/* allocate memory for and read loca table */
- aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 ));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulLocaCount = (uint32)usGlyphCount + 1;
+ uint32 ulAllocSize;
+ if (ULongMult32(ulLocaCount, (uint32)sizeof( uint32 ), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ aulLoca = (uint32 *)Mem_Alloc( ulAllocSize );
+ }
+ else
+ {
+ aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof(uint32) );
+ }
if ( aulLoca == NULL )
return ERR_MEM;
@@ -328,8 +352,22 @@ CMAP_SUBHEADER_GEN CmapSubHeader;
if ((ulGlyfOffset = TTTableOffset( pInputBufferInfo, GLYF_TAG )) == DIRECTORY_ERROR)
return (ERR_MISSING_GLYF);
- usnMaxComponents = Maxp.maxComponentElements * Maxp.maxComponentDepth; /* maximum total possible */
- pausComponents = (uint16 *)Mem_Alloc(usnMaxComponents * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulMaxComp, ulAllocSize;
+ if (ULongMult32((uint32)Maxp.maxComponentElements, (uint32)Maxp.maxComponentDepth, &ulMaxComp) != S_OK ||
+ ULongMult32(ulMaxComp, (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ return(ERR_MEM);
+ if (ulMaxComp > (uint32)USHRT_MAX)
+ return(ERR_INVALID_MAXP);
+ usnMaxComponents = (uint16)ulMaxComp;
+ pausComponents = (uint16 *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ usnMaxComponents = Maxp.maxComponentElements * Maxp.maxComponentDepth;
+ pausComponents = (uint16 *)Mem_Alloc(usnMaxComponents * sizeof(uint16));
+ }
if (pausComponents == NULL)
return(ERR_MEM);
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp
index c0922b8dc52..b79ac87097d 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp
@@ -14,6 +14,8 @@
#include /* for qsort */
#include "typedefs.h"
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
#include "ttff.h"
#include "ttfacc.h"
#include "ttfcntrl.h"
@@ -46,7 +48,17 @@ struct cmapoffsetrecordkeeper /* housekeeping structure */
PRIVATE int16 InitCmapOffsetArray(PCMAPOFFSETRECORDKEEPER pKeeper,
uint16 usRecordCount)
{
- pKeeper->pCmapOffsetArray = (CmapOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pCmapOffsetArray)));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usRecordCount, (uint32)sizeof(*(pKeeper->pCmapOffsetArray)), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ pKeeper->pCmapOffsetArray = (CmapOffsetRecord *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pKeeper->pCmapOffsetArray = (CmapOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pCmapOffsetArray)));
+ }
if (pKeeper->pCmapOffsetArray == NULL)
return ERR_MEM;
pKeeper->usCmapOffsetArrayLen = usRecordCount;
@@ -152,7 +164,17 @@ uint16 i,j;
uint16 usBytesRead;
uint16 usPadBytes;
- pIndexArray = (IndexOffset *) Mem_Alloc(usSubTableCount * sizeof(*pIndexArray));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usSubTableCount, (uint32)sizeof(*pIndexArray), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ pIndexArray = (IndexOffset *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pIndexArray = (IndexOffset *) Mem_Alloc(usSubTableCount * sizeof(*pIndexArray));
+ }
if (pIndexArray == NULL)
return ERR_MEM;
@@ -384,7 +406,17 @@ uint16 usBytesRead;
return ERR_INVALID_CMAP; /* huh?*/
usSubTableCount = GetCmapSubtableCount(pOutputBufferInfo, ulCmapOffset);
- pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(SIZEOF_CMAP_TABLELOC * usSubTableCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)SIZEOF_CMAP_TABLELOC, (uint32)usSubTableCount, &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(SIZEOF_CMAP_TABLELOC * usSubTableCount);
+ }
if (pCmapTableLoc == NULL)
return ERR_MEM;
ulCmapSubTableDirOffset = ulCmapOffset + GetGenericSize( CMAP_HEADER_CONTROL );
@@ -434,8 +466,24 @@ uint16 usBytesRead;
if (errCode != NO_ERROR)
break;
- NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( (usnCharGlyphMapListCount+1) * SIZEOF_FORMAT4_SEGMENTS ); /* add one for the extra dummy segment */
- NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( usnCharGlyphMapListCount * sizeof( *NewFormat4GlyphIdArray ) );
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulSegAllocSize, ulGlyphAllocSize;
+ uint32 ulSegCount32 = (uint32)usnCharGlyphMapListCount + 1; /* add one for extra dummy segment */
+ if (ULongMult32(ulSegCount32, (uint32)SIZEOF_FORMAT4_SEGMENTS, &ulSegAllocSize) != S_OK ||
+ ULongMult32((uint32)usnCharGlyphMapListCount, (uint32)sizeof( *NewFormat4GlyphIdArray ), &ulGlyphAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( ulSegAllocSize );
+ NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( ulGlyphAllocSize );
+ }
+ else
+ {
+ NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( (usnCharGlyphMapListCount + 1) * SIZEOF_FORMAT4_SEGMENTS ); /* add one for the extra dummy segment */
+ NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( usnCharGlyphMapListCount * sizeof( *NewFormat4GlyphIdArray ) );
+ }
if ( NewFormat4Segments == NULL || NewFormat4GlyphIdArray == NULL )
{
@@ -453,7 +501,7 @@ uint16 usBytesRead;
if (CmapFormat4.length <= CmapSubHeader.length) /* if the new length is smaller than the old, we can write it in the old place */
{
- if (pCmapTableLoc[i].platformID == MS_PLATFORMID) /* only applies to this platform */
+ if (pCmapTableLoc[i].platformID == MS_PLATFORMID && (!TTF_SAFE_CHECKS_ENABLED() || usnCharGlyphMapListCount > 0)) /* only applies to this platform */
{
*pOS2MinChr = pCharGlyphMapList[0].usCharCode;
*pOS2MaxChr = pCharGlyphMapList[usnCharGlyphMapListCount-1].usCharCode;
@@ -482,7 +530,20 @@ uint16 usBytesRead;
if (errCode != NO_ERROR)
break;
- NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc( (ulnCharGlyphMapListCount) * SIZEOF_FORMAT12_GROUPS );
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)ulnCharGlyphMapListCount, (uint32)SIZEOF_FORMAT12_GROUPS, &ulAllocSize) != S_OK)
+ {
+ errCode = ERR_MEM;
+ break;
+ }
+ NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc(ulnCharGlyphMapListCount * SIZEOF_FORMAT12_GROUPS);
+ }
if ( NewFormat12Groups == NULL)
{
errCode = ERR_MEM;
@@ -495,7 +556,7 @@ uint16 usBytesRead;
/* Donald, if you don't care if the Cmap subtable grows, you could comment out the next line */
if (CmapFormat12.length <= CmapSubHeader.length) /* if the new length is smaller than the old, we can write it in the old place */
{
- if (pCmapTableLoc[i].platformID == MS_PLATFORMID) /* only applies to this platform */
+ if (pCmapTableLoc[i].platformID == MS_PLATFORMID && (!TTF_SAFE_CHECKS_ENABLED() || ulnCharGlyphMapListCount > 0)) /* only applies to this platform */
{
*pOS2MinChr = (uint16)pCharGlyphMapListEx[0].ulCharCode;
*pOS2MaxChr = (uint16)pCharGlyphMapListEx[ulnCharGlyphMapListCount-1].ulCharCode;
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp
index eaf87f2de70..0cef3bbf07b 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp
@@ -23,6 +23,8 @@
#include "util.h"
#include "modglyf.h"
#include "ttferror.h" /* for error codes */
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
/* ------------------------------------------------------------------- */
/* this function modifies the glyf and loca tables by copying only glyfs
@@ -60,7 +62,18 @@ HEAD Head;
/* allocate memory for and read loca table */
- aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 ));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulLocaCount = (uint32)usGlyphCount + 1;
+ uint32 ulAllocSize;
+ if (ULongMult32(ulLocaCount, (uint32)sizeof( uint32 ), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ aulLoca = (uint32 *)Mem_Alloc( ulAllocSize );
+ }
+ else
+ {
+ aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 ));
+ }
if ( aulLoca == NULL )
return ERR_MEM;
@@ -120,18 +133,56 @@ HEAD Head;
if ( ulGlyphLength )
{
- if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutGlyfOffset + ulOutLoca,
- ulGlyfOffset + aulLoca[ i ], ulGlyphLength )) != NO_ERROR)
- break;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulOutOff, ulInOff;
+ if (UIntAdd32(ulOutGlyfOffset, ulOutLoca, &ulOutOff) != S_OK ||
+ UIntAdd32(ulGlyfOffset, aulLoca[i], &ulInOff) != S_OK)
+ {
+ errCode = ERR_GENERIC;
+ break;
+ }
+ if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutOff,
+ ulInOff, ulGlyphLength )) != NO_ERROR)
+ break;
+ }
+ else
+ {
+ if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutGlyfOffset + ulOutLoca,
+ ulGlyfOffset + aulLoca[ i ], ulGlyphLength )) != NO_ERROR)
+ break;
+ }
}
}
assert((ulOutLoca & 1) != 1);
aulLoca[ i ] = ulOutLoca;
ulOutLoca += ulGlyphLength;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulOutLoca < ulGlyphLength)
+ {
+ errCode = ERR_GENERIC;
+ break;
+ }
+ }
if (ulOutLoca & 1)
{ /* the glyph offset is on an odd-byte boundry. get ready for next time */
- if ((errCode = WriteByte( pOutputBufferInfo, 0, ulOutGlyfOffset + ulOutLoca)) != NO_ERROR)
- break;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulPadOff;
+ if (UIntAdd32(ulOutGlyfOffset, ulOutLoca, &ulPadOff) != S_OK)
+ {
+ errCode = ERR_GENERIC;
+ break;
+ }
+ if ((errCode = WriteByte( pOutputBufferInfo, 0, ulPadOff)) != NO_ERROR)
+ break;
+ }
+ else
+ {
+ if ((errCode = WriteByte( pOutputBufferInfo, 0, ulOutGlyfOffset + ulOutLoca)) != NO_ERROR)
+ break;
+ }
++ulOutLoca;
}
}
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp
index b50aeb50257..c6ea1bd42d9 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp
@@ -24,6 +24,61 @@
// mark them as SecurityCritical because they have unverfiable code and we could
// not negotiate with the CRT team to fix it.
#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
+
+/* ------------------------------------------------------------------- */
+
+/* Helper function for bounds checking EBDT buffer ranges */
+PRIVATE int16 CheckEBDTBounds(uint32 ulOffset, uint32 ulLength, uint32 ulAllocatedSize)
+{
+ uint32 ulEndOffset;
+
+ /* Check for integer overflow in offset + length */
+ if (FAILED(UIntAdd32(ulOffset, ulLength, &ulEndOffset)))
+ {
+ return ERR_INVALID_EBLC;
+ }
+
+ /* Check if write would exceed buffer bounds */
+ if (ulEndOffset > ulAllocatedSize)
+ {
+ return ERR_INVALID_EBLC;
+ }
+
+ return NO_ERROR;
+}
+
+/* Helper function for copying EBDT bytes with read/write bounds and overflow checks */
+PRIVATE int16 CopyEBDTBytesChecked(
+ TTFACC_FILEBUFFERINFO *pInputBufferInfo,
+ uint8 *puchEBDTDestPtr,
+ uint32 ulEBDTSrcOffset,
+ uint32 ulEBDTAllocatedSize,
+ uint32 ulDestImageDataOffset,
+ uint32 ulDestGlyphOffset,
+ uint32 ulSrcImageDataOffset,
+ uint32 ulSrcGlyphOffset,
+ uint32 ulGlyphLength)
+{
+ uint32 ulWriteOffset;
+ uint32 ulReadRelativeOffset;
+ uint32 ulReadOffset;
+ int16 errCode;
+
+ if (FAILED(UIntAdd32(ulDestImageDataOffset, ulDestGlyphOffset, &ulWriteOffset)))
+ return ERR_INVALID_EBLC;
+ if ((errCode = CheckEBDTBounds(ulWriteOffset, ulGlyphLength, ulEBDTAllocatedSize)) != NO_ERROR)
+ return errCode;
+
+ if (FAILED(UIntAdd32(ulSrcImageDataOffset, ulSrcGlyphOffset, &ulReadRelativeOffset)))
+ return ERR_INVALID_EBLC;
+ if ((errCode = CheckEBDTBounds(ulReadRelativeOffset, ulGlyphLength, ulEBDTAllocatedSize)) != NO_ERROR)
+ return errCode;
+ if (FAILED(UIntAdd32(ulEBDTSrcOffset, ulReadRelativeOffset, &ulReadOffset)))
+ return ERR_INVALID_EBLC;
+
+ return ReadBytes(pInputBufferInfo, puchEBDTDestPtr + ulWriteOffset, ulReadOffset, ulGlyphLength);
+}
/* ------------------------------------------------------------------- */
@@ -57,11 +112,30 @@ PRIVATE int16 RecordGlyphOffset(PGLYPHOFFSETRECORDKEEPER pKeeper,
if (pKeeper->ulNextArrayIndex >= pKeeper->ulOffsetArrayLen)
{
- pKeeper->pGlyphOffsetArray = (GlyphOffsetRecord *) Mem_ReAlloc(pKeeper->pGlyphOffsetArray, (pKeeper->ulOffsetArrayLen + 100) * sizeof(*(pKeeper->pGlyphOffsetArray)));
- if (pKeeper->pGlyphOffsetArray == NULL)
- return ERR_MEM; /* ("EBLC: Not enough memory to allocate Offset Array."); */
- memset((char *)(pKeeper->pGlyphOffsetArray) + (sizeof(*(pKeeper->pGlyphOffsetArray)) * pKeeper->ulOffsetArrayLen), '\0', sizeof(*(pKeeper->pGlyphOffsetArray)) * 100);
- pKeeper->ulOffsetArrayLen += 100;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulNewLen;
+ uint32 ulAllocSize;
+ if (UIntAdd32(pKeeper->ulOffsetArrayLen, 100, &ulNewLen) != S_OK ||
+ ULongMult32(ulNewLen, (uint32)sizeof(*(pKeeper->pGlyphOffsetArray)), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ {
+ GlyphOffsetRecord *pNewArray = (GlyphOffsetRecord *) Mem_ReAlloc(pKeeper->pGlyphOffsetArray, ulAllocSize);
+ if (pNewArray == NULL)
+ return ERR_MEM; /* ("EBLC: Not enough memory to allocate Offset Array."); */
+ pKeeper->pGlyphOffsetArray = pNewArray;
+ }
+ memset((char *)(pKeeper->pGlyphOffsetArray) + (sizeof(*(pKeeper->pGlyphOffsetArray)) * pKeeper->ulOffsetArrayLen), '\0', sizeof(*(pKeeper->pGlyphOffsetArray)) * 100);
+ pKeeper->ulOffsetArrayLen = ulNewLen;
+ }
+ else
+ {
+ pKeeper->pGlyphOffsetArray = (GlyphOffsetRecord *) Mem_ReAlloc(pKeeper->pGlyphOffsetArray, (pKeeper->ulOffsetArrayLen + 100) * sizeof(*(pKeeper->pGlyphOffsetArray)));
+ if (pKeeper->pGlyphOffsetArray == NULL)
+ return ERR_MEM; /* ("EBLC: Not enough memory to allocate Offset Array."); */
+ memset((char *)(pKeeper->pGlyphOffsetArray) + (sizeof(*(pKeeper->pGlyphOffsetArray)) * pKeeper->ulOffsetArrayLen), '\0', sizeof(*(pKeeper->pGlyphOffsetArray)) * 100);
+ pKeeper->ulOffsetArrayLen += 100;
+ }
}
pKeeper->pGlyphOffsetArray[pKeeper->ulNextArrayIndex].ulOldOffset = ulOldOffset;
pKeeper->pGlyphOffsetArray[pKeeper->ulNextArrayIndex].ImageDataBlock.ulNewImageDataOffset = pImageDataBlock->ulNewImageDataOffset ;
@@ -123,6 +197,7 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
uint32 *pulEBDTBytesWritten, /* number of bytes written to the EBDT table buffer */
uint8 *puchEBDTDestPtr, /* EBDT data byffer */
uint32 ulEBDTSrcOffset, /* beginning of EBDT table in the InputBufferInfo */
+ uint32 ulEBDTAllocatedSize, /* allocated size of EBDT buffer for bounds checking */
PGLYPHOFFSETRECORDKEEPER pKeeper) /* structure to keep track of multiply referenced EBDT data */
{
INDEXSUBHEADER IndexSubHeader;
@@ -208,11 +283,23 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
return errCode;
ulOffset += usBytesRead;
IndexSubTable1.header.ulImageDataOffset = ulCurrentImageDataOffset; /* set to the new one */
- if (FAILED(UIntAdd(ulLocalCurrentOffset,SIZEOF_INDEXSUBTABLE1,(UINT *)&ulIndexSubtableAfterEnd)) ||
- (ulIndexSubtableAfterEnd > *pulIndexSubTableSize)
- )
+ if (TTF_SAFE_CHECKS_ENABLED())
{
- return ERR_INVALID_EBLC;
+ if (FAILED(UIntAdd32(ulLocalCurrentOffset, SIZEOF_INDEXSUBTABLE1, &ulIndexSubtableAfterEnd)) ||
+ (ulIndexSubtableAfterEnd > *pulIndexSubTableSize)
+ )
+ {
+ return ERR_INVALID_EBLC;
+ }
+ }
+ else
+ {
+ if (FAILED(UIntAdd(ulLocalCurrentOffset, SIZEOF_INDEXSUBTABLE1, (UINT *)&ulIndexSubtableAfterEnd)) ||
+ (ulIndexSubtableAfterEnd > *pulIndexSubTableSize)
+ )
+ {
+ return ERR_INVALID_EBLC;
+ }
}
memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable1, SIZEOF_INDEXSUBTABLE1);
ulTableSize = SIZEOF_INDEXSUBTABLE1;
@@ -233,12 +320,25 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
{
/* if the indexTableSize length field was incorrect */
/* use 2* to account for the extra offset at the end */
- if (FAILED(UIntAdd(ulLocalCurrentOffset, ulTableSize, (UINT *)&ulIndexSubtableAfterEnd)) ||
- FAILED(UIntAdd(ulIndexSubtableAfterEnd, 2*sizeof(ulNewGlyphOffset), (UINT *)&ulIndexSubtableAfterEnd)) ||
- (ulIndexSubtableAfterEnd > *pulIndexSubTableSize)
- )
+ if (TTF_SAFE_CHECKS_ENABLED())
{
- return ERR_INVALID_EBLC;
+ if (FAILED(UIntAdd32(ulLocalCurrentOffset, ulTableSize, &ulIndexSubtableAfterEnd)) ||
+ FAILED(UIntAdd32(ulIndexSubtableAfterEnd, 2*sizeof(ulNewGlyphOffset), &ulIndexSubtableAfterEnd)) ||
+ (ulIndexSubtableAfterEnd > *pulIndexSubTableSize)
+ )
+ {
+ return ERR_INVALID_EBLC;
+ }
+ }
+ else
+ {
+ if (FAILED(UIntAdd(ulLocalCurrentOffset, ulTableSize, (UINT *)&ulIndexSubtableAfterEnd)) ||
+ FAILED(UIntAdd(ulIndexSubtableAfterEnd, 2*sizeof(ulNewGlyphOffset), (UINT *)&ulIndexSubtableAfterEnd)) ||
+ (ulIndexSubtableAfterEnd > *pulIndexSubTableSize)
+ )
+ {
+ return ERR_INVALID_EBLC;
+ }
}
memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &ulNewGlyphOffset,
@@ -254,10 +354,28 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
ulGlyphLength = ulNextGlyphOffset-ulOldGlyphOffset;
if (DoCopy)
{
- if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable1.header.ulImageDataOffset + ulNewGlyphOffset,
- ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset,
- ulGlyphLength)) != NO_ERROR)
- return errCode;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ errCode = CopyEBDTBytesChecked(
+ (TTFACC_FILEBUFFERINFO *)pInputBufferInfo,
+ puchEBDTDestPtr,
+ ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
+ IndexSubTable1.header.ulImageDataOffset,
+ ulNewGlyphOffset,
+ ulOldImageDataOffset,
+ ulOldGlyphOffset,
+ ulGlyphLength);
+ if (errCode != NO_ERROR)
+ return errCode;
+ }
+ else
+ {
+ if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable1.header.ulImageDataOffset + ulNewGlyphOffset,
+ ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset,
+ ulGlyphLength)) != NO_ERROR)
+ return errCode;
+ }
}
ulNewGlyphOffset += ulGlyphLength;
}
@@ -300,14 +418,38 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
/* check if there are any gaps */
if (IndexSubTable5.ulNumGlyphs != (uint32) (*pusNewLastGlyphIndex - *pusNewFirstGlyphIndex + 1)) /* not sparse, we got everyone */
{
- ausGlyphCodeArray = (uint16 *) Mem_Alloc(sizeof(uint16) * IndexSubTable5.ulNumGlyphs);
- /* Need to enlarge pointer too by the difference between Format 2 and format 5 */
- *pulIndexSubTableSize += (IndexSubTable5.ulNumGlyphs * sizeof(uint16) + sizeof(uint32));
- *ppuchIndexSubTable = (uint8 *)Mem_ReAlloc(*ppuchIndexSubTable, *pulIndexSubTableSize);
- if ((ausGlyphCodeArray == NULL) || (*ppuchIndexSubTable == NULL))
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulGlyphAllocSize, ulExtraSize;
+ if (ULongMult32((uint32)sizeof(uint16), IndexSubTable5.ulNumGlyphs, &ulGlyphAllocSize) != S_OK)
+ return ERR_MEM;
+ ausGlyphCodeArray = (uint16 *) Mem_Alloc(ulGlyphAllocSize);
+ /* Need to enlarge pointer too by the difference between Format 2 and format 5 */
+ if (UIntAdd32(ulGlyphAllocSize, (uint32)sizeof(uint32), &ulExtraSize) != S_OK ||
+ UIntAdd32(*pulIndexSubTableSize, ulExtraSize, pulIndexSubTableSize) != S_OK)
+ {
+ Mem_Free(ausGlyphCodeArray);
+ return ERR_MEM;
+ }
+ uint8 *pNewSubTable = (uint8 *)Mem_ReAlloc(*ppuchIndexSubTable, *pulIndexSubTableSize);
+ if ((ausGlyphCodeArray == NULL) || (pNewSubTable == NULL))
+ {
+ Mem_Free(ausGlyphCodeArray);
+ return ERR_MEM;
+ }
+ *ppuchIndexSubTable = pNewSubTable;
+ }
+ else
{
- Mem_Free(ausGlyphCodeArray);
- return ERR_MEM;
+ ausGlyphCodeArray = (uint16 *) Mem_Alloc(sizeof(uint16) * IndexSubTable5.ulNumGlyphs);
+ /* Need to enlarge pointer too by the difference between Format 2 and format 5 */
+ *pulIndexSubTableSize += (IndexSubTable5.ulNumGlyphs * sizeof(uint16) + sizeof(uint32));
+ *ppuchIndexSubTable = (uint8 *)Mem_ReAlloc(*ppuchIndexSubTable, *pulIndexSubTableSize);
+ if ((ausGlyphCodeArray == NULL) || (*ppuchIndexSubTable == NULL))
+ {
+ Mem_Free(ausGlyphCodeArray);
+ return ERR_MEM;
+ }
}
}
@@ -320,12 +462,33 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
ausGlyphCodeArray[IndexSubTable5.ulNumGlyphs++] = i;
if (DoCopy) /* if this glyph is supposed to be kept, copy glyph. */
{
- if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable2.header.ulImageDataOffset + ulNewGlyphOffset,
- ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset,
- ulGlyphLength)) != NO_ERROR)
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ errCode = CopyEBDTBytesChecked(
+ (TTFACC_FILEBUFFERINFO *)pInputBufferInfo,
+ puchEBDTDestPtr,
+ ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
+ IndexSubTable2.header.ulImageDataOffset,
+ ulNewGlyphOffset,
+ ulOldImageDataOffset,
+ ulOldGlyphOffset,
+ ulGlyphLength);
+ if (errCode != NO_ERROR)
+ {
+ Mem_Free(ausGlyphCodeArray); /* in case it got allocated */
+ return errCode;
+ }
+ }
+ else
{
- Mem_Free(ausGlyphCodeArray); /* in case it got allocated */
- return errCode;
+ if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable2.header.ulImageDataOffset + ulNewGlyphOffset,
+ ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset,
+ ulGlyphLength)) != NO_ERROR)
+ {
+ Mem_Free(ausGlyphCodeArray); /* in case it got allocated */
+ return errCode;
+ }
}
}
ulNewGlyphOffset += ulGlyphLength;
@@ -340,14 +503,34 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
if (ausGlyphCodeArray != NULL) /* we changed to format 5 */
{
- ulTableSize = SIZEOF_INDEXSUBTABLE5 + sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs;
- if (ulLocalCurrentOffset + ulTableSize > *pulIndexSubTableSize)
+ if (TTF_SAFE_CHECKS_ENABLED())
{
- Mem_Free(ausGlyphCodeArray); /* in case it got allocated */
- return ERR_INVALID_EBLC;
+ uint32 ulGlyphDataSize;
+ if (ULongMult32((uint32)sizeof(*ausGlyphCodeArray), IndexSubTable5.ulNumGlyphs, &ulGlyphDataSize) != S_OK ||
+ UIntAdd32(SIZEOF_INDEXSUBTABLE5, ulGlyphDataSize, &ulTableSize) != S_OK)
+ {
+ Mem_Free(ausGlyphCodeArray);
+ return ERR_INVALID_EBLC;
+ }
+ if (ulLocalCurrentOffset + ulTableSize > *pulIndexSubTableSize)
+ {
+ Mem_Free(ausGlyphCodeArray); /* in case it got allocated */
+ return ERR_INVALID_EBLC;
+ }
+ memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable5, SIZEOF_INDEXSUBTABLE5);
+ memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE5, ausGlyphCodeArray, ulGlyphDataSize);
+ }
+ else
+ {
+ ulTableSize = SIZEOF_INDEXSUBTABLE5 + sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs;
+ if (ulLocalCurrentOffset + ulTableSize > *pulIndexSubTableSize)
+ {
+ Mem_Free(ausGlyphCodeArray); /* in case it got allocated */
+ return ERR_INVALID_EBLC;
+ }
+ memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable5, SIZEOF_INDEXSUBTABLE5);
+ memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE5, ausGlyphCodeArray, sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs);
}
- memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable5, SIZEOF_INDEXSUBTABLE5);
- memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE5, ausGlyphCodeArray, sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs);
Mem_Free(ausGlyphCodeArray);
}
else
@@ -396,16 +579,47 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
ulTableSize +=sizeof(usNewGlyphOffset); /* update the size of the table */
if (usGlyphIndex < usGlyphListCount && puchKeepGlyphList[usGlyphIndex]) /* if this glyph is supposed to be kept, copy glyph. */
{
- assert(usNextGlyphOffset>=usOldGlyphOffset);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usNextGlyphOffset < usOldGlyphOffset)
+ return ERR_INVALID_EBLC;
+ }
+ else
+ {
+ assert(usNextGlyphOffset>=usOldGlyphOffset);
+ }
usGlyphLength = usNextGlyphOffset-usOldGlyphOffset;
if (DoCopy)
{
- if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *) pInputBufferInfo, puchEBDTDestPtr + IndexSubTable3.header.ulImageDataOffset + usNewGlyphOffset,
- ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset,
- usGlyphLength)) != NO_ERROR)
- return errCode;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ errCode = CopyEBDTBytesChecked(
+ (TTFACC_FILEBUFFERINFO *)pInputBufferInfo,
+ puchEBDTDestPtr,
+ ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
+ IndexSubTable3.header.ulImageDataOffset,
+ (uint32)usNewGlyphOffset,
+ ulOldImageDataOffset,
+ (uint32)usOldGlyphOffset,
+ (uint32)usGlyphLength);
+ if (errCode != NO_ERROR)
+ return errCode;
+ }
+ else
+ {
+ if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable3.header.ulImageDataOffset + usNewGlyphOffset,
+ ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset,
+ usGlyphLength)) != NO_ERROR)
+ return errCode;
+ }
}
usNewGlyphOffset = (uint16)(usNewGlyphOffset + usGlyphLength);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usNewGlyphOffset < usGlyphLength) /* uint16 wrap check */
+ return ERR_INVALID_EBLC;
+ }
}
}
usOldGlyphOffset = usNextGlyphOffset;
@@ -457,16 +671,44 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
ulTableSize +=sizeof(usGlyphIndex);
memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &usNewGlyphOffset, sizeof(usNewGlyphOffset));
ulTableSize +=sizeof(usNewGlyphOffset);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usNextGlyphOffset < usOldGlyphOffset)
+ return ERR_INVALID_EBLC;
+ }
usGlyphLength = usNextGlyphOffset-usOldGlyphOffset;
if (DoCopy)
{
- if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *) pInputBufferInfo, puchEBDTDestPtr + IndexSubTable4.header.ulImageDataOffset + usNewGlyphOffset,
- ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset,
- usGlyphLength)) != NO_ERROR)
- return errCode;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ errCode = CopyEBDTBytesChecked(
+ (TTFACC_FILEBUFFERINFO *)pInputBufferInfo,
+ puchEBDTDestPtr,
+ ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
+ IndexSubTable4.header.ulImageDataOffset,
+ (uint32)usNewGlyphOffset,
+ ulOldImageDataOffset,
+ (uint32)usOldGlyphOffset,
+ (uint32)usGlyphLength);
+ if (errCode != NO_ERROR)
+ return errCode;
+ }
+ else
+ {
+ if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable4.header.ulImageDataOffset + usNewGlyphOffset,
+ ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset,
+ usGlyphLength)) != NO_ERROR)
+ return errCode;
+ }
}
usNewGlyphOffset = (uint16)(usNewGlyphOffset + usGlyphLength);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (usNewGlyphOffset < usGlyphLength) /* uint16 wrap check */
+ return ERR_INVALID_EBLC;
+ }
++ulNumGlyphs;
*pusNewLastGlyphIndex = usGlyphIndex;
}
@@ -521,10 +763,28 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, /
ulTableSize += sizeof(usGlyphIndex);
if (DoCopy)
{
- if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *) pInputBufferInfo, puchEBDTDestPtr + IndexSubTable5.header.ulImageDataOffset + ulNewGlyphOffset,
- ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset,
- ulGlyphLength)) != NO_ERROR)
- return errCode;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ errCode = CopyEBDTBytesChecked(
+ (TTFACC_FILEBUFFERINFO *)pInputBufferInfo,
+ puchEBDTDestPtr,
+ ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
+ IndexSubTable5.header.ulImageDataOffset,
+ ulNewGlyphOffset,
+ ulOldImageDataOffset,
+ ulOldGlyphOffset,
+ ulGlyphLength);
+ if (errCode != NO_ERROR)
+ return errCode;
+ }
+ else
+ {
+ if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable5.header.ulImageDataOffset + ulNewGlyphOffset,
+ ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset,
+ ulGlyphLength)) != NO_ERROR)
+ return errCode;
+ }
}
++ulNumGlyphs;
ulNewGlyphOffset += ulGlyphLength;
@@ -580,6 +840,7 @@ typedef struct {
PRIVATE uint32 FixSbitSubTableFormat1(uint16 usFirstIndex, /* index of first Glyph in table */
uint16 * pusLastIndex, /* pointer to index of last glyph in table - will set if not all table will fit */
uint8 * puchIndexSubTable, /* buffer into which to stuff the Format 3 table(s) - does not include IndexSubTableArray */
+ uint32 ulIndexSubTableBufferSize, /* size of puchIndexSubTable buffer for bounds checking */
uint16 usImageFormat, /* in order to set the Format 3 header */
uint32 ulCurrAdditionalOffset, /* offset from indexSubTableArray of the IndexSubTable */
uint32 ulInitialOffset, /* relative offset from IndexSubTableArray of first IndexSubTable - same as CurrAdditionalOffset for first SubTable */
@@ -593,21 +854,42 @@ uint32 ulLocalCurrentOffset;
uint32 ulTableSize;
uint32 ulAdjustGlyphOffset; /* amount to subtract to get the relative offset */
uint16 usIndex;
+uint32 ulWriteEnd;
ulLocalCurrentOffset = ulCurrAdditionalOffset - ulInitialOffset; /* offset within memory buffer */
+ /* Bounds check: ensure header write fits in buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE3 > ulIndexSubTableBufferSize)
+ return 0;
+ }
+
IndexSubTable3.header.usImageFormat = usImageFormat;
IndexSubTable3.header.usIndexFormat = 3;
IndexSubTable3.header.ulImageDataOffset = *pulNewImageDataOffset; /* set to the new one */
memcpy(puchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable3, SIZEOF_INDEXSUBTABLE3);
ulTableSize = SIZEOF_INDEXSUBTABLE3;
+ /* Bounds check: ensure source reads are within buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (*pulSourceOffset + sizeof(uint32) > ulIndexSubTableBufferSize)
+ return 0;
+ }
ulAdjustGlyphOffset = * ((uint32 *) (puchIndexSubTable + *pulSourceOffset)); /* first offset is what we adjust from */
ulNewGlyphOffset = (* ((uint32 *) (puchIndexSubTable + *pulSourceOffset))) - ulAdjustGlyphOffset; /* first one of array */
*pulSourceOffset += sizeof(uint32);
for( usIndex = usFirstIndex; usIndex <= (* pusLastIndex); ++usIndex )
{
+ /* Bounds check: ensure source read fits in buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (*pulSourceOffset + sizeof(uint32) > ulIndexSubTableBufferSize)
+ return 0;
+ }
+
usNewGlyphOffset = (uint16) ulNewGlyphOffset; /* short version of the new glyph offset */
/* now grab the next one */
ulNewGlyphOffset = (* ((uint32 *) (puchIndexSubTable + *pulSourceOffset))) - ulAdjustGlyphOffset;
@@ -617,6 +899,14 @@ uint16 usIndex;
*pulSourceOffset += sizeof(uint32); /* copied this one */
+ /* Bounds check: ensure write fits in buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ ulWriteEnd = ulLocalCurrentOffset + ulTableSize + sizeof(usNewGlyphOffset);
+ if (ulWriteEnd > ulIndexSubTableBufferSize)
+ return 0;
+ }
+
memcpy(puchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &usNewGlyphOffset,
sizeof(usNewGlyphOffset)); /* copy over the table entry */
ulTableSize +=sizeof(usNewGlyphOffset); /* update the size of the table */
@@ -630,6 +920,13 @@ uint16 usIndex;
if (usIndex > (* pusLastIndex)) /* we need to copy one more */
/* Do the last table entry, which is just for Glyph size calculation purposes */
{
+ /* Bounds check for final entry */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ ulWriteEnd = ulLocalCurrentOffset + ulTableSize + sizeof(usNewGlyphOffset);
+ if (ulWriteEnd > ulIndexSubTableBufferSize)
+ return 0;
+ }
memcpy(puchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &usNewGlyphOffset,sizeof(usNewGlyphOffset));
ulTableSize +=sizeof(usNewGlyphOffset);
}
@@ -652,6 +949,7 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf
uint32 *pulNewImageDataOffset,
uint8 *puchEBDTDestPtr,
uint32 ulEBDTSrcOffset,
+ uint32 ulEBDTAllocatedSize,
PGLYPHOFFSETRECORDKEEPER pKeeper,
uint32 ulEBLCEndOffset)
{
@@ -724,6 +1022,7 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf
&ulEBDTBytesWritten,
puchEBDTDestPtr,
ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
pKeeper);
if (errCode != NO_ERROR)
return errCode;
@@ -753,6 +1052,7 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf
usFirstIndex,
&usLastIndex,
pSubTablePointers->puchIndexSubTables,
+ pSubTablePointers->nIndexSubTablesLen,
((INDEXSUBHEADER *) (pSubTablePointers->puchIndexSubTables + ulCurrAdditionalOffset-ulInitialOffset))->usImageFormat,
ulCurrAdditionalOffset,
ulInitialOffset,
@@ -777,9 +1077,19 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf
{
return ERR_MEM;
}
- pSubTablePointers->pIndexSubTableArray = (INDEXSUBTABLEARRAY *)Mem_ReAlloc(pSubTablePointers->pIndexSubTableArray, ulSubTableArrayLength);
- if (pSubTablePointers->pIndexSubTableArray == NULL)
- return ERR_MEM; /* ("EBLC: Unable to allocate memory for IndexSubTableArray."); */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ INDEXSUBTABLEARRAY *pNewArray = (INDEXSUBTABLEARRAY *)Mem_ReAlloc(pSubTablePointers->pIndexSubTableArray, ulSubTableArrayLength);
+ if (pNewArray == NULL)
+ return ERR_MEM; /* ("EBLC: Unable to allocate memory for IndexSubTableArray."); */
+ pSubTablePointers->pIndexSubTableArray = pNewArray;
+ }
+ else
+ {
+ pSubTablePointers->pIndexSubTableArray = (INDEXSUBTABLEARRAY *)Mem_ReAlloc(pSubTablePointers->pIndexSubTableArray, ulSubTableArrayLength);
+ if (pSubTablePointers->pIndexSubTableArray == NULL)
+ return ERR_MEM;
+ }
usFirstIndex = usLastIndex;
usLastIndex = usSaveLastIndex;
}
@@ -887,7 +1197,7 @@ uint32 ulStartOffset;
/* ------------------------------------------------------------------- */
void Cleanup_SubTablePointers(SubTablePointers *pSubTablePointers,uint32 ulNumSizes)
{
-uint16 ulSizeIndex;
+uint32 ulSizeIndex;
if (pSubTablePointers == NULL)
return;
@@ -954,6 +1264,7 @@ uint32 ulIndexSubTableArrayLength;
uint32 ulIndexSubTablesDataSize;
uint32 ulSubtablePointersArraySize;
uint16 i;
+uint32 ulEBDTAllocatedSize = 0; /* Track allocated EBDT buffer size for bounds checking */
GLYPHOFFSETRECORDKEEPER keeper;
char *EBDTTag;
char *EBLCTag;
@@ -1031,8 +1342,24 @@ uint32 ulEBLCEndOffset;
keeper.ulOffsetArrayLen = 0;
keeper.ulNextArrayIndex = 0;
- /* create a buffer for the EBDT table */
- puchEBDTDestPtr = (uint8 *) Mem_Alloc(TTTableLength((TTFACC_FILEBUFFERINFO *) pInputBufferInfo, EBDTTag)); /* we'll be copying the EBDT (raw bytes) table here temporarily */
+ /* Validate EBDT table size before allocation */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ /* Validate EBDT table size before allocation */
+ ulEBDTAllocatedSize = TTTableLength((TTFACC_FILEBUFFERINFO*)pInputBufferInfo, EBDTTag);
+ if (ulEBDTAllocatedSize < SIZEOF_EBDTHEADER)
+ {
+ errCode = ERR_INVALID_EBLC;
+ break;
+ }
+ /* create a buffer for the EBDT table */
+ puchEBDTDestPtr = (uint8*)Mem_Alloc(ulEBDTAllocatedSize); /* we'll be copying the EBDT (raw bytes) table here temporarily */
+ }
+ else
+ {
+ /* create a buffer for the EBDT table */
+ puchEBDTDestPtr = (uint8 *) Mem_Alloc(TTTableLength((TTFACC_FILEBUFFERINFO *) pInputBufferInfo, EBDTTag)); /* we'll be copying the EBDT (raw bytes) table here temporarily */
+ }
if (!puchEBDTDestPtr)
{
errCode = ERR_MEM;
@@ -1163,6 +1490,7 @@ uint32 ulEBLCEndOffset;
&ulNewImageDataOffset,
puchEBDTDestPtr,
ulEBDTSrcOffset,
+ ulEBDTAllocatedSize,
&keeper,
ulEBLCEndOffset) == NO_ERROR) /* valid table */
&&
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp
index f61c38cd718..0eda170eb15 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp
@@ -37,6 +37,8 @@
#include "ttmem.h"
#include "ttfdelta.h" /* for format */
#include "ttferror.h" /* for error codes */
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
/* here's the deal:
This function may do one of many things.
@@ -170,7 +172,17 @@ const char * xhea_tag;
/* now collapse the table if we are in Compact form for Subsetting and Delta fonts */
/* we will use an interrum table for simplification */
ulCrntOffset = ulXmtxOffset;
- LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(sizeof(LONGXMETRIC) * usDttfGlyphIndexCount);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)sizeof(LONGXMETRIC), (uint32)usDttfGlyphIndexCount, &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(sizeof(LONGXMETRIC) * usDttfGlyphIndexCount);
+ }
if (LongMetricsArray == NULL)
return ERR_MEM;
nNewLongMetrics = 0;
@@ -278,8 +290,22 @@ uint16 usBytesWritten;
/* recompute maxp info */
/* figure a conservative maximum total possible. 3x3 at minimum */
- usnMaxComponents = max(3,MaxP.maxComponentElements) * max(3,MaxP.maxComponentDepth);
- pausComponents = (uint16 *) Mem_Alloc(usnMaxComponents * sizeof(uint16));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulMaxComp, ulAllocSize;
+ if (ULongMult32((uint32)max(3,MaxP.maxComponentElements), (uint32)max(3,MaxP.maxComponentDepth), &ulMaxComp) != S_OK ||
+ ULongMult32(ulMaxComp, (uint32)sizeof(uint16), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ if (ulMaxComp > (uint32)USHRT_MAX)
+ return ERR_INVALID_MAXP;
+ usnMaxComponents = (uint16)ulMaxComp;
+ pausComponents = (uint16 *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ usnMaxComponents = max(3,MaxP.maxComponentElements) * max(3,MaxP.maxComponentDepth);
+ pausComponents = (uint16 *) Mem_Alloc(usnMaxComponents * sizeof(uint16));
+ }
if (pausComponents == NULL)
return ERR_MEM;
@@ -716,7 +742,16 @@ uint32 ulOutSizeDeviceRecord;
DevRecord.maxWidth = maxWidth;
if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *)&DevRecord, SIZEOF_HDMX_DEVICE_REC, HDMX_DEVICE_REC_CONTROL, ulOutDevOffset, &usBytesWritten )) != NO_ERROR)
return errCode;
- ulInOffset = ulInDevOffset + Hdmx.sizeDeviceRecord;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ ulInOffset = ulInDevOffset + (uint32)Hdmx.sizeDeviceRecord;
+ if (ulInOffset < ulInDevOffset) /* overflow check */
+ return ERR_GENERIC;
+ }
+ else
+ {
+ ulInOffset = ulInDevOffset + Hdmx.sizeDeviceRecord;
+ }
ulOutOffset = ulOutDevOffset + ulOutSizeDeviceRecord;
}
/* now need to update hdmx record */
@@ -762,7 +797,16 @@ uint32 ulOutSizeDeviceRecord;
if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *)&DevRecord, SIZEOF_HDMX_DEVICE_REC, HDMX_DEVICE_REC_CONTROL, ulDevOffset, &usBytesWritten )) != NO_ERROR)
return errCode;
}
- ulOffset = ulDevOffset + Hdmx.sizeDeviceRecord;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ ulOffset = ulDevOffset + (uint32)Hdmx.sizeDeviceRecord;
+ if (ulOffset < ulDevOffset) /* overflow check */
+ return ERR_GENERIC;
+ }
+ else
+ {
+ ulOffset = ulDevOffset + Hdmx.sizeDeviceRecord;
+ }
}
*pulNewOutOffset = ulOffset;
}
@@ -893,7 +937,17 @@ struct groupoffsetrecordkeeper /* housekeeping structure */
PRIVATE int16 InitGroupOffsetArray(PGROUPOFFSETRECORDKEEPER pKeeper,
uint16 usRecordCount)
{
- pKeeper->pGroupOffsetArray = (GroupOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pGroupOffsetArray)));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usRecordCount, (uint32)sizeof(*(pKeeper->pGroupOffsetArray)), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ pKeeper->pGroupOffsetArray = (GroupOffsetRecord *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pKeeper->pGroupOffsetArray = (GroupOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pGroupOffsetArray)));
+ }
if (pKeeper->pGroupOffsetArray == NULL)
return ERR_MEM;
pKeeper->usGroupOffsetArrayLen = usRecordCount;
@@ -1018,7 +1072,19 @@ TTFACC_FILEBUFFERINFO * pUnCONSTInputBufferInfo;
ulSrcOffsetGroups = ulSrcOffsetOffsets + sizeof(uint16) * Vdmx.numRatios;
memset(&keeper, 0, sizeof(keeper));
- SrcRatioArray = (VDMXRatio *)Mem_Alloc(Vdmx.numRatios * sizeof(VDMXRatio));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)Vdmx.numRatios, (uint32)sizeof(VDMXRatio), &ulAllocSize) != S_OK)
+ {
+ return ERR_MEM;
+ }
+ SrcRatioArray = (VDMXRatio *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ SrcRatioArray = (VDMXRatio *)Mem_Alloc(Vdmx.numRatios * sizeof(VDMXRatio));
+ }
if (SrcRatioArray == NULL)
errCode = ERR_MEM;
else
@@ -1111,7 +1177,19 @@ TTFACC_FILEBUFFERINFO * pUnCONSTInputBufferInfo;
if ((errCode = ReadGeneric(pUnCONSTInputBufferInfo, (uint8 *) &GroupHeader, SIZEOF_VDMXGROUP, VDMXGROUP_CONTROL, ulSrcOffset + usCurrGroupSrcOffset, &usBytesRead)) != NO_ERROR)
break;
- ulGroupLength = usBytesRead + (GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ ulGroupLength = usBytesRead + ((uint32)GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL));
+ if (ulGroupLength < usBytesRead) /* overflow check */
+ {
+ errCode = ERR_INVALID_VDMX;
+ break;
+ }
+ }
+ else
+ {
+ ulGroupLength = usBytesRead + (GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL));
+ }
/* read the group data into a buffer */
if (ulGroupLength > ulGroupBufferLength)
{
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttf_safe_checks.h b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttf_safe_checks.h
new file mode 100644
index 00000000000..947624e5fde
--- /dev/null
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttf_safe_checks.h
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef TTF_SAFE_CHECKS_H
+#define TTF_SAFE_CHECKS_H
+
+/*
+ * TtfDelta safety switch — read once from managed code (AppContext),
+ * then checked from native C code via the global.
+ *
+ * AppContext switch name:
+ * Switch.MS.Internal.TtfDelta.DisableDirectWriteForwarderBoundsCheckProtection
+ *
+ * Default (false / absent): Safe checks ON (new behavior).
+ * Set to true: Safe checks OFF (old behavior / opt-out).
+ */
+
+/* -1 = uninitialized, 0 = safe checks disabled (old), 1 = safe checks enabled (new) */
+extern int g_fDWFBoundsCheckEnabled;
+
+#define TTF_SAFE_CHECKS_ENABLED() (g_fDWFBoundsCheckEnabled != 0)
+
+#endif /* TTF_SAFE_CHECKS_H */
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp
index 8a2bce89d10..23562d736b0 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp
@@ -23,6 +23,8 @@
#ifdef _DEBUG
#include
#endif
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
#if 0
/* turn back into a macro, because it gets called so much */
@@ -73,7 +75,7 @@ int16 CheckOutOffset(TTFACC_FILEBUFFERINFO *a, register uint32 b, register uint3
{
#ifdef _DEBUG
#if !defined(ARGITERATOR_SUPPORTED) || (defined(ARGITERATOR_SUPPORTED) && ARGITERATOR_SUPPORTED)
- printf("we're reallocating 10 percent (%lu) more bytes\n", (uint32)(a->ulBufferSize * .1));
+ printf("we're reallocating 10 percent (%lu) more bytes\n", (uint32)(a->ulBufferSize * .1));
#endif
#endif
a->ulBufferSize = (uint32) (a->ulBufferSize * 11/10);
@@ -86,14 +88,14 @@ int16 CheckOutOffset(TTFACC_FILEBUFFERINFO *a, register uint32 b, register uint3
#endif
#endif
a->ulBufferSize = b + c;
- }
-
+ }
+
if ((a->puchBuffer = (uint8 *)a->lpfnReAllocate(a->puchBuffer, a->ulBufferSize)) == NULL)
{
a->ulBufferSize = 0L;
return ERR_MEM;
}
- }
+ }
return NO_ERROR;
}
@@ -242,14 +244,30 @@ UNALIGNED uint32 *pulBuffer;
uint16 i;
int16 errCode;
- usControlCount = puchControl[0];
+if (TTF_SAFE_CHECKS_ENABLED())
+{
+ if (pInputBufferInfo == NULL || puchControl == NULL || pusBytesRead == NULL)
+ return ERR_READCONTROL;
+ if (usBufferSize != 0 && puchBuffer == NULL)
+ return ERR_READCONTROL;
+}
+
+ usControlCount = puchControl[0];
for (i = 1; i <= usControlCount; ++i)
{
switch (puchControl[i] & TTFACC_DATA)
{
case TTFACC_BYTE:
- if (usBufferOffset + sizeof(uint8) > usBufferSize)
- return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (static_cast(usBufferOffset) + static_cast(sizeof(uint8)) > static_cast(usBufferSize))
+ return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ }
+ else
+ {
+ if (usBufferOffset + sizeof(uint8) > usBufferSize)
+ return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ }
if (puchControl[i] & TTFACC_PAD) /* don't read, just pad */
*(puchBuffer + usBufferOffset) = 0;
else
@@ -257,13 +275,30 @@ int16 errCode;
if ((errCode = ReadByte(pInputBufferInfo, puchBuffer + usBufferOffset, ulCurrOffset))!=NO_ERROR)
return errCode;
- ulCurrOffset += sizeof(uint8);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulCurrOffset + static_cast(sizeof(uint8)) < ulCurrOffset)
+ return ERR_READOUTOFBOUNDS;
+ ulCurrOffset += static_cast(sizeof(uint8));
+ }
+ else
+ {
+ ulCurrOffset += sizeof(uint8);
+ }
}
usBufferOffset += sizeof(uint8);
break;
case TTFACC_WORD:
- if (usBufferOffset + sizeof(uint16) > usBufferSize)
- return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (static_cast(usBufferOffset) + static_cast(sizeof(uint16)) > static_cast(usBufferSize))
+ return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ }
+ else
+ {
+ if (usBufferOffset + sizeof(uint16) > usBufferSize)
+ return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ }
pusBuffer = (uint16 *) (puchBuffer + usBufferOffset);
if (puchControl[i] & TTFACC_PAD) /* don't read, just pad */
*pusBuffer = 0;
@@ -279,13 +314,30 @@ int16 errCode;
if ((errCode = ReadWord(pInputBufferInfo, pusBuffer, ulCurrOffset))!=NO_ERROR)
return errCode;
}
- ulCurrOffset += sizeof(uint16);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulCurrOffset + static_cast(sizeof(uint16)) < ulCurrOffset)
+ return ERR_READOUTOFBOUNDS;
+ ulCurrOffset += static_cast(sizeof(uint16));
+ }
+ else
+ {
+ ulCurrOffset += sizeof(uint16);
+ }
}
usBufferOffset += sizeof(uint16);
break;
case TTFACC_LONG:
- if (usBufferOffset + sizeof(uint32) > usBufferSize)
- return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (static_cast(usBufferOffset) + static_cast(sizeof(uint32)) > static_cast(usBufferSize))
+ return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ }
+ else
+ {
+ if (usBufferOffset + sizeof(uint32) > usBufferSize)
+ return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */
+ }
pulBuffer = (uint32 *) (puchBuffer + usBufferOffset);
if (puchControl[i] & TTFACC_PAD) /* don't read, just pad */
*pulBuffer = 0;
@@ -302,7 +354,16 @@ int16 errCode;
if ((errCode = ReadLong(pInputBufferInfo, pulBuffer, ulCurrOffset))!=NO_ERROR)
return errCode;
}
- ulCurrOffset += sizeof(uint32);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulCurrOffset + static_cast(sizeof(uint32)) < ulCurrOffset)
+ return ERR_READOUTOFBOUNDS;
+ ulCurrOffset += static_cast(sizeof(uint32));
+ }
+ else
+ {
+ ulCurrOffset += sizeof(uint32);
+ }
}
usBufferOffset += sizeof(uint32);
break;
@@ -312,7 +373,17 @@ int16 errCode;
} /* end for i */
if (usBufferOffset < usBufferSize) /* didn't fill up the buffer */
return ERR_READCONTROL; /* control thing doesn't fit the buffer */
- * pusBytesRead = (uint16) (ulCurrOffset - ulOffset);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulBytesRead = ulCurrOffset - ulOffset;
+ *pusBytesRead = static_cast(ulBytesRead);
+ if (static_cast(*pusBytesRead) != ulBytesRead)
+ return ERR_READCONTROL;
+ }
+ else
+ {
+ * pusBytesRead = (uint16) (ulCurrOffset - ulOffset);
+ }
return NO_ERROR;
}
/* ---------------------------------------------------------------------- */
@@ -348,7 +419,17 @@ uint16 usBytesRead;
puchBuffer += usItemSize;
}
- *pulBytesRead = usItemSize * usItemCount;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulTotalBytesRead;
+ if (ULongMult32((uint32)usItemSize, (uint32)usItemCount, &ulTotalBytesRead) != S_OK)
+ return ERR_READOUTOFBOUNDS;
+ *pulBytesRead = ulTotalBytesRead;
+ }
+ else
+ {
+ *pulBytesRead = usItemSize * usItemCount;
+ }
return NO_ERROR;
}
/* ---------------------------------------------------------------------- */
@@ -378,7 +459,15 @@ uint16 i;
uint32 ulBytesWritten;
int16 errCode;
- usControlCount = puchControl[0];
+if (TTF_SAFE_CHECKS_ENABLED())
+{
+ if (pOutputBufferInfo == NULL || puchControl == NULL || pusBytesWritten == NULL)
+ return ERR_WRITECONTROL;
+ if (usBufferSize != 0 && puchBuffer == NULL)
+ return ERR_WRITECONTROL;
+}
+
+ usControlCount = puchControl[0];
for (i = 1; i <= usControlCount; ++i)
{
switch (puchControl[i] & TTFACC_DATA)
@@ -386,20 +475,45 @@ int16 errCode;
case TTFACC_BYTE:
if (!(puchControl[i] & TTFACC_PAD))
{
- if (usBufferOffset + sizeof(uint8) > usBufferSize)
- return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (static_cast(usBufferOffset) + static_cast(sizeof(uint8)) > static_cast(usBufferSize))
+ return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ }
+ else
+ {
+ if (usBufferOffset + sizeof(uint8) > usBufferSize)
+ return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ }
if ((errCode = WriteByte(pOutputBufferInfo, *(puchBuffer + usBufferOffset), ulCurrOffset))!=NO_ERROR)
return errCode;
- ulCurrOffset += sizeof(uint8);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulCurrOffset + static_cast(sizeof(uint8)) < ulCurrOffset)
+ return ERR_WRITEOUTOFBOUNDS;
+ ulCurrOffset += static_cast(sizeof(uint8));
+ }
+ else
+ {
+ ulCurrOffset += sizeof(uint8);
+ }
}
usBufferOffset += sizeof(uint8);
break;
case TTFACC_WORD:
if (!(puchControl[i] & TTFACC_PAD))
{
- if (usBufferOffset + sizeof(uint16) > usBufferSize)
- return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (static_cast(usBufferOffset) + static_cast(sizeof(uint16)) > static_cast(usBufferSize))
+ return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ }
+ else
+ {
+ if (usBufferOffset + sizeof(uint16) > usBufferSize)
+ return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ }
pusBuffer = (uint16 *) (puchBuffer + usBufferOffset);
if (puchControl[i] & TTFACC_NO_XLATE)
@@ -412,15 +526,32 @@ int16 errCode;
if ((errCode = WriteWord(pOutputBufferInfo, *pusBuffer, ulCurrOffset))!=NO_ERROR)
return errCode;
}
- ulCurrOffset += sizeof(uint16);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulCurrOffset + static_cast(sizeof(uint16)) < ulCurrOffset)
+ return ERR_WRITEOUTOFBOUNDS;
+ ulCurrOffset += static_cast(sizeof(uint16));
+ }
+ else
+ {
+ ulCurrOffset += sizeof(uint16);
+ }
}
usBufferOffset += sizeof(uint16);
break;
case TTFACC_LONG:
if (!(puchControl[i] & TTFACC_PAD))
{
- if (usBufferOffset + sizeof(uint32) > usBufferSize)
- return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (static_cast(usBufferOffset) + static_cast(sizeof(uint32)) > static_cast(usBufferSize))
+ return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ }
+ else
+ {
+ if (usBufferOffset + sizeof(uint32) > usBufferSize)
+ return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */
+ }
pulBuffer = (uint32 *) (puchBuffer + usBufferOffset);
if (puchControl[i] & TTFACC_NO_XLATE)
@@ -433,7 +564,16 @@ int16 errCode;
if ((errCode = WriteLong(pOutputBufferInfo, *pulBuffer, ulCurrOffset))!=NO_ERROR)
return errCode;
}
- ulCurrOffset += sizeof(uint32);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulCurrOffset + static_cast(sizeof(uint32)) < ulCurrOffset)
+ return ERR_WRITEOUTOFBOUNDS;
+ ulCurrOffset += static_cast(sizeof(uint32));
+ }
+ else
+ {
+ ulCurrOffset += sizeof(uint32);
+ }
}
usBufferOffset += sizeof(uint32);
break;
@@ -482,7 +622,17 @@ uint16 usBytesWritten;
puchBuffer += usItemSize;
}
- *pulBytesWritten = usItemSize * usItemCount;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulTotalBytesWritten;
+ if (ULongMult32((uint32)usItemSize, (uint32)usItemCount, &ulTotalBytesWritten) != S_OK)
+ return ERR_WRITEOUTOFBOUNDS;
+ *pulBytesWritten = ulTotalBytesWritten;
+ }
+ else
+ {
+ *pulBytesWritten = usItemSize * usItemCount;
+ }
return NO_ERROR;
}
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp
index 3e3530dbec6..a841c171915 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp
@@ -19,6 +19,9 @@
#include /* for memcpy */
#include "typedefs.h"
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
+
#include "ttff.h"
#include "ttfacc.h"
#include "ttfcntrl.h"
@@ -111,7 +114,14 @@ int16 errCode;
ulOffset += usBytesRead;
/* Create a list of valid tables */
- aDirectory = (DIRECTORY *) Mem_Alloc((usnTables + (ulDttfOffset == 0)) * sizeof(DIRECTORY)); /* one extra for possible private table */
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)(usnTables + (ulDttfOffset == 0)), (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK)
+ return(ERR_MEM);
+ aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize); /* one extra for possible private table */
+ } else {
+ aDirectory = (DIRECTORY *) Mem_Alloc((usnTables + (ulDttfOffset == 0)) * sizeof(DIRECTORY));
+ }
if (aDirectory == NULL)
return(ERR_MEM);
@@ -213,7 +223,14 @@ char szTag[5];
usnTables = OffsetTable.numTables;
/* Create a list of valid tables */
- aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY));
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usnTables, (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK)
+ return(ERR_MEM);
+ aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize);
+ } else {
+ aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY));
+ }
if (aDirectory == NULL)
return(ERR_MEM);
@@ -297,7 +314,15 @@ HEAD Head;
if ((ulHeadOffset = GetHead(pOutputBufferInfo, &Head)) == 0L)
return ERR_MISSING_HEAD;
- aulLoca = (uint32 *)Mem_Alloc( (usGlyphListCount + 1) * sizeof( uint32 ));
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ uint32 ulLocaCount = (uint32)usGlyphListCount + 1;
+ uint32 ulAllocSize;
+ if (ULongMult32(ulLocaCount, (uint32)sizeof( uint32 ), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ aulLoca = (uint32 *)Mem_Alloc( ulAllocSize );
+ } else {
+ aulLoca = (uint32 *)Mem_Alloc( (usGlyphListCount + 1) * sizeof( uint32 ) );
+ }
if ( aulLoca == NULL )
return ERR_MEM;
@@ -316,8 +341,16 @@ HEAD Head;
if ((j == usDttfGlyphIndexCount) || (i < usGlyphListCount && puchKeepGlyphList[i]))
{
usOffset = (uint16) (aulLoca[ i ] / 2L);
- if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulLocaOffset + j*sizeof(uint16) )) != NO_ERROR)
- break;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulLocaOffset + (uint32)j*sizeof(uint16) )) != NO_ERROR)
+ break;
+ }
+ else
+ {
+ if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulLocaOffset + j*sizeof(uint16) )) != NO_ERROR)
+ break;
+ }
++j;
}
}
@@ -329,8 +362,16 @@ HEAD Head;
{
if ((j == usDttfGlyphIndexCount) || (i < usGlyphListCount && puchKeepGlyphList[i]))
{
- if ((errCode = WriteLong( pOutputBufferInfo, aulLoca[ i ], ulLocaOffset + j*sizeof(uint32) )) != NO_ERROR)
- break;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if ((errCode = WriteLong( pOutputBufferInfo, aulLoca[ i ], ulLocaOffset + (uint32)j*sizeof(uint32) )) != NO_ERROR)
+ break;
+ }
+ else
+ {
+ if ((errCode = WriteLong( pOutputBufferInfo, aulLoca[ i ], ulLocaOffset + j*sizeof(uint32) )) != NO_ERROR)
+ break;
+ }
++j;
}
}
@@ -385,11 +426,23 @@ uint16 usBytesWritten;
if (usFormat != TTFDELTA_SUBSET1 && usFormat != TTFDELTA_DELTA) /* formats with dttf tables */
return NO_ERROR;
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ if (usDttfGlyphIndexCount == 0)
+ return ERR_GENERIC;
+ }
+
ulOffset = GetTTDirectory( pOutputBufferInfo, DTTF_TAG, &DttfDirectory);
if ((errCode = ZeroLongWordAlign(pOutputBufferInfo, *pulNewOutOffset, &(DttfDirectory.offset))) != NO_ERROR)
return errCode;
- DttfDirectory.length = GetGenericSize(DTTF_HEADER_CONTROL) + usDttfGlyphIndexCount * sizeof(uint16);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ DttfDirectory.length = GetGenericSize(DTTF_HEADER_CONTROL) + (uint32)usDttfGlyphIndexCount * sizeof(uint16);
+ }
+ else
+ {
+ DttfDirectory.length = GetGenericSize(DTTF_HEADER_CONTROL) + usDttfGlyphIndexCount * sizeof(uint16);
+ }
if (ulOffset == DIRECTORY_ERROR) /* there wasn't one there - don't really need this code - its obsolete */
return ERR_GENERIC;
@@ -427,7 +480,7 @@ uint16 usBytesWritten;
/* in addition any array tables (LTSH, loca, hmtx, hdmx, vmtx) will have a percentage discarded */
/* Format Delta will keep only a list of tables, and the Subset1 compacted and Glyf tables will keep only a portion */
/* ---------------------------------------------------------------------- */
-PRIVATE void CalcOutputBufferSize(CONST_TTFACC_FILEBUFFERINFO *pInputBufferInfo,
+PRIVATE int16 CalcOutputBufferSize(CONST_TTFACC_FILEBUFFERINFO *pInputBufferInfo,
uint16 usGlyphListCount,
uint16 usGlyphKeepCount,
uint16 usFormat,
@@ -458,37 +511,93 @@ uint32 ulKeepTablesLength = 0;
if (ulEBDTTableOffset != TTTableOffset((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BDAT_TAG))
ulBdatTableLength = 0;
}
- ulAllGlyphsLength = ulEBDTTableLength + ulBdatTableLength;
- ulAllGlyphsLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (UIntAdd32(ulEBDTTableLength, ulBdatTableLength, &ulAllGlyphsLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulAllGlyphsLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG), &ulAllGlyphsLength) != S_OK)
+ return ERR_GENERIC;
+
+ if (usFormat == TTFDELTA_DELTA || usFormat == TTFDELTA_SUBSET1)
+ { /* these formats will compact some tables, discarding a percentage of these tables as well */
+ /* tables compacted */
+ ulGlyphDependentDataLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LTSH_TAG);
+ if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HMTX_TAG), &ulGlyphDependentDataLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VMTX_TAG), &ulGlyphDependentDataLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HDMX_TAG), &ulGlyphDependentDataLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LOCA_TAG), &ulGlyphDependentDataLength) != S_OK)
+ return ERR_GENERIC;
+ }
+ if (UIntAdd32(ulGlyphDependentDataLength, ulAllGlyphsLength, &ulGlyphDependentDataLength) != S_OK) /* all formats will discard a percentage of the glyph data */
+ return ERR_GENERIC;
- if (usFormat == TTFDELTA_DELTA || usFormat == TTFDELTA_SUBSET1)
- { /* these formats will compact some tables, discarding a percentage of these tables as well */
- /* tables compacted */
- ulGlyphDependentDataLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LTSH_TAG);
- ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HMTX_TAG);
- ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VMTX_TAG);
- ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HDMX_TAG);
- ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LOCA_TAG);
+ if (usFormat == TTFDELTA_DELTA) /* we're going to keep just a handfull of tables tables */
+ {
+ ulKeepTablesLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HEAD_TAG);
+ if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, MAXP_TAG), &ulKeepTablesLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HHEA_TAG), &ulKeepTablesLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VHEA_TAG), &ulKeepTablesLength) != S_OK)
+ return ERR_GENERIC;
+ if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, CMAP_TAG), &ulKeepTablesLength) != S_OK)
+ return ERR_GENERIC;
+ if (ulEBDTTableLength > 0)
+ {
+ if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, EBLC_TAG), &ulKeepTablesLength) != S_OK)
+ return ERR_GENERIC;
+ }
+ if (ulBdatTableLength > 0)
+ {
+ if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BLOC_TAG), &ulKeepTablesLength) != S_OK)
+ return ERR_GENERIC;
+ }
+
+ if (UIntAdd32(ulKeepTablesLength, (uint32)(flKeepPercent * ulGlyphDependentDataLength/100), pulOutputBufferLength) != S_OK)
+ return ERR_GENERIC;
+ }
+ else
+ /* for straight subset, this will be: ulSrcBufferSize - (discard % * (Glyf table size + EBDT table size + bdat table size)) */
+ *pulOutputBufferLength = ulSrcBufferSize - (uint32)(flDiscardPercent * ulGlyphDependentDataLength/100);
}
- ulGlyphDependentDataLength += ulAllGlyphsLength; /* all formats will discard a percentage of the glyph data */
-
- if (usFormat == TTFDELTA_DELTA) /* we're going to keep just a handfull of tables tables */
+ else
{
- ulKeepTablesLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HEAD_TAG);
- ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, MAXP_TAG);
- ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HHEA_TAG);
- ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VHEA_TAG);
- ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, CMAP_TAG);
- if (ulEBDTTableLength > 0)
- ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, EBLC_TAG);
- if (ulBdatTableLength > 0)
- ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BLOC_TAG);
-
- *pulOutputBufferLength = ulKeepTablesLength + (uint32)(flKeepPercent * ulGlyphDependentDataLength/100);
+ ulAllGlyphsLength = ulEBDTTableLength + ulBdatTableLength;
+ ulAllGlyphsLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG);
+
+ if (usFormat == TTFDELTA_DELTA || usFormat == TTFDELTA_SUBSET1)
+ { /* these formats will compact some tables, discarding a percentage of these tables as well */
+ /* tables compacted */
+ ulGlyphDependentDataLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LTSH_TAG);
+ ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HMTX_TAG);
+ ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VMTX_TAG);
+ ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HDMX_TAG);
+ ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LOCA_TAG);
+ }
+ ulGlyphDependentDataLength += ulAllGlyphsLength; /* all formats will discard a percentage of the glyph data */
+
+ if (usFormat == TTFDELTA_DELTA) /* we're going to keep just a handfull of tables tables */
+ {
+ ulKeepTablesLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HEAD_TAG);
+ ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, MAXP_TAG);
+ ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HHEA_TAG);
+ ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VHEA_TAG);
+ ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, CMAP_TAG);
+ if (ulEBDTTableLength > 0)
+ ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, EBLC_TAG);
+ if (ulBdatTableLength > 0)
+ ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BLOC_TAG);
+
+ *pulOutputBufferLength = ulKeepTablesLength + (uint32)(flKeepPercent * ulGlyphDependentDataLength/100);
+ }
+ else
+ /* for straight subset, this will be: ulSrcBufferSize - (discard % * (Glyf table size + EBDT table size + bdat table size)) */
+ *pulOutputBufferLength = ulSrcBufferSize - (uint32)(flDiscardPercent * ulGlyphDependentDataLength/100);
}
- else
- /* for straight subset, this will be: ulSrcBufferSize - (discard % * (Glyf table size + EBDT table size + bdat table size)) */
- *pulOutputBufferLength = ulSrcBufferSize - (uint32)(flDiscardPercent * ulGlyphDependentDataLength/100);
+ return NO_ERROR;
}
@@ -613,8 +722,29 @@ int16 CreateDeltaTTF(CONST uint8 * puchSrcBuffer,
}
// make room for the extra glyph list
- usCharCount = usListCount + usGlyphKeepCount;
- pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(usCharCount * sizeof(CHAR_ID));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulCharCount = (uint32)usListCount + (uint32)usGlyphKeepCount;
+ if (ulCharCount > (uint32)USHRT_MAX)
+ {
+ Mem_Free(puchKeepGlyphList);
+ return ExitCleanup(ERR_PARAMETER11);
+ }
+ usCharCount = (uint16)ulCharCount;
+
+ uint32 ulCharAllocSize;
+ if (ULongMult32((uint32)usCharCount, (uint32)sizeof(CHAR_ID), &ulCharAllocSize) != S_OK)
+ {
+ Mem_Free(puchKeepGlyphList);
+ return ExitCleanup(ERR_MEM);
+ }
+ pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(ulCharAllocSize);
+ }
+ else
+ {
+ usCharCount = usListCount + usGlyphKeepCount;
+ pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(usCharCount * sizeof(CHAR_ID));
+ }
if (!pulKeepCharCodeList)
{
Mem_Free(puchKeepGlyphList);
@@ -644,7 +774,15 @@ int16 CreateDeltaTTF(CONST uint8 * puchSrcBuffer,
else
{
// allocate for extra 4 chars
- pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc((usListCount + 4) * sizeof(CHAR_ID));
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ if (usListCount > (uint16)(USHRT_MAX - 4))
+ {
+ return ERR_PARAMETER11;
+ }
+ pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(((size_t)usListCount + 4u) * sizeof(CHAR_ID));
+ } else {
+ pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc((usListCount + 4) * sizeof(CHAR_ID));
+ }
if (!pulKeepCharCodeList)
{
return ERR_MEM;
@@ -769,7 +907,15 @@ CONST_TTFACC_FILEBUFFERINFO InputBufferInfo;
if (*ppuchDestBuffer == NULL || *pulDestBufferSize == 0) /* need to allocate some memory */
{
- CalcOutputBufferSize(&InputBufferInfo, usGlyphListCount, usGlyphKeepCount, usFormat, ulSrcBufferSize, pulDestBufferSize);
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ if ((errCode = CalcOutputBufferSize(&InputBufferInfo, usGlyphListCount, usGlyphKeepCount, usFormat, ulSrcBufferSize, pulDestBufferSize)) != NO_ERROR)
+ {
+ Mem_Free(puchKeepGlyphList);
+ return ExitCleanup(errCode);
+ }
+ } else {
+ CalcOutputBufferSize(&InputBufferInfo, usGlyphListCount, usGlyphKeepCount, usFormat, ulSrcBufferSize, pulDestBufferSize);
+ }
#ifdef _DEBUG
#if !defined(ARGITERATOR_SUPPORTED) || (defined(ARGITERATOR_SUPPORTED) && ARGITERATOR_SUPPORTED)
printf("Allocating %lu bytes for output buffer.\n", *pulDestBufferSize);
@@ -896,7 +1042,15 @@ CONST_TTFACC_FILEBUFFERINFO InputBufferInfo;
if (errCode == NO_ERROR)
{
/* now we need to allocate an array to keep a list of the actual glyphs we are keeping in the font */
- pusGlyphIndexArray = (uint16 *)Mem_Alloc(usDttfGlyphIndexCount * sizeof(*pusGlyphIndexArray)); /* big as we would ever need */
+ if (TTF_SAFE_CHECKS_ENABLED()) {
+ uint32 ulGlyphArrayAllocSize;
+ if (ULongMult32((uint32)usDttfGlyphIndexCount, (uint32)sizeof(*pusGlyphIndexArray), &ulGlyphArrayAllocSize) != S_OK)
+ errCode = ERR_MEM;
+ else
+ pusGlyphIndexArray = (uint16 *)Mem_Alloc(ulGlyphArrayAllocSize);
+ } else {
+ pusGlyphIndexArray = (uint16 *)Mem_Alloc(usDttfGlyphIndexCount * sizeof(*pusGlyphIndexArray));
+ }
if (pusGlyphIndexArray == NULL)
errCode = ERR_MEM;
else
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp
index 54f3800a14d..f3bc5b7bae9 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp
@@ -28,6 +28,7 @@
#include "ttftabl1.h"
#include "ttfcntrl.h"
#include "ControlTableInit.h"
+#include "ttf_safe_checks.h"
/* if the _INDEX defines are changed, the Control_Table array below must be updated to match */
@@ -251,8 +252,19 @@ uint32 ulLength;
for ( ul = 0; ul < (ulLength+3) / 4; ul++ )
{
- if ( ReadLong( pInputBufferInfo, &ulWord, ulOffset + ul * sizeof(uint32)) != 0 )
- break;
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulReadOffset = ulOffset + ul * sizeof(uint32);
+ if (ulReadOffset < ulOffset) /* overflow check */
+ break;
+ if ( ReadLong( pInputBufferInfo, &ulWord, ulReadOffset) != 0 )
+ break;
+ }
+ else
+ {
+ if ( ReadLong( pInputBufferInfo, &ulWord, ulOffset + ul * sizeof(uint32)) != 0 )
+ break;
+ }
*pulChecksum = *pulChecksum + ulWord;
}
return ulOffset; /* any non zero number will do */
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp
index cbb2de39061..89dc68877f1 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp
@@ -28,6 +28,8 @@
#include "ttfdelta.h" /* for Dont care info */
#include "ttferror.h"
#include "ttfdcnfg.h"
+#include "intsafe_private_copy.h"
+#include "ttf_safe_checks.h"
/* ---------------------------------------------------------------------- */
PRIVATE int CRTCB AscendingTagCompare( CONST void *arg1, CONST void *arg2 )
@@ -269,6 +271,11 @@ uint32 ulBytesRead;
}
else
{
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (ulGlyphCount + 1 > 0xFFFF)
+ return 0L;
+ }
if (ReadGenericRepeat(pInputBufferInfo, (uint8 *)pulLoca, LONG_CONTROL, ulOffset, &ulBytesRead, (uint16) (ulGlyphCount + 1), sizeof(uint32)) != NO_ERROR)
return 0L;
}
@@ -315,9 +322,17 @@ FORMAT4_SEGMENTS KeySegment;
sIDIdx = (int32)(pFormat4Segment - (Format4Segments + usnSegments));
/* sIDIdx = (uint16) i - (uint16) usnSegments; */
sIDIdx += (int32) (pFormat4Segment->idRangeOffset / 2) + usCharCode - pFormat4Segment->startCount;
- /* check against bounds */
- if (sIDIdx >= usnGlyphs)
- return INVALID_GLYPH_INDEX;
+ /* check against bounds (both negative and too large) */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ if (sIDIdx < 0 || sIDIdx >= usnGlyphs)
+ return INVALID_GLYPH_INDEX;
+ }
+ else
+ {
+ if (sIDIdx >= usnGlyphs)
+ return INVALID_GLYPH_INDEX;
+ }
usGlyphIdx = GlyphId[ sIDIdx ];
if (usGlyphIdx)
/* Only add in idDelta if we've really got a glyph! */
@@ -401,7 +416,17 @@ int16 errCode;
if ( *pusnIds == 0 )
return(NO_ERROR);
- *ppGlyphId = (GLYPH_ID *)Mem_Alloc(*pusnIds * sizeof( (*ppGlyphId)[0] ));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)*pusnIds, (uint32)sizeof( (*ppGlyphId)[0] ), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ *ppGlyphId = (GLYPH_ID *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ *ppGlyphId = (GLYPH_ID *)Mem_Alloc(*pusnIds * sizeof( (*ppGlyphId)[0] ));
+ }
if ( *ppGlyphId == NULL )
return(ERR_MEM);
@@ -431,7 +456,17 @@ uint32 ulBytesRead;
/* allocate memory for variable length part of table */
- *Format4Segments = (FORMAT4_SEGMENTS *)Mem_Alloc( usSegCount * SIZEOF_FORMAT4_SEGMENTS);
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usSegCount, (uint32)SIZEOF_FORMAT4_SEGMENTS, &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ *Format4Segments = (FORMAT4_SEGMENTS *)Mem_Alloc( ulAllocSize );
+ }
+ else
+ {
+ *Format4Segments = (FORMAT4_SEGMENTS *)Mem_Alloc( usSegCount * SIZEOF_FORMAT4_SEGMENTS);
+ }
if ( *Format4Segments == NULL )
return( ERR_MEM );
@@ -661,7 +696,17 @@ int16 errCode;
if (pCmap->format != FORMAT6_CMAP_FORMAT)
return( ERR_FORMAT );
- *glyphIndexArray = (uint16 *)Mem_Alloc( pCmap->entryCount * sizeof( uint16 ));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)pCmap->entryCount, (uint32)sizeof( uint16 ), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ *glyphIndexArray = (uint16 *)Mem_Alloc( ulAllocSize );
+ }
+ else
+ {
+ *glyphIndexArray = (uint16 *)Mem_Alloc( pCmap->entryCount * sizeof( uint16 ));
+ }
if ( *glyphIndexArray == NULL )
return( ERR_MEM );
@@ -1030,7 +1075,20 @@ int16 errCode = NO_ERROR;
usCharCodeCount += (pFormat4Segments[ i ].endCount - pFormat4Segments[ i ].startCount + 1);
}
- *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST)Mem_Alloc(usCharCodeCount * sizeof(**ppCharGlyphMapList));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usCharCodeCount, (uint32)sizeof(**ppCharGlyphMapList), &ulAllocSize) != S_OK)
+ {
+ FreeCmapFormat4(pFormat4Segments, pFormat4GlyphIdArray);
+ return ERR_MEM;
+ }
+ *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST)Mem_Alloc(usCharCodeCount * sizeof(**ppCharGlyphMapList));
+ }
if (*ppCharGlyphMapList == NULL)
{
FreeCmapFormat4(pFormat4Segments, pFormat4GlyphIdArray);
@@ -1134,7 +1192,20 @@ int16 errCode = NO_ERROR;
ulCharCodeCount += (pFormat12Groups[ i ].endCharCode - pFormat12Groups[ i ].startCharCode + 1);
}
- *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST_EX)Mem_Alloc(ulCharCodeCount * sizeof(**ppCharGlyphMapList));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32(ulCharCodeCount, (uint32)sizeof(**ppCharGlyphMapList), &ulAllocSize) != S_OK)
+ {
+ FreeCmapFormat12Groups( pFormat12Groups );
+ return ERR_MEM;
+ }
+ *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST_EX)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST_EX)Mem_Alloc(ulCharCodeCount * sizeof(**ppCharGlyphMapList));
+ }
if (*ppCharGlyphMapList == NULL)
{
FreeCmapFormat12Groups( pFormat12Groups );
@@ -1658,7 +1729,17 @@ char *pStr1, *pStr2; /* temps to point to either new or old string from PNAMEREC
ulOffset = ulNameOffset + GetGenericSize(NAME_HEADER_CONTROL);
/* first create the NameRecordStrings array to sort */
- pNameRecordStrings = (NAMERECORDSTRINGS *)Mem_Alloc(NameRecordCount * sizeof(*pNameRecordStrings));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)NameRecordCount, (uint32)sizeof(*pNameRecordStrings), &ulAllocSize) != S_OK)
+ return ERR_GENERIC;
+ pNameRecordStrings = (NAMERECORDSTRINGS *)Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ pNameRecordStrings = (NAMERECORDSTRINGS *)Mem_Alloc(NameRecordCount * sizeof(*pNameRecordStrings));
+ }
if (pNameRecordStrings == NULL)
return ERR_MEM;
@@ -1845,7 +1926,17 @@ int32 lCopySize;
ulOffset += usBytesRead;
- aDirectory = (DIRECTORY *) Mem_Alloc(((int32)usnNewTables) * sizeof(DIRECTORY)); /* one extra for new table */
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usnNewTables, (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ aDirectory = (DIRECTORY *) Mem_Alloc(((int32)usnNewTables) * sizeof(DIRECTORY)); /* one extra for new table */
+ }
if (aDirectory == NULL)
return(ERR_MEM);
@@ -2150,7 +2241,17 @@ int16 errCode;
ulOffset += usBytesRead;
/* Create a list of valid tables */
- aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY));
+ if (TTF_SAFE_CHECKS_ENABLED())
+ {
+ uint32 ulAllocSize;
+ if (ULongMult32((uint32)usnTables, (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK)
+ return ERR_MEM;
+ aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize);
+ }
+ else
+ {
+ aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY));
+ }
if (aDirectory == NULL)
return(ERR_MEM);
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp
index 28ca4ab6f4e..3bec436548b 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp
@@ -57,16 +57,37 @@ using MS::Internal::TtfDelta::Mem_Free;
using MS::Internal::TtfDelta::Mem_Alloc;
using MS::Internal::TtfDelta::Mem_ReAlloc;
using MS::Internal::TtfDelta::CreateDeltaTTF;
+using MS::Internal::TtfDelta::g_fDWFBoundsCheckEnabled;
namespace MS { namespace Internal {
array ^ TrueTypeSubsetter::ComputeSubset(void * fontData, int fileSize, System::Uri ^ sourceUri, int directoryOffset, array ^ glyphArray)
{
+ // Initialize the bounds check switch from AppContext (once).
+ static bool s_switchInitialized = false;
+ if (!s_switchInitialized)
+ {
+ s_switchInitialized = true;
+ bool switchValue = false;
+ System::AppContext::TryGetSwitch(
+ "Switch.MS.Internal.TtfDelta.DisableDirectWriteForwarderBoundsCheckProtection",
+ switchValue);
+ MS::Internal::TtfDelta::g_fDWFBoundsCheckEnabled = switchValue ? 0 : 1;
+ }
+
uint8 * puchDestBuffer = NULL;
unsigned long ulDestBufferSize = 0, ulBytesWritten = 0;
assert(glyphArray != nullptr && glyphArray->Length > 0 && glyphArray->Length <= USHRT_MAX);
+ if ((g_fDWFBoundsCheckEnabled != 0))
+ {
+ if (fileSize <= 0)
+ {
+ throw gcnew FileFormatException(sourceUri);
+ }
+ }
+
pin_ptr pinnedGlyphArray = &glyphArray[0];
int16 errCode = CreateDeltaTTF(
static_cast(fontData),
@@ -91,10 +112,25 @@ array ^ TrueTypeSubsetter::ComputeSubset(void * fontData, int file
try
{
- if (errCode == NO_ERROR)
+ if ((g_fDWFBoundsCheckEnabled != 0))
+ {
+ if (errCode == NO_ERROR && ulBytesWritten <= INT_MAX)
+ {
+ retArray = gcnew array(ulBytesWritten);
+ System::Runtime::InteropServices::Marshal::Copy((System::IntPtr)puchDestBuffer, retArray, 0, ulBytesWritten);
+ }
+ else if (errCode == NO_ERROR)
+ {
+ errCode = static_cast(ERR_GENERIC);
+ }
+ }
+ else
{
- retArray = gcnew array(ulBytesWritten);
- System::Runtime::InteropServices::Marshal::Copy((System::IntPtr)puchDestBuffer, retArray, 0, ulBytesWritten);
+ if (errCode == NO_ERROR)
+ {
+ retArray = gcnew array(ulBytesWritten);
+ System::Runtime::InteropServices::Marshal::Copy((System::IntPtr)puchDestBuffer, retArray, 0, ulBytesWritten);
+ }
}
}
finally
diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp
index 61ff8727d81..63426a64279 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp
@@ -13,6 +13,7 @@
// We cannot simply put this namespace specification in these 2 header files
// or elase we will break the compilation of truetype subsetter.
namespace MS { namespace Internal { namespace TtfDelta {
+int g_fDWFBoundsCheckEnabled = 1; // definition for linker (initialized in truetype.cpp)
#include "CPP\TrueTypeSubsetter\TtfDelta\GlobalInit.h"
#include "CPP\TrueTypeSubsetter\TtfDelta\ControlTableInit.h"
}}} // namespace MS::Internal::TtfDelta
diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp
index 37ef3140bbd..8d774fa0e42 100644
--- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp
@@ -216,3 +216,14 @@ STDMETHODIMP CPimcManagerFactory::LockServer(BOOL fLock)
}
#endif // WANT_SINGLETON
+/////////////////////////////////////////////////////////////////////////////
+// Security mitigation switch - static storage and exported setter
+
+#include "PenImcSwitches.h"
+
+bool PenImcSwitches::s_boundsCheckDisabled = false;
+
+extern "C" void WINAPI SetDisablePenImcBoundsCheckProtection(BOOL fDisable)
+{
+ PenImcSwitches::SetPenImcBoundsCheckProtectionDisabled(!!fDisable);
+}
diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def
index 193a703c902..ec3ce6c124d 100644
--- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def
+++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def
@@ -22,4 +22,5 @@ EXPORTS
LockWispObjectFromGit PRIVATE
UnlockWispObjectFromGit PRIVATE
RegisterDllForSxSCOM PRIVATE
+ SetDisablePenImcBoundsCheckProtection PRIVATE
diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImcSwitches.h b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImcSwitches.h
new file mode 100644
index 00000000000..fcb5c4effc3
--- /dev/null
+++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImcSwitches.h
@@ -0,0 +1,22 @@
+#pragma once
+
+///
+/// Switch for PenImc security fixes, set from managed CoreAppContextSwitches
+/// via P/Invoke at startup.
+///
+class PenImcSwitches
+{
+public:
+ static bool IsPenImcBoundsCheckProtectionDisabled()
+ {
+ return s_boundsCheckDisabled;
+ }
+
+ static void SetPenImcBoundsCheckProtectionDisabled(bool disabled)
+ {
+ s_boundsCheckDisabled = disabled;
+ }
+
+private:
+ static bool s_boundsCheckDisabled;
+};
diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp
index 9578b17934e..454be79de5a 100644
--- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp
@@ -12,6 +12,9 @@
#include "PimcContext.h"
#include "..\tablib\sidutils.h"
#include "..\tablib\scopes.h"
+#include
+
+#include "PenImcSwitches.h"
using namespace ComUtils;
@@ -524,7 +527,16 @@ HRESULT CPimcContext::EnsurePackets(DWORD cb)
{
if (m_pbPackets)
delete [] m_pbPackets;
- m_cbPackets = max(256, cb * 2);
+ if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled())
+ {
+ UINT cbDoubled;
+ CHR(UIntMult(cb, 2, &cbDoubled));
+ m_cbPackets = max(256, (DWORD)cbDoubled);
+ }
+ else
+ {
+ m_cbPackets = max(256, cb * 2);
+ }
CHR_MEMALLOC(m_pbPackets = new BYTE[m_cbPackets]);
}
CLEANUP:
diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp
index 1cb2d9f4901..4f975793d02 100644
--- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp
@@ -10,6 +10,7 @@
#include "PimcTablet.h"
#include
#include
+#include "PenImcSwitches.h"
using namespace ComUtils;
@@ -46,6 +47,11 @@ static const WCHAR* MOUSEDEVICE_BUTTON_ONE_NAME = L"Tip Switch";
static const WCHAR* MOUSEDEVICE_BUTTON_TWO_NAME = L"Barrel Switch";
static const WCHAR* MOUSEDEVICE_PLUGANDPLAYID = L"SCREEN";
+// Reasonable upper bounds for COM-returned counts to guard against
+// integer overflow in allocation size calculations.
+static const DWORD MAX_TABLET_CURSORS = 128;
+static const DWORD MAX_CURSOR_BUTTONS = 64;
+
static void EnsureNoDuplicateGUIDs(__in GUID *pGUID, __inout ULONG &cGUID)
{
ULONG iIndex = 0;
@@ -545,6 +551,10 @@ STDMETHODIMP CPimcTablet::RefreshCursorInfo()
if (m_pTabS)
{
CHR(m_pTabS->GetCursorCount(&m_cCursors));
+ if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled())
+ {
+ CHR(m_cCursors <= MAX_TABLET_CURSORS ? S_OK : E_UNEXPECTED);
+ }
m_apCursorInfo = new PCURSORINFO[m_cCursors]();
CHR(m_apCursorInfo ? S_OK : E_OUTOFMEMORY);
@@ -566,6 +576,10 @@ STDMETHODIMP CPimcTablet::RefreshCursorInfo()
DWORD cButtons;
CHR(pCursorS->GetButtonCount(&cButtons));
+ if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled())
+ {
+ CHR(cButtons <= MAX_CURSOR_BUTTONS ? S_OK : E_UNEXPECTED);
+ }
pCursorInfo->cButtons = cButtons;
pCursorInfo->apButtonInfo = new PCURSORBUTTONINFO[cButtons]();
@@ -839,7 +853,14 @@ STDMETHODIMP CPimcTablet::IsPropertySupported(GUID guid, __out BOOL * pfSupporte
DHR;
CHR(pfSupported ? S_OK : E_INVALIDARG);
PROPERTY_METRICS metric;
- *pfSupported = S_OK == m_pTabS->GetPropertyMetrics(guid, &metric);
+ if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled())
+ {
+ *pfSupported = m_pTabS ? (S_OK == m_pTabS->GetPropertyMetrics(guid, &metric)) : FALSE;
+ }
+ else
+ {
+ *pfSupported = S_OK == m_pTabS->GetPropertyMetrics(guid, &metric);
+ }
CLEANUP:
RHR;
}
diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs
index e3bf8b4934f..3c6dcfb2e09 100644
--- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs
+++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs
@@ -81,6 +81,9 @@ internal static class UnsafeNativeMethods
[DllImport(ExternDll.Penimc, CharSet=CharSet.Auto)]
internal static extern IntPtr RegisterDllForSxSCOM();
+ [DllImport(ExternDll.Penimc, CharSet = CharSet.Auto)]
+ internal static extern void SetDisablePenImcBoundsCheckProtection([MarshalAs(UnmanagedType.Bool)] bool value);
+
#endregion
///
@@ -107,6 +110,9 @@ internal static void EnsurePenImcClassesActivated()
{
throw new InvalidOperationException(SR.Format(SR.PenImcSxSRegistrationFailed, ExternDll.Penimc));
}
+
+ // Pass security mitigation switch to native PenImc code.
+ SetDisablePenImcBoundsCheckProtection(CoreAppContextSwitches.DisablePenImcBoundsCheckProtection);
}
}
diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs
index ed8253043c2..bb9e37aced9 100644
--- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs
+++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs
@@ -401,5 +401,50 @@ public static bool DisableSpecialCharacterLigature
#endregion
+ #region DisableDirectWriteForwarderBoundsCheckProtection
+
+ internal const string DisableDirectWriteForwarderBoundsCheckProtectionSwitchName = "Switch.MS.Internal.TtfDelta.DisableDirectWriteForwarderBoundsCheckProtection";
+ private static int _disableDirectWriteForwarderBoundsCheckProtection;
+ public static bool DisableDirectWriteForwarderBoundsCheckProtection
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(DisableDirectWriteForwarderBoundsCheckProtectionSwitchName, ref _disableDirectWriteForwarderBoundsCheckProtection);
+ }
+ }
+
+ #endregion
+
+ #region DisablePenImcBoundsCheckProtection
+
+ internal const string DisablePenImcBoundsCheckProtectionSwitchName = "Switch.MS.Internal.PenImc.DisablePenImcBoundsCheckProtection";
+ private static int _disablePenImcBoundsCheckProtection;
+ public static bool DisablePenImcBoundsCheckProtection
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(DisablePenImcBoundsCheckProtectionSwitchName, ref _disablePenImcBoundsCheckProtection);
+ }
+ }
+
+ #endregion
+
+ #region DisableWpfGfxBoundsCheckProtection
+
+ internal const string DisableWpfGfxBoundsCheckProtectionSwitchName = "Switch.MS.Internal.WpfGfx.DisableWpfGfxBoundsCheckProtection";
+ private static int _disableWpfGfxBoundsCheckProtection;
+ public static bool DisableWpfGfxBoundsCheckProtection
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(DisableWpfGfxBoundsCheckProtectionSwitchName, ref _disableWpfGfxBoundsCheckProtection);
+ }
+ }
+
+ #endregion
+
}
}
diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs
index 40edd7976b3..b415076cacd 100644
--- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs
+++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs
@@ -67,6 +67,9 @@ public static bool Startup(MediaContext mc)
s_refCount++;
}
+ // Pass security mitigation switch to native WpfGfx code.
+ UnsafeNativeMethods.WpfGfx_SetDisableBoundsCheckProtection(CoreAppContextSwitches.DisableWpfGfxBoundsCheckProtection);
+
// Setting renderOption for Hardware acceleration in RDP as per appcontext switch.
UnsafeNativeMethods.RenderOptions_EnableHardwareAccelerationInRdp(CoreAppContextSwitches.EnableHardwareAccelerationInRdp);
diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs
index a17613aec1c..a8d004ddc54 100644
--- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs
+++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs
@@ -195,6 +195,9 @@ internal static extern unsafe void RenderOptions_ForceSoftwareRenderingModeForPr
[DllImport(DllImport.MilCore, EntryPoint = "RenderOptions_IsSoftwareRenderingForcedForProcess")]
internal static extern unsafe bool RenderOptions_IsSoftwareRenderingForcedForProcess();
+ [DllImport(DllImport.MilCore, EntryPoint = "WpfGfx_SetDisableBoundsCheckProtection")]
+ internal static extern unsafe void WpfGfx_SetDisableBoundsCheckProtection(bool value);
+
[DllImport(DllImport.MilCore, EntryPoint = "RenderOptions_EnableHardwareAccelerationInRdp")]
internal static extern unsafe void RenderOptions_EnableHardwareAccelerationInRdp(bool value);
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp
index 4ded9028ff9..dbf5945d138 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp
@@ -21,6 +21,7 @@
**************************************************************************/
#include "precomp.hpp"
+#include "..\shared\WpfGfxSwitches.h"
MtDefine(CEffectList, MILRender, "CEffectList");
@@ -320,16 +321,47 @@ CEffectList::GetParameters(
API_ENTRY_NOFPU(IMILEffectList::GetParameters);
HRESULT hr = S_OK;
- UINT uiSize = m_rgParamBlock[idxEffect].cbParamSize;
- if (idxEffect >= (UINT)m_rgParamBlock.GetCount() ||
- size < uiSize ||
- pData == NULL)
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
{
- IFC(E_INVALIDARG);
+ if (idxEffect >= (UINT)m_rgParamBlock.GetCount() ||
+ pData == NULL)
+ {
+ IFC(E_INVALIDARG);
+ }
+
+ UINT uiSize = m_rgParamBlock[idxEffect].cbParamSize;
+ if (size < uiSize)
+ {
+ IFC(E_INVALIDARG);
+ }
+
+ UINT cbParamOffset = m_rgParamBlock[idxEffect].cbParamOffset;
+ UINT cbDataBlockSize = m_rgDataBlock.GetCount();
+ UINT cbEndOffset;
+
+ // Validate that offset + size does not exceed data block bounds
+ if (FAILED(UIntAdd(cbParamOffset, uiSize, &cbEndOffset)) ||
+ cbEndOffset > cbDataBlockSize)
+ {
+ IFC(E_INVALIDARG);
+ }
+
+ void* pParamData = m_rgDataBlock.GetDataBuffer() + cbParamOffset;
+ GpMemcpy(pData, pParamData, uiSize);
}
+ else
+ {
+ UINT uiSize = m_rgParamBlock[idxEffect].cbParamSize;
+ if (idxEffect >= (UINT)m_rgParamBlock.GetCount() ||
+ size < uiSize ||
+ pData == NULL)
+ {
+ IFC(E_INVALIDARG);
+ }
- void* pParamData = m_rgDataBlock.GetDataBuffer() + m_rgParamBlock[idxEffect].cbParamOffset;
- GpMemcpy(pData, pParamData, uiSize);
+ void* pParamData = m_rgDataBlock.GetDataBuffer() + m_rgParamBlock[idxEffect].cbParamOffset;
+ GpMemcpy(pData, pParamData, uiSize);
+ }
Cleanup:
API_CHECK(hr);
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp
index 67235c49dc3..8129b289e1b 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp
@@ -40,6 +40,7 @@
//
#include "precomp.hpp"
+#include "..\shared\WpfGfxSwitches.h"
//+-----------------------------------------------------------------------------
//
@@ -84,8 +85,17 @@ Convert_1_32bppARGB(
UINT n, bits;
- ARGB c0 = ppal->Entries[0];
- ARGB c1 = ppal->Entries[1];
+ ARGB c0 = 0, c1 = 0;
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ c0 = ppal->Count > 0 ? ppal->Entries[0] : 0;
+ c1 = ppal->Count > 1 ? ppal->Entries[1] : 0;
+ }
+ else
+ {
+ c0 = ppal->Entries[0];
+ c1 = ppal->Entries[1];
+ }
// NOTE: We choose code size over speed here
@@ -149,6 +159,7 @@ Convert_4_32bppARGB(
Assert(ppal);
const ARGB* colors = ppal->Entries;
+ UINT paletteCount = ppal->Count;
UINT n = uiCount >> 1;
// Handle whole bytes
@@ -160,8 +171,20 @@ Convert_4_32bppARGB(
Assert((bits >> 4) < ppal->Count);
Assert((bits & 0xf) < ppal->Count);
- pDest[0] = colors[bits >> 4];
- pDest[1] = colors[bits & 0xf];
+ UINT hiNibble = bits >> 4;
+ UINT loNibble = bits & 0xf;
+
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ // Clamp indices to valid palette range to prevent OOB read
+ pDest[0] = hiNibble < paletteCount ? colors[hiNibble] : 0;
+ pDest[1] = loNibble < paletteCount ? colors[loNibble] : 0;
+ }
+ else
+ {
+ pDest[0] = colors[hiNibble];
+ pDest[1] = colors[loNibble];
+ }
pDest += 2;
}
@@ -169,7 +192,17 @@ Convert_4_32bppARGB(
// Handle the last odd nibble, if any
if (uiCount & 1)
- *pDest = colors[*pSrc >> 4];
+ {
+ UINT lastNibble = *pSrc >> 4;
+ if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ *pDest = lastNibble < paletteCount ? colors[lastNibble] : 0;
+ }
+ else
+ {
+ *pDest = colors[lastNibble];
+ }
+ }
}
@@ -186,6 +219,7 @@ Convert_2_32bppARGB(
const ColorPalette *ppal = DYNCAST(OSDPalette, pSOP->m_posd)->m_pPalette;
Assert(ppal);
+ UINT paletteCount = ppal->Count;
const ARGB* colors = ppal->Entries;
@@ -205,7 +239,14 @@ Convert_2_32bppARGB(
Assert(i < ppal->Count);
- * pDest++ = colors[i];
+ if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ *pDest++ = i < paletteCount ? colors[i] : 0;
+ }
+ else
+ {
+ *pDest++ = colors[i];
+ }
c --;
}
@@ -226,19 +267,29 @@ Convert_8_32bppARGB(
const ColorPalette *ppal = DYNCAST(OSDPalette, pSOP->m_posd)->m_pPalette;
Assert(ppal);
+ UINT paletteCount = ppal->Count;
const ARGB* colors = ppal->Entries;
while (uiCount--)
{
+ BYTE index = *pSrc++;
#if DBG
- if (*pSrc >= ppal->Count)
+ if (index >= paletteCount)
{
TraceTag((tagMILWarning,
"Palette missing entries on conversion from 8bpp to 32bppARGB"));
}
#endif
- *pDest++ = colors[*pSrc++];
+
+ if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ *pDest++ = index < paletteCount ? colors[index] : 0;
+ }
+ else
+ {
+ *pDest++ = colors[index];
+ }
}
}
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.cpp
new file mode 100644
index 00000000000..189817c241f
--- /dev/null
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.cpp
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include
+#include "WpfGfxSwitches.h"
+
+// Static storage for WpfGfxSwitches
+bool WpfGfxSwitches::g_fWpfGfxBoundsCheckProtectionDisabled = false;
+
+void WINAPI
+WpfGfx_SetDisableBoundsCheckProtection(BOOL fDisable)
+{
+ WpfGfxSwitches::SetWpfGfxBoundsCheckProtectionDisabled(!!fDisable);
+}
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.h b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.h
new file mode 100644
index 00000000000..e15b5f9865b
--- /dev/null
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.h
@@ -0,0 +1,22 @@
+#pragma once
+
+///
+/// Switch for WpfGfx security fixes, set from managed CoreAppContextSwitches
+/// via P/Invoke at startup.
+///
+class WpfGfxSwitches
+{
+public:
+ static bool IsWpfGfxBoundsCheckProtectionDisabled()
+ {
+ return g_fWpfGfxBoundsCheckProtectionDisabled;
+ }
+
+ static void SetWpfGfxBoundsCheckProtectionDisabled(bool disabled)
+ {
+ g_fWpfGfxBoundsCheckProtectionDisabled = disabled;
+ }
+
+private:
+ static bool g_fWpfGfxBoundsCheckProtectionDisabled;
+};
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h
index c65ae22fa26..927e9cef07e 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h
@@ -89,16 +89,30 @@ template class DynArray : public DynArray
__ecount(this->Count) T &First() const
{
__pfx_assert(Count > 0, "Buffer overflow accessing empty DynArray");
- Assert(Count > 0);
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ FreAssert(Count > 0);
+ }
+ else
+ {
+ Assert(Count > 0);
+ }
return GetDataBuffer()[0];
}
__ecount(1) T &Last() const
{
__pfx_assert(Count > 0, "Buffer overflow accessing empty DynArray");
- Assert(Count > 0);
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ FreAssert(Count > 0);
+ }
+ else
+ {
+ Assert(Count > 0);
+ }
#pragma prefast (push)
-#pragma prefast (disable: 37001 37002 37003, "This operation will not overflow becasuse of the Assert above.")
+#pragma prefast (disable: 37001 37002 37003, "This operation will not overflow because of the Assert/FreAssert above.")
return GetDataBuffer()[Count-1];
#pragma prefast (pop)
}
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h
index 00a0e0808cc..ce6a9b86dcc 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h
@@ -29,6 +29,7 @@
#include "refcountbase.h"
#include "arithmetic.h"
#include "dynarrayimpl.h"
+#include "WpfGfxSwitches.h"
#include "dynarray.h"
#include "heap.h"
#include "resourcecache.h"
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj
index d20cf37c3ad..8d2cb7bcb1c 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj
@@ -71,6 +71,7 @@
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp
index ba3244c453f..13b0cd49710 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp
@@ -230,7 +230,7 @@ CCommonRegistryData::InitializeFromRegistry()
}
}
- // NOTICE-2006/07/19-milesc Given that most of the registry keys previously
+ // NOTICE-2006/07/19-milesc Given that most of the registry keys previously
// in the class were not registry keys we wanted to ship, this class no longer
// accesses the registry for all keys. Instead default values are returned
// from the public functions for those keys we didn't want to ship with.
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp
index b16b6d203d2..4ba1608a3eb 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp
@@ -1176,7 +1176,7 @@ CGradientTextureGenerator::SetFirstStop(
Assert(uStopCount <= MAX_GRADIENTSTOP_COUNT);
UINT uCurrentIndex;
-
+
//
// This method handles all possible cominations to determine the gradient stop at 0.0
//
@@ -1451,9 +1451,10 @@ CGradientTextureGenerator::SetLastStop(
Assert(uStopCount >= 2);
Assert(uStopCount <= MAX_GRADIENTSTOP_COUNT);
+
//
// See the comment in SetFirstStop for the URL containing the Spec Case #'s
- // This method handles the remaining cominations of stops to determine the
+ // This method handles the remaining cominations of stops to determine the
// gradient stop at 1.0, including:
//
// 1. All stops are < 1.0 (Spec case 8)
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def
index 518ecd99426..9b4a44aa079 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def
@@ -137,5 +137,6 @@ EXPORTS
RenderOptions_ForceSoftwareRenderingModeForProcess
RenderOptions_IsSoftwareRenderingForcedForProcess
+ WpfGfx_SetDisableBoundsCheckProtection
RenderOptions_EnableHardwareAccelerationInRdp
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp
index fb7b1fdb0ba..29355c75192 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp
@@ -343,9 +343,21 @@ HRESULT CD3DGlyphBank::RectFillAlpha(
// pDst00 points to the texel in destination that corresponds
// to point (x,y) = (0,0) in source array
- const BYTE *pSrc00 = pSrcData
- - srcPitch*fullDataRect.top
- - fullDataRect.left;
+ // Use 64-bit arithmetic to avoid integer overflow when srcPitch * fullDataRect.top
+ // exceeds INT32 range (possible with large ClearType glyphs where srcPitch = width*3).
+ const BYTE *pSrc00;
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ pSrc00 = pSrcData
+ - (INT64)srcPitch*fullDataRect.top
+ - fullDataRect.left;
+ }
+ else
+ {
+ pSrc00 = pSrcData
+ - srcPitch*fullDataRect.top
+ - fullDataRect.left;
+ }
// pSrc00 points to (x,y) = (0,0) in given data array
int y;
@@ -365,7 +377,15 @@ HRESULT CD3DGlyphBank::RectFillAlpha(
for (; y < ymax; y++)
{
BYTE* pDstRow = pDst00 + lockedRect.Pitch*y;
- const BYTE* pSrcRow = pSrc00 + srcPitch*y;
+ const BYTE* pSrcRow;
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ pSrcRow = pSrc00 + (INT64)srcPitch*y;
+ }
+ else
+ {
+ pSrcRow = pSrc00 + srcPitch*y;
+ }
memset(pDstRow + srcRect.left, 0, xmin - srcRect.left);
memcpy(pDstRow + xmin, pSrcRow + xmin, xmax - xmin);
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp
index 73785e9e942..8d77ba689b2 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp
@@ -3716,7 +3716,14 @@ CHwBitmapColorSource::PushTheSourceBitsToVideoMemory(
rcMilTextureLock.Y = 0;
rcMilTextureLock.Width = static_cast(m_d3dsdRequired.Width);
rcMilTextureLock.Height = static_cast(m_d3dsdRequired.Height);
- cbLockedBufferSize = GetRequiredBufferSize(m_fmtTexture, d3dlrBitmapCopyDestination.Pitch, &rcMilTextureLock);
+ if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ IFC(HrGetRequiredBufferSize(m_fmtTexture, d3dlrBitmapCopyDestination.Pitch, &rcMilTextureLock, &cbLockedBufferSize));
+ }
+ else
+ {
+ cbLockedBufferSize = GetRequiredBufferSize(m_fmtTexture, d3dlrBitmapCopyDestination.Pitch, &rcMilTextureLock);
+ }
fLockedSurface = true;
}
@@ -3774,16 +3781,49 @@ CHwBitmapColorSource::PushTheSourceBitsToVideoMemory(
rcDirty.left, rcDirty.top, rcDirty.right - rcDirty.left, rcDirty.bottom - rcDirty.top
};
- BYTE *pvDestPixels = reinterpret_cast(d3dlrBitmapCopyDestination.pBits)
- + uPixelSize * static_cast(ptDest.x)
- + d3dlrBitmapCopyDestination.Pitch * ptDest.y +
- // Offset according to border.
- uBorderSize * (uPixelSize + d3dlrBitmapCopyDestination.Pitch);
+ BYTE *pvDestPixels;
+ UINT cbRemainingBufferSize;
+
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ // Compute destination offset with overflow-safe arithmetic.
+ UINT uDestOffsetX;
+ UINT uDestOffsetY;
+ UINT uDestOffset;
+ UINT uBorderOffset;
+
+ IFC(UIntMult(uPixelSize, static_cast(ptDest.x), &uDestOffsetX));
+ IFC(UIntMult(static_cast(d3dlrBitmapCopyDestination.Pitch), static_cast(ptDest.y), &uDestOffsetY));
+ IFC(UIntAdd(uDestOffsetX, uDestOffsetY, &uDestOffset));
+
+ // Border offset: uBorderSize * (uPixelSize + Pitch)
+ IFC(UIntAdd(uPixelSize, static_cast(d3dlrBitmapCopyDestination.Pitch), &uBorderOffset));
+ IFC(UIntMult(uBorderSize, uBorderOffset, &uBorderOffset));
+ IFC(UIntAdd(uDestOffset, uBorderOffset, &uDestOffset));
+
+ // Verify the offset doesn't exceed the locked buffer
+ if (uDestOffset >= cbLockedBufferSize)
+ {
+ IFC(WGXERR_INTERNALERROR);
+ }
+
+ pvDestPixels = reinterpret_cast(d3dlrBitmapCopyDestination.pBits)
+ + uDestOffset;
+ cbRemainingBufferSize = cbLockedBufferSize - uDestOffset;
+ }
+ else
+ {
+ pvDestPixels = reinterpret_cast(d3dlrBitmapCopyDestination.pBits)
+ + uPixelSize * static_cast(ptDest.x)
+ + d3dlrBitmapCopyDestination.Pitch * ptDest.y +
+ uBorderSize * (uPixelSize + d3dlrBitmapCopyDestination.Pitch);
+ cbRemainingBufferSize = cbLockedBufferSize;
+ }
IFC(pIBitmapSource->CopyPixels(
&rcCopy,
d3dlrBitmapCopyDestination.Pitch,
- cbLockedBufferSize,
+ cbRemainingBufferSize,
pvDestPixels
));
}
@@ -4451,7 +4491,8 @@ DbgTintDirtyRectangle(
// Function: SelfCopyPixels
//
// Synopsis: Copy source rectangle to new location (non-overlapping)
-// in image. Does not check memory!
+// in image. Validates all offsets against buffer size using
+// overflow-safe arithmetic before copying.
//
//-----------------------------------------------------------------------------
void
@@ -4468,20 +4509,52 @@ SelfCopyPixels(
__inout_bcount(cbBufferSize) BYTE *pvPixels // Pointer to start of output
)
{
- #pragma prefast(suppress: 22013, "Offset calculations may not overflow")
- UINT offReadEnd = cbStep * rc.right + cbStride * (rc.bottom-1);
- UINT offWriteEnd = cbStep * (x+rc.Width()) + cbStride * (y+rc.Height()-1);
-
- if (cbBufferSize < offReadEnd)
- {
- RIP("Buffer size too small for source rectangle");
- }
- else if (cbBufferSize < offWriteEnd)
- {
- RIP("Buffer size too small for destination rectangle");
- }
- else
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
{
+ // Compute the end offsets for both source and destination using
+ // overflow-safe arithmetic. If any multiplication or addition
+ // overflows, the bounds check will correctly reject the operation.
+ UINT offReadEnd = 0;
+ UINT offWriteEnd = 0;
+ UINT temp1, temp2;
+
+ bool fOverflow = false;
+
+ // offReadEnd = cbStep * rc.right + cbStride * (rc.bottom - 1)
+ if (rc.bottom == 0 ||
+ FAILED(UIntMult(cbStep, rc.right, &temp1)) ||
+ FAILED(UIntMult(cbStride, rc.bottom - 1, &temp2)) ||
+ FAILED(UIntAdd(temp1, temp2, &offReadEnd)))
+ {
+ fOverflow = true;
+ }
+
+ // offWriteEnd = cbStep * (x + rc.Width()) + cbStride * (y + rc.Height() - 1)
+ if (!fOverflow)
+ {
+ UINT destRight, destBottom;
+ if (FAILED(UIntAdd(x, rc.Width(), &destRight)) ||
+ FAILED(UIntMult(cbStep, destRight, &temp1)) ||
+ FAILED(UIntAdd(y, rc.Height(), &destBottom)) ||
+ destBottom == 0 ||
+ FAILED(UIntMult(cbStride, destBottom - 1, &temp2)) ||
+ FAILED(UIntAdd(temp1, temp2, &offWriteEnd)))
+ {
+ fOverflow = true;
+ }
+ }
+
+ if (fOverflow || cbBufferSize < offReadEnd)
+ {
+ RIP("Buffer size too small for source rectangle");
+ return;
+ }
+ else if (cbBufferSize < offWriteEnd)
+ {
+ RIP("Buffer size too small for destination rectangle");
+ return;
+ }
+
for (UINT i = rc.left; i < rc.right; ++i)
{
for (UINT j = rc.top; j < rc.bottom; ++j)
@@ -4495,6 +4568,36 @@ SelfCopyPixels(
}
}
}
+ else
+ {
+ #pragma prefast(suppress: 22013, "Offset calculations may not overflow")
+ UINT offReadEnd = cbStep * rc.right + cbStride * (rc.bottom-1);
+ UINT offWriteEnd = cbStep * (x+rc.Width()) + cbStride * (y+rc.Height()-1);
+
+ if (cbBufferSize < offReadEnd)
+ {
+ RIP("Buffer size too small for source rectangle");
+ }
+ else if (cbBufferSize < offWriteEnd)
+ {
+ RIP("Buffer size too small for destination rectangle");
+ }
+ else
+ {
+ for (UINT i = rc.left; i < rc.right; ++i)
+ {
+ for (UINT j = rc.top; j < rc.bottom; ++j)
+ {
+ BYTE *pvSrc = pvPixels + j * cbStride + i * cbStep;
+ BYTE *pvDst = pvPixels + ((j-rc.top)+y) * cbStride + ((i-rc.left)+x) * cbStep;
+ Assert(pvDst + cbStep <= pvPixels + cbBufferSize);
+ Assert(pvSrc + cbStep <= pvPixels + cbBufferSize);
+
+ RtlCopyMemory(pvDst, pvSrc, cbStep);
+ }
+ }
+ }
+ }
return;
}
diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp
index 7c81f299d53..8dabb56c491 100644
--- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp
@@ -1700,7 +1700,22 @@ CGlyphRunRealization::EnsureValidAlphaMap(__in const EnhancedContrastTable *pECT
CMilRectL CTBbox(clearTypeAlphaMapBoundingBox);
CMilRectL UnionBBox(BLBbox);
UnionBBox.Union(CTBbox);
- UINT32 textureSize = UnionBBox.Width() * UnionBBox.Height();
+
+ UINT32 textureSize;
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ UINT64 textureSize64 = (UINT64)UnionBBox.Width() * UnionBBox.Height();
+ if (textureSize64 > UINT32_MAX)
+ {
+ IFC(WGXERR_BADNUMBER);
+ }
+ textureSize = (UINT32)textureSize64;
+ }
+ else
+ {
+ textureSize = UnionBBox.Width() * UnionBBox.Height();
+ }
+
BYTE *pCombinedAlphaMap = (BYTE*)WPFAlloc(ProcessHeap,
Mt(GlyphBitmapClearType),
textureSize
@@ -1866,14 +1881,25 @@ CGlyphRunRealization::RealizeAlphaBoundsAndTextures(
//
UINT32 width = boundingBox.right - boundingBox.left;
UINT32 height = boundingBox.bottom - boundingBox.top;
- UINT32 textureStride = width;
+ UINT32 textureStrideU32 = width;
if (textureType == DWRITE_TEXTURE_CLEARTYPE_3x1)
{
- // ClearType bitmaps (DWRITE_TEXTURE_CLEARTYPE_3x1) contain 3 bytes per pixel,
- // Aliased bitmaps only contain 1.
- textureStride *= 3;
+ textureStrideU32 *= 3;
+ }
+ UINT32 textureSize = 0;
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ UINT64 textureSize64 = (UINT64)textureStrideU32 * height;
+ if (textureSize64 > UINT32_MAX)
+ {
+ IFC(WGXERR_BADNUMBER);
+ }
+ textureSize = (UINT32)textureSize64;
+ }
+ else
+ {
+ textureSize = textureStrideU32 * height;
}
- UINT32 textureSize = textureStride * height;
pAlphaValues = (BYTE *)WPFAlloc(ProcessHeap,
(textureType == DWRITE_TEXTURE_CLEARTYPE_3x1 ? Mt(GlyphBitmapClearType) : Mt(GlyphBitmapBiLevel)),
@@ -1902,7 +1928,7 @@ CGlyphRunRealization::RealizeAlphaBoundsAndTextures(
// pECT may be NULL if the contrast enhancement value is 0.
if (pECT)
{
- pECT->RenormalizeAndApplyContrast(pAlphaValues, boundingBox.right - boundingBox.left, boundingBox.bottom - boundingBox.top, textureStride, textureSize);
+ pECT->RenormalizeAndApplyContrast(pAlphaValues, boundingBox.right - boundingBox.left, boundingBox.bottom - boundingBox.top, textureStrideU32, textureSize);
}
}
else
@@ -1910,10 +1936,27 @@ CGlyphRunRealization::RealizeAlphaBoundsAndTextures(
// Future Consideration: probably shouldn't do this texture expansion. Need to write a different
// shader and shrink the texture to benefit perf. Aliased text is relatively rare however, so it's
// not worth the investment at this point.
- BYTE *pNewAlphaValues = (BYTE *)WPFAlloc(ProcessHeap,
- Mt(GlyphBitmapBiLevel),
- textureSize * 3);
- TraceTagText((tagError, "CGlyphRunRealization::RealizeAlphaBoundsAndTextures, allocated bytes: %d", textureSize * 3));
+ BYTE *pNewAlphaValues;
+ if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled())
+ {
+ UINT64 expandedSize64 = (UINT64)textureSize * 3;
+ if (expandedSize64 > UINT32_MAX)
+ {
+ IFC(WGXERR_BADNUMBER);
+ }
+ UINT32 expandedSize = (UINT32)expandedSize64;
+ pNewAlphaValues = (BYTE *)WPFAlloc(ProcessHeap,
+ Mt(GlyphBitmapBiLevel),
+ expandedSize);
+ TraceTagText((tagError, "CGlyphRunRealization::RealizeAlphaBoundsAndTextures, allocated bytes: %d", expandedSize));
+ }
+ else
+ {
+ pNewAlphaValues = (BYTE *)WPFAlloc(ProcessHeap,
+ Mt(GlyphBitmapBiLevel),
+ textureSize * 3);
+ TraceTagText((tagError, "CGlyphRunRealization::RealizeAlphaBoundsAndTextures, allocated bytes: %d", textureSize * 3));
+ }
for (UINT i = 0; i < textureSize; i++)
{