diff --git a/src/System.Management.Automation/engine/debugger/debugger.cs b/src/System.Management.Automation/engine/debugger/debugger.cs
index b78c8b66aa..f16352a885 100644
--- a/src/System.Management.Automation/engine/debugger/debugger.cs
+++ b/src/System.Management.Automation/engine/debugger/debugger.cs
@@ -1104,12 +1104,16 @@ namespace System.Management.Automation
internal Breakpoint NewCommandBreakpoint(string path, string command, ScriptBlock action)
{
WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
+
+ CheckForBreakpointSupport();
return AddCommandBreakpoint(new CommandBreakpoint(path, pattern, command, action));
}
internal Breakpoint NewCommandBreakpoint(string command, ScriptBlock action)
{
WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
+
+ CheckForBreakpointSupport();
return AddCommandBreakpoint(new CommandBreakpoint(null, pattern, command, action));
}
@@ -1147,6 +1151,7 @@ namespace System.Management.Automation
{
Diagnostics.Assert(path != null, "caller to verify path is not null");
+ CheckForBreakpointSupport();
return AddLineBreakpoint(new LineBreakpoint(path, line, action));
}
@@ -1154,6 +1159,7 @@ namespace System.Management.Automation
{
Diagnostics.Assert(path != null, "caller to verify path is not null");
+ CheckForBreakpointSupport();
return AddLineBreakpoint(new LineBreakpoint(path, line, column, action));
}
@@ -1174,11 +1180,13 @@ namespace System.Management.Automation
internal Breakpoint NewVariableBreakpoint(string path, string variableName, VariableAccessMode accessMode, ScriptBlock action)
{
+ CheckForBreakpointSupport();
return AddVariableBreakpoint(new VariableBreakpoint(path, variableName, accessMode, action));
}
internal Breakpoint NewVariableBreakpoint(string variableName, VariableAccessMode accessMode, ScriptBlock action)
{
+ CheckForBreakpointSupport();
return AddVariableBreakpoint(new VariableBreakpoint(null, variableName, accessMode, action));
}
@@ -1734,12 +1742,6 @@ namespace System.Management.Automation
originalLanguageMode = _context.LanguageMode;
_context.LanguageMode = PSLanguageMode.FullLanguage;
}
- else if (System.Management.Automation.Security.SystemPolicy.GetSystemLockdownPolicy() ==
- System.Management.Automation.Security.SystemEnforcementMode.Enforce)
- {
- // If there is a system lockdown in place, enforce it
- originalLanguageMode = Utils.EnforceSystemLockDownLanguageMode(this._context);
- }
// Update the prompt to the debug prompt
if (hadDefaultPrompt)
@@ -2034,6 +2036,17 @@ namespace System.Management.Automation
{
lock (_syncObject)
{
+ // Disable script debugger when in system lock down mode
+ if (IsSystemLockedDown)
+ {
+ if (_context._debuggingMode != (int)InternalDebugMode.Disabled)
+ {
+ _context._debuggingMode = (int)InternalDebugMode.Disabled;
+ }
+
+ return;
+ }
+
switch (mode)
{
case InternalDebugMode.InPushedStop:
@@ -2060,6 +2073,24 @@ namespace System.Management.Automation
}
}
+ private static bool IsSystemLockedDown
+ {
+ get
+ {
+ return (System.Management.Automation.Security.SystemPolicy.GetSystemLockdownPolicy() ==
+ System.Management.Automation.Security.SystemEnforcementMode.Enforce);
+ }
+ }
+
+ private static void CheckForBreakpointSupport()
+ {
+ if (IsSystemLockedDown)
+ {
+ // Local script debugging is not supported in locked down mode
+ throw new PSNotSupportedException();
+ }
+ }
+
#region Enable debug stepping
[Flags]
@@ -2297,6 +2328,15 @@ namespace System.Management.Automation
{
lock (_syncObject)
{
+ // Restrict local script debugger mode when in system lock down.
+ // DebugModes enum flags provide a combination of values. To disable local script debugging
+ // we have to disallow 'LocalScript' and 'Default' flags and only allow 'None' or 'RemoteScript'
+ // flags exclusively. This allows only no debugging 'None' or remote debugging 'RemoteScript'.
+ if (IsSystemLockedDown && (mode != DebugModes.None) && (mode != DebugModes.RemoteScript))
+ {
+ mode = DebugModes.RemoteScript;
+ }
+
base.SetDebugMode(mode);
if (!CanEnableDebugger)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageDebugger.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageDebugger.Tests.ps1
index 31c047a244..04aaa8b386 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageDebugger.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageDebugger.Tests.ps1
@@ -18,10 +18,89 @@ try
$defaultParamValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:Skip"] = !$IsWindows
- Describe "Trusted module on locked down machine should not expose private functions to script debugger command processing" -Tags 'CI','RequireAdminOnWindows' {
+ Describe "Local script debugger is disabled in system lock down mode" -Tags 'CI','RequireAdminOnWindows' {
BeforeAll {
+ # Invoke-LanguageModeTestingSupportCmdlet definition
+ $languageModeCmdletDef = @'
+ using System;
+ using System.Globalization;
+ using System.Reflection;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Security;
+ using System.Runtime.InteropServices;
+ using System.Threading;
+ using System.Management.Automation;
+
+ /// Adds a new type to the Application Domain
+ [Cmdlet("Invoke", "LanguageModeTestingSupportCmdlet")]
+ public sealed class InvokeLanguageModeTestingSupportCmdlet : PSCmdlet
+ {
+ [Parameter()]
+ public SwitchParameter EnableFullLanguageMode
+ {
+ get { return enableFullLanguageMode; }
+ set { enableFullLanguageMode = value; }
+ }
+ private SwitchParameter enableFullLanguageMode;
+
+ [Parameter()]
+ public SwitchParameter SetLockdownMode
+ {
+ get { return setLockdownMode; }
+ set { setLockdownMode = value; }
+ }
+ private SwitchParameter setLockdownMode;
+
+ [Parameter()]
+ public SwitchParameter RevertLockdownMode
+ {
+ get { return revertLockdownMode; }
+ set { revertLockdownMode = value; }
+ }
+ private SwitchParameter revertLockdownMode;
+
+ protected override void BeginProcessing()
+ {
+ if(enableFullLanguageMode)
+ {
+ SessionState.LanguageMode = PSLanguageMode.FullLanguage;
+ }
+
+ if(setLockdownMode)
+ {
+ Environment.SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", EnvironmentVariableTarget.Machine);
+ }
+
+ if(revertLockdownMode)
+ {
+ Environment.SetEnvironmentVariable("__PSLockdownPolicy", null, EnvironmentVariableTarget.Machine);
+ }
+ }
+ }
+'@
+
+ if (-not (Get-Command Invoke-LanguageModeTestingSupportCmdlet -ea Ignore))
+ {
+ $languageModeModuleName = "LanguageModeModule"
+ $modulePath = [System.IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetRandomFileName())
+ $script:moduleDirectory = join-path "$PSScriptRoot\$modulePath" $languageModeModuleName
+ if (-not (Test-Path $moduleDirectory))
+ {
+ $null = New-Item -ItemType Directory $moduleDirectory -Force
+ }
+
+ try
+ {
+ Add-Type -TypeDefinition $languageModeCmdletDef -OutputAssembly $moduleDirectory\TestCmdletForConstrainedLanguage.dll -ErrorAction Ignore
+ } catch {}
+
+ Import-Module -Name $moduleDirectory\TestCmdletForConstrainedLanguage.dll
+ }
+
# Debugger test type definition
$debuggerTestTypeDef = @'
using System;
@@ -33,29 +112,14 @@ try
public class DebuggerTester
{
private Runspace _runspace;
- private readonly string _privateFnName;
- [Flags]
- public enum TestResults
- {
- NoResult = 0x0,
- DebuggerStopHandled = 0x1,
- PrivateFnFound = 0x2
- };
-
- public TestResults TestResult
+ public int DebuggerStopHitCount
{
private set;
get;
}
- public Exception ScriptException
- {
- private set;
- get;
- }
-
- public DebuggerTester(Runspace runspace, string privateFnName)
+ public DebuggerTester(Runspace runspace)
{
if (runspace.Debugger == null)
{
@@ -63,363 +127,160 @@ try
}
_runspace = runspace;
- _privateFnName = privateFnName;
_runspace.Debugger.DebuggerStop += (sender, args) =>
{
- try
- {
- // Within the debugger stop handler, make sure trusted private functions are not accessible.
- string commandText = string.Format(@"Get-Command ""{0}""", _privateFnName);
- PSCommand command = new PSCommand();
- command.AddCommand(new Command(commandText, true));
- PSDataCollection output = new PSDataCollection();
-
- _runspace.Debugger.ProcessCommand(command, output);
- if ((output.Count > 0) && (output[0].BaseObject is CommandInfo))
- {
- TestResult |= TestResults.PrivateFnFound;
- }
- }
- catch (Exception e)
- {
- ScriptException = e;
- System.Console.WriteLine(e.Message);
- }
- TestResult |= TestResults.DebuggerStopHandled;
+ DebuggerStopHitCount += 1;
};
}
}
}
'@
- $modulePath = Join-Path $TestDrive Modules
- if (Test-Path -Path $modulePath)
- {
- try { Remove-Item -Path $modulePath -Recurse -Force -ErrorAction SilentlyContinue } catch { }
- }
+ $script = @'
+ "Hello"
+ Wait-Debugger
+ "Goodbye"
+'@
+ $scriptFilePath = Join-Path $TestDrive TScript.ps1
+ $script > $scriptFilePath
- # Trusted module
- $trustedModuleName = "TrustedModule_System32"
- $trustedModuleDirectory = Join-Path $modulePath $trustedModuleName
- New-Item -ItemType Directory -Path $trustedModuleDirectory -Force -ErrorAction SilentlyContinue
- $trustedModuleFilePath = Join-Path $trustedModuleDirectory "$($trustedModuleName).psm1"
- $trustedManifestFilePath = Join-Path $trustedModuleDirectory "$($trustedModuleName).psd1"
- @'
- function PublicFn {
- Write-Output PrivateFn "PublicFn"
- }
-
- function PrivateFn {
- param ([string] $msg)
-
- Write-Output $msg
- }
-'@ > $trustedModuleFilePath
- $modManifest = "@{ ModuleVersion = '1.0'" + ("; RootModule = '{0}'" -f $trustedModuleFilePath) + "; FunctionsToExport = 'PublicFn' }"
- $modManifest > $trustedManifestFilePath
-
- # Create test runspace
- [runspace] $runspace = [runspacefactory]::CreateRunspace()
- $runspace.Open()
-
- # Create debugger test object
+ # Define debugger test type
Add-Type -TypeDefinition $debuggerTestTypeDef
}
AfterAll {
- if ($runspace -ne $null) { $runspace.Dispose() }
- }
-
- It "Verifies that private trusted module function is not available in script debugger" {
-
- # Run debugger access test
- $debuggerTester = [TestRunner.DebuggerTester]::new($runspace, "PrivateFn")
-
- # Script to invoke the script debugger so that $debuggerTester can handle
- # the debugger stop event and test for access of private functions within the
- # script debugger command processor.
- $script = @'
- Import-Module -Name HelpersSecurity
- Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
- $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
- Import-Module -Name {0} -Force
- Set-PSBreakpoint -Command PublicFn
- PublicFn
-'@ -f $trustedManifestFilePath
-
- [powershell] $ps = [powershell]::Create()
- $ps.Runspace = $runspace
-
- try
+ if (($script:moduleDirectory -ne $null) -and (Test-Path $script:moduleDirectory))
{
- $ps.AddScript($script).BeginInvoke()
-
- # Wait for debugger test result for up to ten seconds
- $count = 0
- while (($debuggerTester.TestResult -eq 0) -and ($count++ -lt 40))
- {
- Start-Sleep -Milliseconds 250
- }
+ try { Remove-Item -Path $moduleDirectory -Recurse -Force -ErrorAction SilentlyContinue } catch { }
}
- finally
- {
- # Revert lockdown
- Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
- }
-
- # Verify that PrivateFn function name is not accessible
- $debuggerTester.TestResult | Should -Match "DebuggerStopHandled"
- $debuggerTester.TestResult | Should -Not -Match "PrivateFnFound"
- $debuggerTester.ScriptException | Should -BeNullOrEmpty
- }
- }
-
- Describe "Cross language debugger get-item commands should not have access to FullLanguage trusted functions through provider" -Tags 'Feature','RequireAdminOnWindows' {
-
- BeforeAll {
-
- # Trusted module that will always run in FullLanguage mode
- $scriptModuleName = "ImportTrustedModuleForTestA_System32"
- $moduleFilePath = Join-Path $TestDrive ($scriptModuleName + ".psm1")
- $script = @'
- function PublicFn { "PublicFn"; PrivateFn }
- function PrivateFn { "PrivateFn" }
-
- Export-ModuleMember -Function PublicFn
-'@
- $script > $moduleFilePath
-
- # Import and run module function script
- $scriptIM = @'
- Import-Module -Name {0} -Force
- $null = Set-PSBreakpoint -command PublicFn
- PublicFn
-'@ -f $moduleFilePath
-
- # Debugger stop event handler object.
- $type = @'
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Management.Automation;
- using System.Management.Automation.Runspaces;
-
- public class DebuggerStopEventHandler
- {
- private Runspace _runspace;
- public object GetItemResult
- {
- get;
- internal set;
- }
- public object GetChildItemResult
- {
- get;
- internal set;
- }
- public object CopyItemResult
- {
- get;
- internal set;
- }
- public object FunctionVariableResult
- {
- get;
- internal set;
- }
- public object RenameItemResult
- {
- get;
- internal set;
- }
- public DebuggerStopEventHandler(Runspace runspace)
- {
- _runspace = runspace;
- _runspace.Debugger.DebuggerStop += (sender, args) =>
- {
- var debugger = sender as Debugger;
-
- PSDataCollection output = new PSDataCollection();
- PSCommand command = new PSCommand();
-
- command.AddScript(@"Get-Item -Path function:\PrivateFn 2>&1");
- debugger.ProcessCommand(command, output);
- GetItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
-
- command.Clear();
- output.Clear();
- command.AddScript(@"Get-ChildItem -Path function:\PrivateFn 2>&1");
- debugger.ProcessCommand(command, output);
- GetChildItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
-
- command.Clear();
- output.Clear();
- command.AddScript(@"Copy-Item -Path function:\PrivateFn -Destination function:\MyPrivateFn 2>&1");
- debugger.ProcessCommand(command, output);
- CopyItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
-
- command.Clear();
- output.Clear();
- command.AddScript(@"${function:\PrivateFn}");
- debugger.ProcessCommand(command, output);
- FunctionVariableResult = (output.Count > 0) ? (output[0].BaseObject): null;
-
- command.Clear();
- output.Clear();
- command.AddScript(@"Rename-Item -Path function:\PrivateFn -NewName function:\MyPrivateFn -Passthru 2>&1");
- debugger.ProcessCommand(command, output);
- RenameItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
- };
- }
- public void Reset() { GetItemResult = null; GetChildItemResult = null; CopyItemResult = null; }
- }
-'@
-
- try { Add-Type -TypeDefinition $type } catch { }
-
- # Create runspace and debugger event handler
- [runspace] $rs = [runspacefactory]::CreateRunspace($host)
- $rs.Open()
- $rs.Debugger.SetDebugMode(@('LocalScript','RemoteScript'))
- $debuggerStopHandler = [DebuggerStopEventHandler]::New($rs)
-
- # Create PowerShell to run module script
- [powershell] $ps = [powershell]::Create()
- $ps.Runspace = $rs
- $ps.AddScript($scriptIM)
}
- AfterAll {
-
- if ($rs -ne $null) { $rs.Dispose() }
- if ($ps -ne $null) { $ps.Dispose() }
- }
-
- It "Verifies that same language mode trusted public functions *are* accessible from debugger through Get-Item, Get-ChildItem, Copy-Item, Rename-Item, Variable" {
-
- # Test
- $results = $ps.Invoke()
-
- # Results. Only PublicFn is returned since PrivateFn is renamed.
- $results[0] | Should Be "PublicFn"
-
- # Expected Get-Item function:\PrivateFn returns FunctionInfo object
- ($debuggerStopHandler.GetItemResult -is [System.Management.Automation.FunctionInfo]) | Should Be $true
-
- # Expected Get-ChildItem function:\PrivateFn returns FunctionInfo object
- ($debuggerStopHandler.GetChildItemResult -is [System.Management.Automation.FunctionInfo]) | Should Be $true
-
- # Expected Copy-Item function:\PrivateFn succeeds with no error output
- $debuggerStopHandler.CopyItemResult | Should Be $null
-
- # Expected function variable succeeds
- ($debuggerStopHandler.FunctionVariableResult -is [scriptblock]) | Should Be $true
-
- # Expected Rename-Item function:\PrivateFn returns FunctionInfo object
- ($debuggerStopHandler.RenameItemResult -is [System.Management.Automation.FunctionInfo]) | Should Be $true
- }
-
- It "Verifies that cross language mode trusted public functions *are not* accessible through Get-Item, Get-ChildItem, Copy-Item, Rename-Item, Variable" {
-
- # Test
- $debuggerStopHandler.Reset()
- try
- {
- $rs.LanguageMode = "ConstrainedLanguage"
- Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
-
- $results = $ps.Invoke()
- }
- finally
- {
- Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
- }
-
- # Results
- $results[0] | Should Be "PublicFn"
- $results[1] | Should Be "PrivateFn"
-
- # Expected Get-Item function:\PrivateFn returns error
- $debuggerStopHandler.GetItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
-
- # Expected Get-ChildItem function:\PrivateFn returns error
- $debuggerStopHandler.GetChildItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand"
-
- # Expected Copy-Item fails with error output
- $debuggerStopHandler.CopyItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
-
- # Expected function variable fails
- $debuggerStopHandler.FunctionVariableResult | Should Be $null
-
- # Expected Rename-Item function:\PrivateFn fails with error
- $debuggerStopHandler.RenameItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.RenameItemCommand"
- }
- }
-
- Describe "Cross language debugger Action scripts should not have access to FullLanguage trusted functions through provider" -Tags 'Feature','RequireAdminOnWindows' {
-
- BeforeAll {
-
- # Trusted script that will always run in FullLanguage mode
- $scriptFileName = "TrustedScriptForTestB_System32"
- $scriptFilePath = Join-Path $TestDrive ($scriptFileName + ".ps1")
- $script = @'
- function PublicFn { PrivateFn -typeDef 'public class Hello { public new static void ToString() { System.Console.WriteLine("Hello!"); } }'; [Hello]::ToString(); }
- function PrivateFn { param ([string]$typeDef) Add-Type -TypeDefinition $typeDef }
- PublicFn
- "Complete"
-'@
- $script > $scriptFilePath
- }
-
- AfterAll {
-
- Get-PSBreakpoint | Remove-PSBreakpoint
- }
-
- It "Verifies that debugger stop Action scriptblock cannot access PrivateFn" {
+ It "Verifies that Set-PSBreakpoint Line is disabled on locked down system" {
try
{
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
- # Set breakpoint on script
- Set-PSBreakpoint -Script $scriptFilePath -Line 4 -Action {
- & (Get-Item -Path function:\PrivateFn) -typeDef @'
- public class Foo {
- public new static void ToString() {
- System.Console.WriteLine("pwnd!");
- }
- }
-'@
- }
-
- # Run script
- & $scriptFilePath
- }
- finally
- {
- Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
- }
-
- try
- {
- # Verify that Action scriptblock did not create Foo type using PrivateFn
- [Foo]::ToString()
+ Set-PSBreakpoint -Script $scriptFilePath -Line 1
throw "No Exception!"
}
catch
{
- $_.FullyQualifiedErrorId | Should Be "TypeNotFound"
+ $expectedError = $_
}
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
+ }
+
+ It "Verifies that Set-PSBreakpoint Statement is disabled on locked down system" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
+ $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
+
+ Set-PSBreakpoint -Script $scriptFilePath -Line 1 -Column 1
+ throw "No Exception!"
+ }
+ catch
+ {
+ $expectedError = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
+ }
+
+ It "Verifies that Set-PSBreakpoint Command is disabled on locked down system" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
+ $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
+
+ Set-PSBreakpoint -Command $scriptFilePath
+ throw "No Exception!"
+ }
+ catch
+ {
+ $expectedError = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
+ }
+
+ It "Verifies that Set-PSBreakpoint Variable is disabled on locked down system" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
+ $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
+
+ Set-PSBreakpoint -Variable HelloVar
+ throw "No Exception!"
+ }
+ catch
+ {
+ $expectedError = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
+ }
+
+ It "Verifies that Wait-Debugger is disabled on locked down system" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
+
+ # Create test runspace
+ [runspace] $runspace = [runspacefactory]::CreateRunspace()
+ $runspace.Open()
+
+ # Attach TestRuner.DebuggerTester DebugStop event handler to runspace
+ $debuggerTester = [TestRunner.DebuggerTester]::new($runspace)
+
+ # Run $scriptFilePath script with 'Wait-Debugger' in locked down mode
+ [powershell] $ps = [powershell]::Create()
+ $ps.Runspace = $runspace
+ $null = $ps.AddScript('"Hello"; Wait-Debugger; "Goodbye"').Invoke()
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
+ if ($runspace -ne $null) { $runspace.Dispose() }
+ if ($ps -ne $null) { $ps.Dispose() }
+ }
+
+ # Debugger should not have been active in lockdown mode
+ $debuggerTester.DebuggerStopHitCount | Should Be 0
}
}
}
finally
{
- if ($defaultParamValues -ne $null)
+ if ($null -ne $defaultParamValues)
{
$Global:PSDefaultParameterValues = $defaultParamValues
}
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1
index a3bc16494d..e5fe6d081c 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1
@@ -365,116 +365,6 @@ try
}
}
- Describe "Script debugging in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
-
- It "Verifies that a debugging breakpoint cannot be set in constrained language and no system lockdown" {
-
- try
- {
- $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
- function MyDebuggerFunction {}
-
- Set-PSBreakpoint -Command MyDebuggerFunction
- throw "No Exception!"
- }
- catch
- {
- $expectedError = $_
- }
- finally
- {
- Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
- }
-
- $expectedError.FullyQualifiedErrorId | Should -BeExactly "CannotSetBreakpointInconsistentLanguageMode,Microsoft.PowerShell.Commands.SetPSBreakpointCommand"
- }
-
- It "Verifies that a debugging breakpoint can be set in constrained language with system lockdown" {
-
- try
- {
- $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
- Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
-
- function MyDebuggerFunction2 {}
- $Global:DebuggingOk = $null
- $null = Set-PSBreakpoint -Command MyDebuggerFunction2 -Action { $Global:DebuggingOk = "DebuggingOk" }
- MyDebuggerFunction2
- }
- finally
- {
- Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
- }
-
- $Global:DebuggingOk | Should -BeExactly "DebuggingOk"
- }
-
- It "Verifies that debugger commands do not run in full language mode when system is locked down" {
-
- try
- {
- $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
-
- function MyDebuggerFunction3 {}
-
- & {
- $null = Set-PSBreakpoint -Command MyDebuggerFunction3 -Action { $Global:dbgResult = [object]::Equals("A", "B") }
- $restoreEAPreference = $ErrorActionPreference
- $ErrorActionPreference = "Stop"
- MyDebuggerFunction3
- }
- throw "No Exception!"
- }
- catch
- {
- $expectedError = $_
- }
- finally
- {
- Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
- if ($restoreEAPreference -ne $null) { $ErrorActionPreference = $restoreEAPreference }
- }
-
- $expectedError.FullyQualifiedErrorId | Should -BeExactly "CannotSetBreakpointInconsistentLanguageMode,Microsoft.PowerShell.Commands.SetPSBreakpointCommand"
- }
-
- It "Verifies that debugger command injection is blocked in system lock down" {
-
- $trustedScriptContent = @'
- function Trusted
- {
- param ($UserInput)
-
- Add-Type -TypeDefinition $UserInput
- try { $null = New-Object safe_738057 -ErrorAction Ignore } catch {}
- try { $null = New-Object pwnd_738057 -ErrorAction Ignore } catch {}
- }
-
- Trusted -UserInput 'public class safe_738057 { public safe_738057() { System.Environment.SetEnvironmentVariable("pwnd_738057", "False"); } }'
-
- "Hello World"
-'@
- $trustedFile = Join-Path $TestDrive CommandInjectionDebuggingBlocked_System32.ps1
-
- try
- {
- $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
- Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
-
- Set-Content $trustedScriptContent -Path $trustedFile
- $env:pwnd_738057 = "False"
- Set-PSBreakpoint -Script $trustedFile -Line 12 -Action { Trusted -UserInput 'public class pwnd_738057 { public pwnd_738057() { System.Environment.SetEnvironmentVariable("pwnd_738057", "Pwnd"); } }' }
- & $trustedFile
- }
- finally
- {
- Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
- }
-
- $env:pwnd_738057 | Should -Not -Be "Pwnd"
- }
- }
-
Describe "Engine events in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
It "Verifies engine event in constrained language mode, its action runs as constrained" {
@@ -1003,7 +893,7 @@ try
$scriptModuleName = "UntrustedModuleScriptBlockTest"
$scriptModulePath = Join-Path $TestDrive ($scriptModuleName + ".psm1")
@'
- function RunScriptBlock {{
+ function RunScriptBlock {{
$sb = (Get-Command -Name {0}).ScriptBlock
# ScriptBlock trusted function, TrustedFn, is dot sourced into current scope