SEBWIN-316: Implemented rudimentary VM detection.
This commit is contained in:
parent
bc0170976c
commit
18fb059ddc
10 changed files with 240 additions and 13 deletions
|
@ -88,6 +88,8 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
MessageBox_StartupErrorTitle,
|
MessageBox_StartupErrorTitle,
|
||||||
MessageBox_UnexpectedConfigurationError,
|
MessageBox_UnexpectedConfigurationError,
|
||||||
MessageBox_UnexpectedConfigurationErrorTitle,
|
MessageBox_UnexpectedConfigurationErrorTitle,
|
||||||
|
MessageBox_VirtualMachineNotAllowed,
|
||||||
|
MessageBox_VirtualMachineNotAllowedTitle,
|
||||||
MessageBox_YesButton,
|
MessageBox_YesButton,
|
||||||
Notification_AboutTooltip,
|
Notification_AboutTooltip,
|
||||||
Notification_LogTooltip,
|
Notification_LogTooltip,
|
||||||
|
@ -117,6 +119,7 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
OperationStatus_StopMouseInterception,
|
OperationStatus_StopMouseInterception,
|
||||||
OperationStatus_TerminateBrowser,
|
OperationStatus_TerminateBrowser,
|
||||||
OperationStatus_TerminateShell,
|
OperationStatus_TerminateShell,
|
||||||
|
OperationStatus_ValidateVirtualMachinePolicy,
|
||||||
OperationStatus_WaitExplorerStartup,
|
OperationStatus_WaitExplorerStartup,
|
||||||
OperationStatus_WaitExplorerTermination,
|
OperationStatus_WaitExplorerTermination,
|
||||||
OperationStatus_WaitRuntimeDisconnection,
|
OperationStatus_WaitRuntimeDisconnection,
|
||||||
|
|
|
@ -222,6 +222,12 @@
|
||||||
<Entry key="MessageBox_UnexpectedConfigurationErrorTitle">
|
<Entry key="MessageBox_UnexpectedConfigurationErrorTitle">
|
||||||
Configuration Error
|
Configuration Error
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="MessageBox_VirtualMachineNotAllowed">
|
||||||
|
This computer appears to be a virtual machine. The currently active configuration does not allow SEB to be run in a virtual machine.
|
||||||
|
</Entry>
|
||||||
|
<Entry key="MessageBox_VirtualMachineNotAllowedTitle">
|
||||||
|
Virtual Machine Detected
|
||||||
|
</Entry>
|
||||||
<Entry key="MessageBox_YesButton">
|
<Entry key="MessageBox_YesButton">
|
||||||
Yes
|
Yes
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -309,6 +315,9 @@
|
||||||
<Entry key="OperationStatus_TerminateShell">
|
<Entry key="OperationStatus_TerminateShell">
|
||||||
Terminating user interface
|
Terminating user interface
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="OperationStatus_ValidateVirtualMachinePolicy">
|
||||||
|
Validating virtual machine policy
|
||||||
|
</Entry>
|
||||||
<Entry key="OperationStatus_WaitExplorerStartup">
|
<Entry key="OperationStatus_WaitExplorerStartup">
|
||||||
Waiting for Windows explorer to start up
|
Waiting for Windows explorer to start up
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -7,16 +7,135 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Runtime.Operations;
|
||||||
|
using SafeExamBrowser.Settings;
|
||||||
|
using SafeExamBrowser.Settings.Security;
|
||||||
|
using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class VirtualMachineOperationTests
|
public class VirtualMachineOperationTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
private Mock<IVirtualMachineDetector> detector;
|
||||||
public void TODO()
|
private Mock<ILogger> logger;
|
||||||
|
private SessionContext context;
|
||||||
|
private VirtualMachineOperation sut;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
{
|
{
|
||||||
Assert.Fail();
|
detector = new Mock<IVirtualMachineDetector>();
|
||||||
|
logger = new Mock<ILogger>();
|
||||||
|
context = new SessionContext();
|
||||||
|
|
||||||
|
context.Next = new SessionConfiguration();
|
||||||
|
context.Next.Settings = new AppSettings();
|
||||||
|
|
||||||
|
sut = new VirtualMachineOperation(detector.Object, logger.Object, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Perform_MustAbortIfVirtualMachineNotAllowed()
|
||||||
|
{
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Deny;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(true);
|
||||||
|
|
||||||
|
var result = sut.Perform();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.Once);
|
||||||
|
Assert.AreEqual(OperationResult.Aborted, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Perform_MustSucceedIfVirtualMachineAllowed()
|
||||||
|
{
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Allow;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(true);
|
||||||
|
|
||||||
|
var result = sut.Perform();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.AtMostOnce);
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Allow;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(false);
|
||||||
|
|
||||||
|
result = sut.Perform();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.AtMost(2));
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Perform_MustSucceedIfNotAVirtualMachine()
|
||||||
|
{
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Deny;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(false);
|
||||||
|
|
||||||
|
var result = sut.Perform();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.Once);
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Repeat_MustAbortIfVirtualMachineNotAllowed()
|
||||||
|
{
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Deny;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(true);
|
||||||
|
|
||||||
|
var result = sut.Repeat();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.Once);
|
||||||
|
Assert.AreEqual(OperationResult.Aborted, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Repeat_MustSucceedIfVirtualMachineAllowed()
|
||||||
|
{
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Allow;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(true);
|
||||||
|
|
||||||
|
var result = sut.Repeat();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.AtMostOnce);
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Allow;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(false);
|
||||||
|
|
||||||
|
result = sut.Repeat();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.AtMost(2));
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Repeat_MustSucceedIfNotAVirtualMachine()
|
||||||
|
{
|
||||||
|
context.Next.Settings.Security.VirtualMachinePolicy = VirtualMachinePolicy.Deny;
|
||||||
|
detector.Setup(d => d.IsVirtualMachine()).Returns(false);
|
||||||
|
|
||||||
|
var result = sut.Repeat();
|
||||||
|
|
||||||
|
detector.Verify(d => d.IsVirtualMachine(), Times.Once);
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Revert_MustDoNothing()
|
||||||
|
{
|
||||||
|
var result = sut.Revert();
|
||||||
|
|
||||||
|
detector.VerifyNoOtherCalls();
|
||||||
|
logger.VerifyNoOtherCalls();
|
||||||
|
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
var sessionContext = new SessionContext();
|
var sessionContext = new SessionContext();
|
||||||
var uiFactory = new UserInterfaceFactory(text);
|
var uiFactory = new UserInterfaceFactory(text);
|
||||||
var userInfo = new UserInfo(ModuleLogger(nameof(UserInfo)));
|
var userInfo = new UserInfo(ModuleLogger(nameof(UserInfo)));
|
||||||
|
var vmDetector = new VirtualMachineDetector(ModuleLogger(nameof(VirtualMachineDetector)), systemInfo);
|
||||||
|
|
||||||
var bootstrapOperations = new Queue<IOperation>();
|
var bootstrapOperations = new Queue<IOperation>();
|
||||||
var sessionOperations = new Queue<IRepeatableOperation>();
|
var sessionOperations = new Queue<IRepeatableOperation>();
|
||||||
|
@ -83,7 +84,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext));
|
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost, sessionContext));
|
||||||
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new HashAlgorithm(), logger, sessionContext));
|
sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new HashAlgorithm(), logger, sessionContext));
|
||||||
sessionOperations.Enqueue(new VirtualMachineOperation(sessionContext));
|
sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext));
|
||||||
sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo));
|
sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo));
|
||||||
sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS));
|
sessionOperations.Enqueue(new ClientTerminationOperation(logger, processFactory, proxyFactory, runtimeHost, sessionContext, THIRTY_SECONDS));
|
||||||
sessionOperations.Enqueue(new KioskModeOperation(desktopFactory, explorerShell, logger, processFactory, sessionContext));
|
sessionOperations.Enqueue(new KioskModeOperation(desktopFactory, explorerShell, logger, processFactory, sessionContext));
|
||||||
|
|
|
@ -8,34 +8,65 @@
|
||||||
|
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Runtime.Operations.Events;
|
||||||
|
using SafeExamBrowser.Settings.Security;
|
||||||
|
using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class VirtualMachineOperation : SessionOperation
|
internal class VirtualMachineOperation : SessionOperation
|
||||||
{
|
{
|
||||||
//private IVirtualMachineDetector detector;
|
private IVirtualMachineDetector detector;
|
||||||
|
private ILogger logger;
|
||||||
|
|
||||||
public VirtualMachineOperation(/*IVirtualMachineDetector detector, */SessionContext context) : base(context)
|
public VirtualMachineOperation(IVirtualMachineDetector detector, ILogger logger, SessionContext context) : base(context)
|
||||||
{
|
{
|
||||||
//this.detector = detector;
|
this.detector = detector;
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
public override event ActionRequiredEventHandler ActionRequired;
|
||||||
public override event StatusChangedEventHandler StatusChanged { add { } remove { } }
|
public override event StatusChangedEventHandler StatusChanged;
|
||||||
|
|
||||||
public override OperationResult Perform()
|
public override OperationResult Perform()
|
||||||
{
|
{
|
||||||
return OperationResult.Success;
|
return ValidatePolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OperationResult Repeat()
|
public override OperationResult Repeat()
|
||||||
{
|
{
|
||||||
return OperationResult.Success;
|
return ValidatePolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OperationResult Revert()
|
public override OperationResult Revert()
|
||||||
{
|
{
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OperationResult ValidatePolicy()
|
||||||
|
{
|
||||||
|
logger.Info($"Validating virtual machine policy...");
|
||||||
|
StatusChanged?.Invoke(TextKey.OperationStatus_ValidateVirtualMachinePolicy);
|
||||||
|
|
||||||
|
if (Context.Next.Settings.Security.VirtualMachinePolicy == VirtualMachinePolicy.Deny && detector.IsVirtualMachine())
|
||||||
|
{
|
||||||
|
var args = new MessageEventArgs
|
||||||
|
{
|
||||||
|
Icon = MessageBoxIcon.Error,
|
||||||
|
Message = TextKey.MessageBox_VirtualMachineNotAllowed,
|
||||||
|
Title = TextKey.MessageBox_VirtualMachineNotAllowedTitle
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.Error("Detected virtual machine while SEB is not allowed to be run in a virtual machine! Aborting startup...");
|
||||||
|
ActionRequired?.Invoke(args);
|
||||||
|
|
||||||
|
return OperationResult.Aborted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.SystemComponents.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides functionality related to virtual machine detection.
|
||||||
|
/// </summary>
|
||||||
|
public interface IVirtualMachineDetector
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the computer is in fact a virtual machine.
|
||||||
|
/// </summary>
|
||||||
|
bool IsVirtualMachine();
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Audio\Events\VolumeChangedEventHandler.cs" />
|
<Compile Include="Audio\Events\VolumeChangedEventHandler.cs" />
|
||||||
<Compile Include="Audio\IAudio.cs" />
|
<Compile Include="Audio\IAudio.cs" />
|
||||||
|
<Compile Include="IVirtualMachineDetector.cs" />
|
||||||
<Compile Include="PowerSupply\Events\StatusChangedEventHandler.cs" />
|
<Compile Include="PowerSupply\Events\StatusChangedEventHandler.cs" />
|
||||||
<Compile Include="PowerSupply\IPowerSupply.cs" />
|
<Compile Include="PowerSupply\IPowerSupply.cs" />
|
||||||
<Compile Include="PowerSupply\BatteryChargeStatus.cs" />
|
<Compile Include="PowerSupply\BatteryChargeStatus.cs" />
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SystemInfo.cs" />
|
<Compile Include="SystemInfo.cs" />
|
||||||
<Compile Include="UserInfo.cs" />
|
<Compile Include="UserInfo.cs" />
|
||||||
|
<Compile Include="VirtualMachineDetector.cs" />
|
||||||
<Compile Include="WirelessNetwork\WirelessAdapter.cs" />
|
<Compile Include="WirelessNetwork\WirelessAdapter.cs" />
|
||||||
<Compile Include="WirelessNetwork\WirelessNetwork.cs" />
|
<Compile Include="WirelessNetwork\WirelessNetwork.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -45,8 +45,8 @@ namespace SafeExamBrowser.SystemComponents
|
||||||
|
|
||||||
private void InitializeMachineInfo()
|
private void InitializeMachineInfo()
|
||||||
{
|
{
|
||||||
var model = string.Empty;
|
var model = default(string);
|
||||||
var systemFamily = string.Empty;
|
var systemFamily = default(string);
|
||||||
|
|
||||||
using (var searcher = new ManagementObjectSearcher("Select * from Win32_ComputerSystem"))
|
using (var searcher = new ManagementObjectSearcher("Select * from Win32_ComputerSystem"))
|
||||||
using (var results = searcher.Get())
|
using (var results = searcher.Get())
|
||||||
|
|
41
SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs
Normal file
41
SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.SystemComponents
|
||||||
|
{
|
||||||
|
public class VirtualMachineDetector : IVirtualMachineDetector
|
||||||
|
{
|
||||||
|
private ILogger logger;
|
||||||
|
private ISystemInfo systemInfo;
|
||||||
|
|
||||||
|
public VirtualMachineDetector(ILogger logger, ISystemInfo systemInfo)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.systemInfo = systemInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsVirtualMachine()
|
||||||
|
{
|
||||||
|
var isVirtualMachine = false;
|
||||||
|
var manufacturer = systemInfo.Manufacturer.ToLower();
|
||||||
|
var model = systemInfo.Model.ToLower();
|
||||||
|
|
||||||
|
isVirtualMachine |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface");
|
||||||
|
isVirtualMachine |= manufacturer.Contains("vmware");
|
||||||
|
isVirtualMachine |= manufacturer.Contains("parallels software");
|
||||||
|
isVirtualMachine |= model.Contains("virtualbox");
|
||||||
|
|
||||||
|
logger.Debug($"Computer '{systemInfo.Name}' appears to {(isVirtualMachine ? "" : "not ")}be a virtual machine.");
|
||||||
|
|
||||||
|
return isVirtualMachine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue