Skip to content

Commit

Permalink
Merged PR 4: Fix for MSRC43423 for VS 2017 version 15.0
Browse files Browse the repository at this point in the history
Block reading of resx files with "Mark of the web" if they contain "data" or "metadata" sections to avoid deserializing arbitrary data.
  • Loading branch information
Pilchie committed Jun 20, 2018
2 parents f1b283f + ab55741 commit 9257cbd
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 70 deletions.
3 changes: 0 additions & 3 deletions build/Scripts/copyOutput.cmd
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
echo Copy the Modern Vsixes manifest into VsixV3
robocopy %BinariesDirectory% %BinariesDirectory%VsixV3 Microsoft.VisualStudio.Editors.vsman Microsoft.VisualStudio.ProjectSystem.Managed.vsman /njh /njs /np /xx

echo Copy the Nugets to CoreXT Share
robocopy %BinariesDirectory%NuGetPackages \\cpvsbuild\drops\dd\nuget /njh /njs /np /xx
26 changes: 21 additions & 5 deletions build/Targets/VSL.Versions.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,34 @@
<RoslynSemanticVersion Condition="'$(RoslynSemanticVersion)' == '' AND '$(UseVisualStudioVersion)' == 'true'">15.0.1</RoslynSemanticVersion>
<RoslynSemanticVersion Condition="'$(RoslynSemanticVersion)' == ''">2.0.1</RoslynSemanticVersion>
<MicroBuildVersion>0.2.0</MicroBuildVersion>

<!-- We should not be signing a build anywhere except for in MicroBuild, which will always specify 'BUILD_BUILDNUMBER'-->
<BuildNumber Condition="'$(BuildNumber)' == ''">$(BUILD_BUILDNUMBER)</BuildNumber>
<Error Condition="'$(BuildNumber)' == '' AND '$(OfficialBuild)' == 'true'">A build number must be specified for a signed build.</Error>

<!-- When a build number is not specified, then we should default back to '00065535.0', which is a build number in the
same format as provided by MicroBuild v2, but greater than any that MicroBuild v2 will produce, and is still compatible
with the Win32 file version limitations. This is required so that builds done locally, where '$(OfficialBuild)' == 'true',
can still be deployed to VS and override the version that is globally installed. -->
<BuildNumberFiveDigitDateStamp Condition="'$(BuildNumber)' == ''">65535</BuildNumberFiveDigitDateStamp>
<BuildNumberBuildOfTheDayPadded Condition="'$(BuildNumber)' == ''">01</BuildNumberBuildOfTheDayPadded>
</PropertyGroup>

<PropertyGroup Condition="'$(BuildNumber)' != ''">
<!-- When a build number is specified, it needs to be in the format of 'x.y'-->
<Error Condition="$(BuildNumber.Split($([System.Convert]::ToString(`.`).ToCharArray())).Length) != 2">BuildNumber should have two parts (in the form of 'x.y')</Error>

<!-- Split the build parts out from the BuildNumber which is given to us by MicroBuild in the format of yyyymmdd.nn
where BuildNumberFiveDigitDateStamp is mmmdd (such as 60615) and BuildNumberBuildOfTheDay is nn (which represents the nth build
started that day). So the first build of the day, 20160615.1, will produce something similar to BuildNumberFiveDigitDateStamp: 60615,
BuildNumberBuildOfTheDayPadded: 01;and the 12th build of the day, 20160615.12, will produce BuildNumberFiveDigitDateStamp: 60615, BuildNumberBuildOfTheDay: 12
Additionally, in order ensure the value fits in the 16-bit PE header fields, we will only take the last five digits of the BuildNumber, so
in the case of 20160615, we will set BuildNumberFiveDigitDateStamp to 60615. Unfortunately for releases in 2017 we can't go any higher, so
we will continue the month counting instead: the build after 61231 is 61301. -->
<BuildNumberFiveDigitDateStamp Condition="'$(BuildNumber)' != ''">$([MSBuild]::Subtract($(BuildNumber.Split('.')[0].Substring(3).Trim()), 8800))</BuildNumberFiveDigitDateStamp>
<BuildNumberBuildOfTheDayPadded Condition="('$(BuildNumber)' != '') AND ($(BuildNumber.Split('.').Length) == 2)">$(BuildNumber.Split('.')[1].PadLeft(2,'0'))</BuildNumberBuildOfTheDayPadded>
in the case of 20160615, we will set BuildNumberFiveDigitDateStamp to 60615. Further, if this would result in a number like 71201 or 81201, we
decrement the year and add 12 to the month to extend the time. -->
<BuildNumberFiveDigitDateStamp>$([MSBuild]::Subtract($(BuildNumber.Split($([System.Convert]::ToString(`.`).ToCharArray())).GetValue($([System.Convert]::ToInt32(0)))), 20100000))</BuildNumberFiveDigitDateStamp>
<_BuildNumberFiveDigitDateStampYearsToOffset>$([System.Math]::Max($([System.Convert]::ToInt32($([MSBuild]::Subtract($([MSBuild]::Divide($(BuildNumberFiveDigitDateStamp), 10000)), 6)))), 0))</_BuildNumberFiveDigitDateStampYearsToOffset>
<BuildNumberFiveDigitDateStamp>$([MSBuild]::Subtract($([System.Convert]::ToInt32($(BuildNumberFiveDigitDateStamp))), $([MSBuild]::Multiply($(_BuildNumberFiveDigitDateStampYearsToOffset), 8800))))</BuildNumberFiveDigitDateStamp>
<BuildNumberBuildOfTheDayPadded>$(BuildNumber.Split($([System.Convert]::ToString(`.`).ToCharArray())).GetValue($([System.Convert]::ToInt32(1))).PadLeft($([System.Convert]::ToInt32(2)), $([System.Convert]::ToChar(`0`))))</BuildNumberBuildOfTheDayPadded>
</PropertyGroup>

<Choose>
Expand Down
48 changes: 48 additions & 0 deletions src/Microsoft.VisualStudio.Editors/Common/Utils.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,54 @@ Namespace Microsoft.VisualStudio.Editors.Common
Return False
End Function

Friend Function GetSecurityZoneOfFile(path As String, serviceProvider As ServiceProvider) As Security.SecurityZone
If path Is Nothing Then
Throw New ArgumentNullException("path")
End If

If Not IO.Path.IsPathRooted(path) Then
Throw CreateArgumentException("path")
End If

' Some additional verification is done by Path.GetFullPath...
Dim absPath As String = IO.Path.GetFullPath(path)

Dim internetSecurityManager As IInternetSecurityManager = Nothing

' We've got to get a fresh instance of the InternetSecurityManager, since it seems that the instance we
' can get from our ServiceProvider can't Map URLs to zones...
Dim localReg As ILocalRegistry2 = TryCast(serviceProvider.GetService(GetType(ILocalRegistry)), ILocalRegistry2)
If localReg IsNot Nothing Then
Dim ObjectPtr As IntPtr = IntPtr.Zero
Try
Static CLSID_InternetSecurityManager As New Guid("7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4")
VSErrorHandler.ThrowOnFailure(localReg.CreateInstance(CLSID_InternetSecurityManager, Nothing, NativeMethods.IID_IUnknown, win.CLSCTX_INPROC_SERVER, ObjectPtr))
internetSecurityManager = TryCast(Marshal.GetObjectForIUnknown(ObjectPtr), IInternetSecurityManager)
Catch Ex As Exception When ReportWithoutCrash(Ex, "Failed to create Interop.IInternetSecurityManager", NameOf(Utils) & "." & NameOf(GetSecurityZoneOfFile))
Finally
If ObjectPtr <> IntPtr.Zero Then
Marshal.Release(ObjectPtr)
End If
End Try
End If

If internetSecurityManager Is Nothing Then
Debug.Fail("Failed to create an InternetSecurityManager")
Throw New ApplicationException
End If

Dim zone As Integer
Dim hr As Integer = internetSecurityManager.MapUrlToZone(absPath, zone, 0)

If VSErrorHandler.Failed(hr) Then
' If we can't map the absolute path to a zone, we silently fail...
Return Security.SecurityZone.NoZone
End If

Return CType(zone, Security.SecurityZone)
End Function


#Region "Telemetry"
Public Class TelemetryLogger

Expand Down
50 changes: 4 additions & 46 deletions src/Microsoft.VisualStudio.Editors/PropPages/CompilePropPage2.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,7 @@ Namespace Microsoft.VisualStudio.Editors.PropertyPages
MyBase.PreApplyPageChanges()
End Sub


''' <summary>
''' Check if the path is a trusted path or not
''' </summary>
Expand All @@ -1321,53 +1322,11 @@ Namespace Microsoft.VisualStudio.Editors.PropertyPages
''' If that code ever changes, we've gotta update this as well...
''' </remarks>
Private Function CheckPath(path As String) As Boolean
If path Is Nothing Then
Throw New ArgumentNullException("path")
End If


If Not IO.Path.IsPathRooted(path) Then
Throw Common.CreateArgumentException("path")
End If

' Some additional verification is done by Path.GetFullPath...
Dim absPath As String = IO.Path.GetFullPath(path)

Dim internetSecurityManager As Interop.IInternetSecurityManager = Nothing

' We've got to get a fresh instance of the InternetSecurityManager, since it seems that the instance we
' can get from our ServiceProvider can't Map URLs to zones...
Dim localReg As ILocalRegistry2 = TryCast(ServiceProvider.GetService(GetType(ILocalRegistry)), ILocalRegistry2)
If localReg IsNot Nothing Then
Dim ObjectPtr As IntPtr = IntPtr.Zero
Try
Static CLSID_InternetSecurityManager As New Guid("7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4")
VSErrorHandler.ThrowOnFailure(localReg.CreateInstance(CLSID_InternetSecurityManager, Nothing, Interop.NativeMethods.IID_IUnknown, Interop.win.CLSCTX_INPROC_SERVER, ObjectPtr))
internetSecurityManager = TryCast(System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(ObjectPtr), Interop.IInternetSecurityManager)
Catch Ex As Exception When Common.ReportWithoutCrash(Ex, "Failed to create Interop.IInternetSecurityManager", NameOf(CompilePropPage2))
Finally
If ObjectPtr <> IntPtr.Zero Then
System.Runtime.InteropServices.Marshal.Release(ObjectPtr)
End If
End Try
End If

If internetSecurityManager Is Nothing Then
Debug.Fail("Failed to create an InternetSecurityManager")
Throw New ApplicationException
End If

Dim zone As Integer
Dim hr As Integer = internetSecurityManager.MapUrlToZone(absPath, zone, 0)

If VSErrorHandler.Failed(hr) Then
' If we can't map the absolute path to a zone, we silently fail...
Return True
End If
Dim zone As Security.SecurityZone = Common.GetSecurityZoneOfFile(path, ServiceProvider)

Dim folderEvidence As Security.Policy.Evidence = New Security.Policy.Evidence()
folderEvidence.AddHostEvidence(New Security.Policy.Url("file:///" & absPath))
folderEvidence.AddHostEvidence(New Security.Policy.Zone(CType(zone, Security.SecurityZone)))
folderEvidence.AddHostEvidence(New Security.Policy.Url("file:///" & IO.Path.GetFullPath(path)))
folderEvidence.AddHostEvidence(New Security.Policy.Zone(zone))
Dim folderPSet As Security.PermissionSet = Security.SecurityManager.GetStandardSandbox(folderEvidence)

' Get permission set that is granted to local code running on the local machine.
Expand All @@ -1386,7 +1345,6 @@ Namespace Microsoft.VisualStudio.Editors.PropertyPages
End If
End Function


''' <summary>
''' Set the drop-down width of comboboxes with user-handled events so they'll fit their contents
''' </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ Namespace Microsoft.VisualStudio.Editors.ResourceEditor
' We want to show an empty designer when we open an empty resx file. The file could come from a V7.x projects
If Not String.IsNullOrEmpty(bufferText) Then
'CONSIDER: get DocDataBufferReader and pass that in to ReadResources directly instead of the additional overhead of calling GetAllBufferText, which turns a stream into a string, and then turning the string into a stream.
Using Reader As StringReader = New StringReader(bufferText)
ResourceFile.ReadResources(Reader)
End Using
ResourceFile.ReadResources(NewResourceEditorRoot.ResourceFileName, bufferText)
End If

'NOTE: We should consider to restoer many view states before populating the designer surface...
Expand Down
93 changes: 80 additions & 13 deletions src/Microsoft.VisualStudio.Editors/ResourceEditor/ResourceFile.vb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Imports System.ComponentModel.Design
Imports System.Resources
Imports System.IO
Imports System.Windows.Forms

Imports Microsoft.Win32
Imports System.Xml

Namespace Microsoft.VisualStudio.Editors.ResourceEditor

Expand Down Expand Up @@ -93,6 +94,8 @@ Namespace Microsoft.VisualStudio.Editors.ResourceEditor
Private _inBatchAdding As Boolean

Private _multiTargetService As MultiTargetService

Private _allowMOTW As Boolean = False
#End Region


Expand Down Expand Up @@ -143,6 +146,15 @@ Namespace Microsoft.VisualStudio.Editors.ResourceEditor
End If

_mainThread = System.Threading.Thread.CurrentThread

Try
Dim allowUntrustedFiles As Object = Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\SDK", "AllowProcessOfUntrustedResourceFiles", Nothing)
If TypeOf allowUntrustedFiles Is String Then
_allowMOTW = DirectCast(allowUntrustedFiles, String).Equals("true", StringComparison.OrdinalIgnoreCase)
End If
Catch ex As Exception
' Deliberately empty
End Try
End Sub


Expand Down Expand Up @@ -849,22 +861,31 @@ Namespace Microsoft.VisualStudio.Editors.ResourceEditor


''' <summary>
''' Reads resources from a TextReader on a resx file.
''' Reads resources from a string (contents of a resx file).
''' </summary>
''' <param name="TextReader">The TextReader to read from</param>
''' <param name="allBufferText">The TextReader to read from</param>
''' <remarks></remarks>
Public Sub ReadResources(TextReader As TextReader)
Dim ResXReader As ResXResourceReader
Dim TypeResolutionService As ITypeResolutionService = View.GetTypeResolutionService()
If TypeResolutionService IsNot Nothing Then
ResXReader = New ResXResourceReader(TextReader, TypeResolutionService)
Else
ResXReader = New ResXResourceReader(TextReader, ResourceEditorView.GetDefaultAssemblyReferences())
Public Sub ReadResources(resourceFileName As String, allBufferText As String)

If IsDangerous(resourceFileName, allBufferText) Then
' NOTE: Not localized because we're shipping in a hotfix and don't have facility to ship localized resources.
View.DsMsgBox("Unable to load '" & resourceFileName & "' because it is not trusted.", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
ResXReader.BasePath = _basePath

ReadResources(ResXReader)
ResXReader.Close()
Using TextReader = New StringReader(allBufferText)
Dim ResXReader As ResXResourceReader
Dim TypeResolutionService As ITypeResolutionService = View.GetTypeResolutionService()
If TypeResolutionService IsNot Nothing Then
ResXReader = New ResXResourceReader(TextReader, TypeResolutionService)
Else
ResXReader = New ResXResourceReader(TextReader, ResourceEditorView.GetDefaultAssemblyReferences())
End If
ResXReader.BasePath = _basePath

ReadResources(ResXReader)
ResXReader.Close()
End Using
End Sub

Public Function TypeNameConverter(runtimeType As Type) As String
Expand Down Expand Up @@ -910,6 +931,7 @@ Namespace Microsoft.VisualStudio.Editors.ResourceEditor
Debug.Assert(ResXReader IsNot Nothing, "ResXReader must exist!")

_isLoadingResourceFile = True

Try
Dim orderID As Integer = 0
Dim lastName As String = String.Empty
Expand Down Expand Up @@ -1789,6 +1811,51 @@ Namespace Microsoft.VisualStudio.Editors.ResourceEditor
End If
End Sub


Private Function IsDangerous(resxFilePath As String, allBufferText As String) As Boolean
If _allowMOTW Then
Return False
End If

Dim zone As Security.SecurityZone = GetSecurityZoneOfFile(resxFilePath, Shell.ServiceProvider.GlobalProvider)
If zone < Security.SecurityZone.Internet Then
Return False
End If

Dim dangerous As Boolean = False

Using textReader = New StringReader(allBufferText)
Using reader = New XmlTextReader(textReader)
reader.DtdProcessing = DtdProcessing.Ignore
reader.XmlResolver = Nothing
Try
While reader.Read()
If reader.NodeType = XmlNodeType.Element Then
Dim s As String = reader.LocalName

' We only want to parse data nodes,
' the mimetype attribute gives the serializer
' that's requested.
If reader.LocalName.Equals("data") Then
If reader("mimetype") <> Nothing Then
dangerous = True
End If
ElseIf reader.LocalName.Equals("metadata") Then
If reader("mimetype") <> Nothing Then
dangerous = True
End If
End If
End If
End While
Catch
' If we hit an error while parsing assume there's a dangerous type in this file.
dangerous = True
End Try
End Using
End Using
Return dangerous
End Function

#End Region

End Class
Expand Down

0 comments on commit 9257cbd

Please sign in to comment.