diff --git a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj
index 95d8ea17f..e7ebfbedb 100644
--- a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj
+++ b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj
@@ -43,7 +43,8 @@
-
+
+
Create
diff --git a/src/cascadia/LocalTests_TerminalApp/TrustCommandlineTests.cpp b/src/cascadia/LocalTests_TerminalApp/TrustCommandlineTests.cpp
new file mode 100644
index 000000000..55a46e6d4
--- /dev/null
+++ b/src/cascadia/LocalTests_TerminalApp/TrustCommandlineTests.cpp
@@ -0,0 +1,81 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+
+#include "../TerminalApp/TerminalPage.h"
+
+using namespace Microsoft::Console;
+using namespace TerminalApp;
+using namespace winrt::TerminalApp;
+using namespace winrt::Microsoft::Terminal::Settings::Model;
+
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+using namespace WEX::Common;
+
+using namespace winrt::Windows::ApplicationModel::DataTransfer;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::Windows::System;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::UI::Text;
+
+namespace winrt
+{
+ namespace MUX = Microsoft::UI::Xaml;
+ namespace WUX = Windows::UI::Xaml;
+ using IInspectable = Windows::Foundation::IInspectable;
+}
+
+namespace TerminalAppLocalTests
+{
+ class TrustCommandlineTests
+ {
+ BEGIN_TEST_CLASS(TrustCommandlineTests)
+ END_TEST_CLASS()
+
+ TEST_METHOD(SimpleTests);
+ TEST_METHOD(TestCommandlineWithArgs);
+ TEST_METHOD(TestCommandlineWithSpaces);
+ TEST_METHOD(WslTests);
+ TEST_METHOD(TestPwshLocation);
+
+ bool trust(std::wstring_view cmdline);
+ };
+
+ bool TrustCommandlineTests::trust(std::wstring_view cmdline)
+ {
+ return implementation::TerminalPage::_isTrustedCommandline(cmdline);
+ }
+
+ void TrustCommandlineTests::SimpleTests()
+ {
+ VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\cmd.exe"));
+ VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"));
+ VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\i-definitely-don't-exist.exe"));
+
+ VERIFY_IS_FALSE(trust(L"cmd.exe"));
+ VERIFY_IS_FALSE(trust(L"powershell.exe"));
+ }
+
+ void TrustCommandlineTests::TestCommandlineWithArgs()
+ {
+ VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /k echo Boo!"));
+ VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /k echo Boo! & cmd.exe"));
+ }
+
+ void TrustCommandlineTests::TestCommandlineWithSpaces()
+ {
+ VERIFY_IS_TRUE(false, L"TODO! implement me.");
+ }
+ void TrustCommandlineTests::WslTests()
+ {
+ VERIFY_IS_TRUE(false, L"TODO! implement me.");
+ }
+ void TrustCommandlineTests::TestPwshLocation()
+ {
+ VERIFY_IS_TRUE(false, L"TODO! implement me.");
+ }
+}
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index 70cd3497a..f47d199fd 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -1506,7 +1506,7 @@ namespace winrt::TerminalApp::implementation
// - C:\windows\system32\cmd.exe /k echo sneaky sneak -> returns false
// - %SystemRoot%\System32\cmd.exe -> returns true
// - %SystemRoot%\System32\wsl.exe -d -> returns true
- static bool _isTrustedCommandline(std::wstring_view commandLine)
+ bool TerminalPage::_isTrustedCommandline(std::wstring_view commandLine)
{
// use C++11 magic statics to make sure we only do this once.
static std::wstring systemDirectory = []() -> std::wstring {
@@ -1544,6 +1544,13 @@ namespace winrt::TerminalApp::implementation
}
}
+ // TODO! Remove the WSL allowing. it's trivial to insert some malicious
+ // stuff into WSL, via .bash_profile, so we're not giving them the (y)
+
+ // TODO! CommandlineToArgv to get the executable from the commandline.
+ // If there's one argc, and it's parent path is %ProgramFiles%, and it
+ // ends in pwsh.exe, then it's fine.
+
// Also, if the path is literally
// %SystemRoot%\System32\wsl.exe -d
// then allow it.
@@ -1601,27 +1608,33 @@ namespace winrt::TerminalApp::implementation
else if (executableFilename == L"pwsh" || executableFilename == L"pwsh.exe")
{
// is does executablePath start with %ProgramFiles%\\PowerShell?
- const std::filesystem::path powershellCoreRoot
+ const std::vector powershellCoreRoots
{
- wil::ExpandEnvironmentStringsW(
+ // Always look in "%ProgramFiles%
+ { wil::ExpandEnvironmentStringsW(L"%ProgramFiles%\\PowerShell") },
+
#if defined(_M_AMD64) || defined(_M_ARM64) // No point in looking for WOW if we're not somewhere it exists
- L"%ProgramFiles(x86)%\\PowerShell"
-#elif defined(_M_ARM64) // same with ARM
- L"%ProgramFiles(Arm)%\\PowerShell"
-#else
- L"%ProgramFiles%\\PowerShell"
+ { wil::ExpandEnvironmentStringsW(L"%ProgramFiles(x86)%\\PowerShell") },
+#endif
+
+#if defined(_M_ARM64) // same with ARM
+ {
+ wil::ExpandEnvironmentStringsW(L"%ProgramFiles(Arm)%\\PowerShell")
+ }
#endif
- )
};
- // Is the path to the commandline actually exactly one of the
- // versions that exists in this directory?
- for (const auto& versionedDir : std::filesystem::directory_iterator(powershellCoreRoot))
+ for (const auto& pwshRoot : powershellCoreRoots)
{
- const auto versionedPath = versionedDir.path();
- if (executablePath.parent_path() == versionedPath)
+ // Is the path to the commandline actually exactly one of the
+ // versions that exists in this directory?
+ for (const auto& versionedDir : std::filesystem::directory_iterator(pwshRoot))
{
- return true;
+ const auto versionedPath = versionedDir.path();
+ if (executablePath.parent_path() == versionedPath)
+ {
+ return true;
+ }
}
}
}
diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h
index 2d3efb9c0..0689743c4 100644
--- a/src/cascadia/TerminalApp/TerminalPage.h
+++ b/src/cascadia/TerminalApp/TerminalPage.h
@@ -19,6 +19,7 @@ namespace TerminalAppLocalTests
{
class TabTests;
class SettingsTests;
+ class TrustCommandlineTests;
};
namespace winrt::TerminalApp::implementation
@@ -417,6 +418,7 @@ namespace winrt::TerminalApp::implementation
void _SetAsDefaultOpenSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
+ static bool _isTrustedCommandline(std::wstring_view commandLine);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
@@ -427,6 +429,7 @@ namespace winrt::TerminalApp::implementation
friend class TerminalAppLocalTests::TabTests;
friend class TerminalAppLocalTests::SettingsTests;
+ friend class TerminalAppLocalTests::TrustCommandlineTests;
};
}