From f509d47d5bec0a91b0a610a98bb64924fc0cf62e Mon Sep 17 00:00:00 2001 From: Eric Johnson Date: Fri, 17 Mar 2023 15:11:55 -0700 Subject: [PATCH] Enable plugins to restrict non-Microsoft hosts (#41) * Enable plugins to restrict non-Microsoft hosts * Add script fix to reset appxmanifest version after building --------- Co-authored-by: Eric Johnson --- Build.ps1 | 8 +- build/scripts/CreateBuildInfo.ps1 | 2 +- pluginsdk/Build.ps1 | 7 +- .../Microsoft.Windows.DevHome.SDK.Lib.csproj | 4 + .../NativeMethods.txt | 5 ++ .../PluginInstanceManager.cs | 73 +++++++++++++++++-- .../PluginServer.cs | 4 +- 7 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/NativeMethods.txt diff --git a/Build.ps1 b/Build.ps1 index eec8b03..06e95e2 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -101,6 +101,12 @@ Try { } } } + + # Reset the version in appxmanifest to prevent unnecessary code changes + $appxmanifest = [System.Xml.Linq.XDocument]::Load($appxmanifestPath) + $xName = [System.Xml.Linq.XName]::Get("{http://schemas.microsoft.com/appx/manifest/foundation/windows10}Identity"); + $appxmanifest.Root.Element($xName).Attribute("Version").Value = "0.0.0.0" + $appxmanifest.Save($appxmanifestPath) } if (($BuildStep -ieq "all") -Or ($BuildStep -ieq "msixbundle")) { @@ -120,7 +126,7 @@ Try { $TotalTime = (Get-Date)-$StartTime $TotalMinutes = [math]::Floor($TotalTime.TotalMinutes) -$TotalSeconds = [math]::Ceiling($TotalTime.TotalSeconds) +$TotalSeconds = [math]::Ceiling($TotalTime.TotalSeconds) - ($totalMinutes * 60) if (-not($isAdmin)) { Write-Host @" diff --git a/build/scripts/CreateBuildInfo.ps1 b/build/scripts/CreateBuildInfo.ps1 index 1ca098f..24cd0b6 100644 --- a/build/scripts/CreateBuildInfo.ps1 +++ b/build/scripts/CreateBuildInfo.ps1 @@ -6,7 +6,7 @@ Param( ) $Major = "0" -$Minor = "0" +$Minor = "1" $Patch = "99" # default to 99 for local builds $versionSplit = $Version.Split("."); diff --git a/pluginsdk/Build.ps1 b/pluginsdk/Build.ps1 index f6c8ffa..8346625 100644 --- a/pluginsdk/Build.ps1 +++ b/pluginsdk/Build.ps1 @@ -35,7 +35,6 @@ $ErrorActionPreference = "Stop" $buildPlatforms = "x64","x86","arm64","AnyCPU" $env:Build_Configuration = $Configuration -$env:sdk_version = & (Join-Path $PSScriptRoot "..\build\Scripts\CreateBuildInfo.ps1") -Version $SDKVersion -IsSdkVersion $true -IsAzurePipelineBuild $IsAzurePipelineBuild $msbuildPath = &"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe if ($IsAzurePipelineBuild) { @@ -67,11 +66,11 @@ Try { Exit 1 } -& $nugetPath pack (Join-Path $PSScriptRoot "nuget\Microsoft.Windows.DevHome.SDK.nuspec") -Version $env:sdk_version -OutputDirectory "$PSScriptRoot\_build" +& $nugetPath pack (Join-Path $PSScriptRoot "nuget\Microsoft.Windows.DevHome.SDK.nuspec") -Version $SDKVersion -OutputDirectory "$PSScriptRoot\_build" if ($IsAzurePipelineBuild) { - Write-Host "##vso[task.setvariable variable=SDKVersion;]$env:sdk_version" - Write-Host "##vso[task.setvariable variable=SDKVersion;isOutput=true;]$env:sdk_version" + Write-Host "##vso[task.setvariable variable=SDKVersion;]$SDKVersion" + Write-Host "##vso[task.setvariable variable=SDKVersion;isOutput=true;]$SDKVersion" } $TotalTime = (Get-Date)-$StartTime diff --git a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/Microsoft.Windows.DevHome.SDK.Lib.csproj b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/Microsoft.Windows.DevHome.SDK.Lib.csproj index e86e655..caa9da1 100644 --- a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/Microsoft.Windows.DevHome.SDK.Lib.csproj +++ b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/Microsoft.Windows.DevHome.SDK.Lib.csproj @@ -15,6 +15,10 @@ + + all + runtime; build; native; contentfiles; analyzers + diff --git a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/NativeMethods.txt b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/NativeMethods.txt new file mode 100644 index 0000000..c357d14 --- /dev/null +++ b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/NativeMethods.txt @@ -0,0 +1,5 @@ +CoImpersonateClient +GetCurrentThread +OpenThreadToken +GetPackageFamilyNameFromToken +CoRevertToSelf \ No newline at end of file diff --git a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginInstanceManager.cs b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginInstanceManager.cs index 87f4d49..c5a6e81 100644 --- a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginInstanceManager.cs +++ b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginInstanceManager.cs @@ -2,10 +2,14 @@ // Licensed under the MIT license. using System; +using System.Reflection.Metadata; using System.Runtime.InteropServices; using Windows.ApplicationModel.Background; using Windows.Foundation; -using Windows.Storage; +using Windows.Storage; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.Security; using WinRT; namespace Microsoft.Windows.DevHome.SDK; @@ -16,26 +20,36 @@ internal class PluginInstanceManager : IClassFactory { #pragma warning disable SA1310 // Field names should not contain underscore - private const int E_NOINTERFACE = unchecked((int)0x800004002); + private const int E_NOINTERFACE = unchecked((int)0x80004002); private const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110); + + private const int E_ACCESSDENIED = unchecked((int)0x80070005); private static readonly Guid IID_IUnknown = Guid.Parse("00000000-0000-0000-C000-000000000046"); #pragma warning restore SA1310 // Field names should not contain underscore - private readonly Func _createPlugin; + private readonly Func _createPlugin; + + private readonly bool _restrictToMicrosoftPluginHosts; - public PluginInstanceManager(Func createPlugin) + public PluginInstanceManager(Func createPlugin, bool restrictToMicrosoftPluginHosts) { - this._createPlugin = createPlugin; + this._createPlugin = createPlugin; + this._restrictToMicrosoftPluginHosts = restrictToMicrosoftPluginHosts; } public void CreateInstance( [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, ref Guid riid, out IntPtr ppvObject) - { + { + if (_restrictToMicrosoftPluginHosts && !IsMicrosoftPluginHost()) + { + Marshal.ThrowExceptionForHR(E_ACCESSDENIED); + } + ppvObject = IntPtr.Zero; if (pUnkOuter != null) @@ -58,6 +72,53 @@ public void CreateInstance( public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock) { + } + + private unsafe bool IsMicrosoftPluginHost() + { + if (PInvoke.CoImpersonateClient() != 0) + { + return false; + } + + HANDLE callerToken = HANDLE.Null; + if (PInvoke.OpenThreadToken(PInvoke.GetCurrentThread(), TOKEN_ACCESS_MASK.TOKEN_QUERY, true, &callerToken) != 0) + { + return false; + } + + if (PInvoke.CoRevertToSelf() != 0) + { + return false; + } + + uint a = 0; + if (PInvoke.GetPackageFamilyNameFromToken(callerToken, &a, null) != 0) + { + return false; + } + + var value = new char[a]; + fixed (char* p = value) + { + if (PInvoke.GetPackageFamilyNameFromToken(callerToken, &a, p) != 0) + { + return false; + } + } + + var valueStr = new string(value); + switch (valueStr) + { + case "Microsoft.Windows.DevHome_8wekyb3d8bbwe\0": + case "Microsoft.WindowsTerminal\0": + case "Microsoft.WindowsTerminal_8wekyb3d8bbwe\0": + case "WindowsTerminalDev_8wekyb3d8bbwe\0": + case "Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\0": + return true; + default: + return false; + } } } diff --git a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginServer.cs b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginServer.cs index 8b2cebe..3716e64 100644 --- a/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginServer.cs +++ b/pluginsdk/Microsoft.Windows.DevHome.SDK.Lib/PluginServer.cs @@ -10,7 +10,7 @@ public sealed class PluginServer : IDisposable { private readonly HashSet registrationCookies = new (); - public void RegisterPlugin(Func createPlugin) + public void RegisterPlugin(Func createPlugin, bool restrictToMicrosoftPluginHosts = false) where T : IPlugin { Trace.WriteLine($"Registering class object:"); @@ -22,7 +22,7 @@ public void RegisterPlugin(Func createPlugin) var clsid = typeof(T).GUID; var hr = Ole32.CoRegisterClassObject( ref clsid, - new PluginInstanceManager(createPlugin), + new PluginInstanceManager(createPlugin, restrictToMicrosoftPluginHosts), Ole32.CLSCTX_LOCAL_SERVER, Ole32.REGCLS_MULTIPLEUSE | Ole32.REGCLS_SUSPENDED, out cookie);