From 101fc447ecab361897af457c2ecb0c76d2c08ad4 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Mon, 18 Jun 2018 15:33:25 -0700 Subject: [PATCH] Add Hyper-V access check on data directory --- plugins/providers/hyperv/action.rb | 2 ++ .../providers/hyperv/action/check_access.rb | 24 +++++++++++++ plugins/providers/hyperv/errors.rb | 4 +++ .../hyperv/scripts/check_hyperv_access.ps1 | 14 ++++++++ .../scripts/utils/VagrantVM/VagrantVM.psm1 | 36 +++++++++++++++++-- templates/locales/providers_hyperv.yml | 7 ++++ 6 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 plugins/providers/hyperv/action/check_access.rb create mode 100644 plugins/providers/hyperv/scripts/check_hyperv_access.ps1 diff --git a/plugins/providers/hyperv/action.rb b/plugins/providers/hyperv/action.rb index a42c9966a..05d058b35 100644 --- a/plugins/providers/hyperv/action.rb +++ b/plugins/providers/hyperv/action.rb @@ -158,6 +158,7 @@ module VagrantPlugins def self.action_up Vagrant::Action::Builder.new.tap do |b| b.use CheckEnabled + b.use CheckAccess b.use HandleBox b.use ConfigValidate b.use Call, IsState, :not_created do |env1, b1| @@ -290,6 +291,7 @@ module VagrantPlugins autoload :Export, action_root.join("export") autoload :CheckEnabled, action_root.join("check_enabled") + autoload :CheckAccess, action_root.join("check_access") autoload :Configure, action_root.join("configure") autoload :DeleteVM, action_root.join("delete_vm") autoload :Import, action_root.join("import") diff --git a/plugins/providers/hyperv/action/check_access.rb b/plugins/providers/hyperv/action/check_access.rb new file mode 100644 index 000000000..0d1271cf2 --- /dev/null +++ b/plugins/providers/hyperv/action/check_access.rb @@ -0,0 +1,24 @@ +module VagrantPlugins + module HyperV + module Action + class CheckAccess + def initialize(app, env) + @app = app + end + + def call(env) + env[:ui].output("Verifying Hyper-V is accessible...") + result = env[:machine].provider.driver.execute(:check_hyperv_access, + "Path" => Vagrant::Util::Platform.wsl_to_windows_path(env[:machine].data_dir).gsub("/", "\\") + ) + if !result["result"] + raise Errors::SystemAccessRequired, + root_dir: result["root_dir"] + end + + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/hyperv/errors.rb b/plugins/providers/hyperv/errors.rb index ada15cde9..72db0aa5b 100644 --- a/plugins/providers/hyperv/errors.rb +++ b/plugins/providers/hyperv/errors.rb @@ -37,6 +37,10 @@ module VagrantPlugins class WindowsRequired < HyperVError error_key(:windows_required) end + + class SystemAccessRequired < HyperVError + error_key(:system_access_required) + end end end end diff --git a/plugins/providers/hyperv/scripts/check_hyperv_access.ps1 b/plugins/providers/hyperv/scripts/check_hyperv_access.ps1 new file mode 100644 index 000000000..21e51a25b --- /dev/null +++ b/plugins/providers/hyperv/scripts/check_hyperv_access.ps1 @@ -0,0 +1,14 @@ +#Requires -Modules VagrantMessages, VagrantVM + +param( + [parameter (Mandatory=$true)] + [string] $Path +) + +$check = Check-VagrantHyperVAccess -Path $Path +$result = @{ + root_dir = ($Path -split '\\')[0,2] -join '\'; + result = $check +} + +Write-OutputMessage $(ConvertTo-Json $result) diff --git a/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 b/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 index fd11bdba1..813f9c5e7 100644 --- a/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 +++ b/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 @@ -90,7 +90,7 @@ function New-VagrantVMVMCX { # If the config is empty it means the import failed. Attempt to provide # context for failure if($VMConfig -eq $null) { - Error-VagrantVMImport -VMConfigFile $VMConfigFile + Report-ErrorVagrantVMImport -VMConfigFile $VMConfigFile } $VM = $VMConfig.VM @@ -125,7 +125,7 @@ function New-VagrantVMVMCX { if([System.IO.Path]::GetFileName($Drive.Path) -eq [System.IO.Path]::GetFileName($SourcePath)) { $Path = $Drive.Path Hyper-V\Remove-VMHardDiskDrive $Drive - Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath + Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath -Differencing Hyper-V\Add-VMHardDiskDrive -VM $VM -Path $DestinationPath break } @@ -348,7 +348,7 @@ VirtualMachine. The cloned Hyper-V VM. #> } -function Error-VagrantVMImport { +function Report-ErrorVagrantVMImport { param ( [parameter(Mandatory=$true)] [string] $VMConfigFile @@ -702,3 +702,33 @@ Name of the VMSwitch. VirtualMachine. #> } + +function Check-VagrantHyperVAccess { + param ( + [parameter (Mandatory=$true)] + [string] $Path + ) + $acl = Get-ACL -Path $Path + $systemACL = $acl.Access | where {$_.IdentityReference -eq "NT AUTHORITY\System" -and $_.FileSystemRights -eq "FullControl" -and $_.AccessControlType -eq "Allow" -and $_.IsInherited -eq $true} + if($systemACL) { + return $true + } + return $false +<# +.SYNOPSIS + +Check Hyper-V access at given path. + +.DESCRIPTION + +Checks that the given path has the correct access rules for Hyper-V + +.PARAMETER PATH + +Path to check + +.OUTPUT + +Boolean +#> +} diff --git a/templates/locales/providers_hyperv.yml b/templates/locales/providers_hyperv.yml index d4deb6153..dd2a13c44 100644 --- a/templates/locales/providers_hyperv.yml +++ b/templates/locales/providers_hyperv.yml @@ -99,3 +99,10 @@ en: windows_required: |- The Hyper-V provider only works on Windows. Please try to use another provider. + system_access_required: |- + Hyper-V access check has failed for the configured destination. This + is usually caused by running on a non-system drive which is missing + required permissions. Running the following command may resolve the + problem: + + icacls.exe %{root_dir} /T /Q /grant "NT AUTHORITY\SYSTEM:(IO)(CI)(F)"