diff --git a/go.mod b/go.mod index 10cbdb9cc6..d4d2998c18 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/containers/conmon v2.0.20+incompatible github.com/containers/gvisor-tap-vsock v0.7.1 github.com/containers/image/v5 v5.29.1-0.20231201205726-671ab94a09ea - github.com/containers/libhvee v0.5.0 + github.com/containers/libhvee v0.6.0 github.com/containers/ocicrypt v1.1.9 github.com/containers/psgo v1.8.0 github.com/containers/storage v1.51.1-0.20231205203947-fe005407c7d5 @@ -116,7 +116,7 @@ require ( github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect diff --git a/go.sum b/go.sum index 37bcb25bd9..6ab0a2476a 100644 --- a/go.sum +++ b/go.sum @@ -264,8 +264,8 @@ github.com/containers/gvisor-tap-vsock v0.7.1 h1:+Rc+sOPplrkQb/BUXeN0ug8TxjgyrIq github.com/containers/gvisor-tap-vsock v0.7.1/go.mod h1:WSSsjcuYZkvP8i0J+Ht3LF8yvysn3krD5zxQ74wz7y0= github.com/containers/image/v5 v5.29.1-0.20231201205726-671ab94a09ea h1:tsXGDybhfKVnQ3vgsuPYhhNu5VnxNlDdLFwx5X1ruSo= github.com/containers/image/v5 v5.29.1-0.20231201205726-671ab94a09ea/go.mod h1:viinaAODpZKsuvRIecjkmgV890VxszevaGiH+m8Qcug= -github.com/containers/libhvee v0.5.0 h1:rDhfG2NI8Q+VgeXht2dXezanxEdpj9pHqYX3vWfOGUw= -github.com/containers/libhvee v0.5.0/go.mod h1:yvU3Em2u1ZLl2VLd2glMIBWriBwfhWsDaRJsvixUIB0= +github.com/containers/libhvee v0.6.0 h1:tUzwSz8R0GjR6IctgDnkTMjdtCk5Mxhpai4Vyv6UeF4= +github.com/containers/libhvee v0.6.0/go.mod h1:f/q1wCdQqOLiK3IZqqBfOD7exMZYBU5pDYsrMa/pSFg= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/luksy v0.0.0-20231030195837-b5a7f79da98b h1:8XvNAm+g7ivwPUkyiHvBs7z356JWpK9a0FDaek86+sY= @@ -423,8 +423,9 @@ github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= diff --git a/pkg/machine/hyperv/config.go b/pkg/machine/hyperv/config.go index 8b8d2336ce..c15ea6a1e4 100644 --- a/pkg/machine/hyperv/config.go +++ b/pkg/machine/hyperv/config.go @@ -32,13 +32,23 @@ func VirtualizationProvider() machine.VirtProvider { func (v HyperVVirtualization) CheckExclusiveActiveVM() (bool, string, error) { vmm := hypervctl.NewVirtualMachineManager() - // Use of GetAll is OK here because we do not want to use the same name - // as something already *actually* configured in hyperv - vms, err := vmm.GetAll() + + // Get all the VMs on disk (json files) + onDiskVMs, err := v.loadFromLocalJson() if err != nil { return false, "", err } - for _, vm := range vms { + for _, onDiskVM := range onDiskVMs { + // lookup if the vm exists in hyperv + exists, vm, err := vmm.GetMachineExists(onDiskVM.Name) + if err != nil { + return false, "", err + } + // hyperv does not know about it, move on + if !exists { // hot path + // TODO should we logrus this to show we found a JSON with no hyperv vm ? + continue + } if vm.IsStarting() || vm.State() == hypervctl.Enabled { return true, vm.ElementName, nil } diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd.go new file mode 100644 index 0000000000..d82fed49f4 --- /dev/null +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd.go @@ -0,0 +1,108 @@ +package hypervctl + +import ( + "encoding/xml" + "fmt" + "strconv" + "strings" + + "github.com/containers/libhvee/pkg/wmiext" + "github.com/containers/podman/v4/pkg/strongunits" +) + +// ResizeDisk takes a diskPath and strongly typed new size and uses powershell +// to change its size. There is no error protection for trying to size a disk +// smaller than the current size. +func ResizeDisk(diskPath string, newSize strongunits.GiB) error { + var ( + service *wmiext.Service + err error + job *wmiext.Instance + ret int32 + ) + + if service, err = NewLocalHyperVService(); err != nil { + return err + } + defer service.Close() + + imms, err := service.GetSingletonInstance("Msvm_ImageManagementService") + if err != nil { + return err + } + defer imms.Close() + + err = imms.BeginInvoke("ResizeVirtualHardDisk"). + In("Path", diskPath). + In("MaxInternalSize", int64(newSize.ToBytes())). + Execute(). + Out("Job", &job). + Out("ReturnValue", &ret). + End() + + if err != nil { + return fmt.Errorf("failed to resize disk: %w", err) + } + return waitVMResult(ret, service, job, "failed to resize disk", nil) +} + +func GetDiskSize(diskPath string) (strongunits.B, error) { + var ( + service *wmiext.Service + err error + job *wmiext.Instance + ret int32 + results string + ) + + if service, err = NewLocalHyperVService(); err != nil { + return 0, err + } + defer service.Close() + imms, err := service.GetSingletonInstance("Msvm_ImageManagementService") + if err != nil { + return 0, err + } + defer imms.Close() + + inv := imms.BeginInvoke("GetVirtualHardDiskSettingData"). + In("Path", diskPath). + Execute(). + Out("Job", &job). + Out("ReturnValue", &ret) + + if err := inv.Error(); err != nil { + return 0, fmt.Errorf("failed to get setting data for disk %s: %q", diskPath, err) + } + + if err := waitVMResult(ret, service, job, "failure waiting on result from disk settings", nil); err != nil { + return 0, err + } + + err = inv.Out("SettingData", &results).End() + if err != nil { + return 0, fmt.Errorf("failed to retrieve setting object payload for disk: %q", err) + } + + type CimSingleInstance struct { + XMLName xml.Name `xml:"INSTANCE"` + Properties []CimKvpItemProperty `xml:"PROPERTY"` + } + + diskSettings := CimSingleInstance{} + if err := xml.Unmarshal([]byte(results), &diskSettings); err != nil { + return 0, fmt.Errorf("unable to parse disk settings xml: %q", err) + } + + for _, prop := range diskSettings.Properties { + if strings.EqualFold(prop.Name, "MaxInternalSize") { + size, err := strconv.ParseUint(prop.Value, 10, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse size in disk settings") + } + return strongunits.B(size), nil + } + } + + return 0, fmt.Errorf("disk settings was missing a size value") +} diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go index 489c57503d..ea7f239488 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go @@ -4,6 +4,7 @@ package hypervctl import ( + "errors" "fmt" "github.com/containers/libhvee/pkg/wmiext" @@ -88,7 +89,25 @@ func (vmm *VirtualMachineManager) Exists(name string) (bool, error) { return false, nil } +// GetMachine is a stub to lookup and get settings for a VM func (vmm *VirtualMachineManager) GetMachine(name string) (*VirtualMachine, error) { + return vmm.getMachine(name) +} + +// GetMachineExists looks for a machine defined in hyperv and returns it if it exists +func (vmm *VirtualMachineManager) GetMachineExists(name string) (bool, *VirtualMachine, error) { + vm, err := vmm.getMachine(name) + if err != nil { + if errors.Is(err, wmiext.ErrNoResults) { + return false, nil, nil + } + return false, nil, err + } + return true, vm, nil +} + +// getMachine looks up a single VM by name +func (vmm *VirtualMachineManager) getMachine(name string) (*VirtualMachine, error) { const wql = "Select * From Msvm_VirtualSystemSettingData Where VirtualSystemType = 'Microsoft:Hyper-V:System:Realized' And ElementName='%s'" vm := &VirtualMachine{} @@ -108,6 +127,9 @@ func (vmm *VirtualMachineManager) GetMachine(name string) (*VirtualMachine, erro settings, err := service.FindFirstInstance(fmt.Sprintf(wql, name)) if err != nil { + if errors.Is(err, wmiext.ErrNoResults) { + return nil, err + } return vm, fmt.Errorf("could not find virtual machine %q: %w", name, err) } defer settings.Close() diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/error.go b/vendor/github.com/containers/libhvee/pkg/wmiext/error.go index 9956c58d2a..ce7a9d10bb 100644 --- a/vendor/github.com/containers/libhvee/pkg/wmiext/error.go +++ b/vendor/github.com/containers/libhvee/pkg/wmiext/error.go @@ -1,6 +1,7 @@ package wmiext import ( + "errors" "fmt" "os" "strings" @@ -158,6 +159,11 @@ var ( wmiModule syscall.Handle ) +// VM Lookup errors +var ( + ErrNoResults = errors.New("no results found") +) + func init() { file := os.ExpandEnv("${windir}\\system32\\wbem\\wmiutils.dll") wmiModule, _ = syscall.LoadLibrary(file) diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/service.go b/vendor/github.com/containers/libhvee/pkg/wmiext/service.go index c173e12526..c58d06c1aa 100644 --- a/vendor/github.com/containers/libhvee/pkg/wmiext/service.go +++ b/vendor/github.com/containers/libhvee/pkg/wmiext/service.go @@ -299,7 +299,7 @@ func (s *Service) FindFirstInstance(wql string) (*Instance, error) { } if instance == nil { - return nil, errors.New("no results found") + return nil, ErrNoResults } return instance, nil diff --git a/vendor/github.com/go-ole/go-ole/SECURITY.md b/vendor/github.com/go-ole/go-ole/SECURITY.md new file mode 100644 index 0000000000..dac281523b --- /dev/null +++ b/vendor/github.com/go-ole/go-ole/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/go-ole/go-ole/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. diff --git a/vendor/github.com/go-ole/go-ole/appveyor.yml b/vendor/github.com/go-ole/go-ole/appveyor.yml index 0d557ac2ff..8df7fa26e3 100644 --- a/vendor/github.com/go-ole/go-ole/appveyor.yml +++ b/vendor/github.com/go-ole/go-ole/appveyor.yml @@ -6,14 +6,9 @@ version: "1.3.0.{build}-alpha-{branch}" -os: Windows Server 2012 R2 +os: Visual Studio 2019 -branches: - only: - - master - - v1.2 - - v1.1 - - v1.0 +build: off skip_tags: true @@ -21,20 +16,40 @@ clone_folder: c:\gopath\src\github.com\go-ole\go-ole environment: GOPATH: c:\gopath - matrix: - - GOARCH: amd64 - GOVERSION: 1.5 - GOROOT: c:\go - DOWNLOADPLATFORM: "x64" + GOROOT: c:\go + DOWNLOADPLATFORM: "x64" -install: - - choco install mingw - - SET PATH=c:\tools\mingw64\bin;%PATH% +before_test: # - Download COM Server - ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip" - 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL - c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat - # - set + +test_script: + - go test -v -cover ./... + # go vet has false positives on unsafe.Pointer with windows/sys. Disabling since it is recommended to use go test instead. + # - go vet ./... + +branches: + only: + - master + - v1.2 + - v1.1 + - v1.0 + +matrix: + allow_failures: + - environment: + GOROOT: C:\go-x86 + DOWNLOADPLATFORM: "x86" + - environment: + GOROOT: C:\go118 + DOWNLOADPLATFORM: "x64" + - environment: + GOROOT: C:\go118-x86 + DOWNLOADPLATFORM: "x86" + +install: - go version - go env - go get -u golang.org/x/tools/cmd/cover @@ -45,10 +60,9 @@ build_script: - cd c:\gopath\src\github.com\go-ole\go-ole - go get -v -t ./... - go build - - go test -v -cover ./... # disable automatic tests -test: off +test: on # disable deployment deploy: off diff --git a/vendor/github.com/go-ole/go-ole/com.go b/vendor/github.com/go-ole/go-ole/com.go index a9bef150a3..cabbac0122 100644 --- a/vendor/github.com/go-ole/go-ole/com.go +++ b/vendor/github.com/go-ole/go-ole/com.go @@ -11,6 +11,7 @@ import ( var ( procCoInitialize = modole32.NewProc("CoInitialize") procCoInitializeEx = modole32.NewProc("CoInitializeEx") + procCoInitializeSecurity = modole32.NewProc("CoInitializeSecurity") procCoUninitialize = modole32.NewProc("CoUninitialize") procCoCreateInstance = modole32.NewProc("CoCreateInstance") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") @@ -37,6 +38,9 @@ var ( procDispatchMessageW = moduser32.NewProc("DispatchMessageW") ) +// This is to enable calling COM Security initialization multiple times +var bSecurityInit bool = false + // coInitialize initializes COM library on current thread. // // MSDN documentation suggests that this function should not be called. Call @@ -68,6 +72,35 @@ func coInitializeEx(coinit uint32) (err error) { return } +// coInitializeSecurity: Registers security and sets the default security values +// for the process. +func coInitializeSecurity(cAuthSvc int32, + dwAuthnLevel uint32, + dwImpLevel uint32, + dwCapabilities uint32) (err error) { + // Check COM Security initialization has done previously + if !bSecurityInit { + // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity + hr, _, _ := procCoInitializeSecurity.Call( + uintptr(0), // Allow *all* VSS writers to communicate back! + uintptr(cAuthSvc), // Default COM authentication service + uintptr(0), // Default COM authorization service + uintptr(0), // Reserved parameter + uintptr(dwAuthnLevel), // Strongest COM authentication level + uintptr(dwImpLevel), // Minimal impersonation abilities + uintptr(0), // Default COM authentication settings + uintptr(dwCapabilities), // Cloaking + uintptr(0)) // eserved parameter + if hr != 0 { + err = NewError(hr) + } else { + // COM Security initialization done make global flag true. + bSecurityInit = true + } + } + return +} + // CoInitialize initializes COM library on current thread. // // MSDN documentation suggests that this function should not be called. Call @@ -96,6 +129,15 @@ func CoUninitialize() { procCoUninitialize.Call() } +// CoInitializeSecurity: Registers security and sets the default security values +// for the process. +func CoInitializeSecurity(cAuthSvc int32, + dwAuthnLevel uint32, + dwImpLevel uint32, + dwCapabilities uint32) (err error) { + return coInitializeSecurity(cAuthSvc, dwAuthnLevel, dwImpLevel, dwCapabilities) +} + // CoTaskMemFree frees memory pointer. func CoTaskMemFree(memptr uintptr) { procCoTaskMemFree.Call(memptr) diff --git a/vendor/github.com/go-ole/go-ole/idispatch_windows.go b/vendor/github.com/go-ole/go-ole/idispatch_windows.go index b399f04791..649c0734ff 100644 --- a/vendor/github.com/go-ole/go-ole/idispatch_windows.go +++ b/vendor/github.com/go-ole/go-ole/idispatch_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package ole @@ -92,7 +93,7 @@ func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{} case int8: vargs[n] = NewVariant(VT_I1, int64(v.(int8))) case *int8: - vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8))))) + vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int8))))) case int16: vargs[n] = NewVariant(VT_I2, int64(v.(int16))) case *int16: diff --git a/vendor/github.com/go-ole/go-ole/variant.go b/vendor/github.com/go-ole/go-ole/variant.go index 967a23fea9..a2c8402f7b 100644 --- a/vendor/github.com/go-ole/go-ole/variant.go +++ b/vendor/github.com/go-ole/go-ole/variant.go @@ -99,7 +99,7 @@ func (v *VARIANT) Value() interface{} { case VT_DISPATCH: return v.ToIDispatch() case VT_BOOL: - return v.Val != 0 + return (v.Val & 0xffff) != 0 } return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index e881c90eba..0ad2b8f2ce 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -308,7 +308,7 @@ github.com/containers/image/v5/transports github.com/containers/image/v5/transports/alltransports github.com/containers/image/v5/types github.com/containers/image/v5/version -# github.com/containers/libhvee v0.5.0 +# github.com/containers/libhvee v0.6.0 ## explicit; go 1.18 github.com/containers/libhvee/pkg/hypervctl github.com/containers/libhvee/pkg/kvp/ginsu @@ -542,7 +542,7 @@ github.com/go-logr/logr/funcr # github.com/go-logr/stdr v1.2.2 ## explicit; go 1.16 github.com/go-logr/stdr -# github.com/go-ole/go-ole v1.2.6 +# github.com/go-ole/go-ole v1.3.0 ## explicit; go 1.12 github.com/go-ole/go-ole github.com/go-ole/go-ole/oleutil