vss: fix potential crash (not reachable in restic) (#3045)

HasSufficientPrivilegesForVSS() now returns an error
This commit is contained in:
fgma 2020-11-04 22:14:18 +01:00 committed by GitHub
parent a06f5c28c0
commit 916b2d303b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 33 deletions

View File

@ -556,8 +556,8 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
var targetFS fs.FS = fs.Local{} var targetFS fs.FS = fs.Local{}
if runtime.GOOS == "windows" && opts.UseFsSnapshot { if runtime.GOOS == "windows" && opts.UseFsSnapshot {
if !fs.HasSufficientPrivilegesForVSS() { if err = fs.HasSufficientPrivilegesForVSS(); err != nil {
return errors.Fatal("user doesn't have sufficient privileges to use VSS snapshots\n") return err
} }
errorHandler := func(item string, err error) error { errorHandler := func(item string, err error) error {

View File

@ -286,7 +286,7 @@ func TestBackup(t *testing.T) {
} }
func TestBackupWithFilesystemSnapshots(t *testing.T) { func TestBackupWithFilesystemSnapshots(t *testing.T) {
if runtime.GOOS == "windows" && fs.HasSufficientPrivilegesForVSS() { if runtime.GOOS == "windows" && fs.HasSufficientPrivilegesForVSS() == nil {
testBackup(t, true) testBackup(t, true)
} }
} }

View File

@ -26,8 +26,8 @@ type VssSnapshot struct {
} }
// HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS. // HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS.
func HasSufficientPrivilegesForVSS() bool { func HasSufficientPrivilegesForVSS() error {
return false return errors.New("VSS snapshots are only supported on windows")
} }
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't // NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't

View File

@ -686,10 +686,10 @@ func (p *VssSnapshot) GetSnapshotDeviceObject() string {
} }
// initializeCOMInterface initialize an instance of the VSS COM api // initializeCOMInterface initialize an instance of the VSS COM api
func initializeVssCOMInterface() (*ole.IUnknown, uintptr, error) { func initializeVssCOMInterface() (*ole.IUnknown, error) {
vssInstance, err := loadIVssBackupComponentsConstructor() vssInstance, err := loadIVssBackupComponentsConstructor()
if err != nil { if err != nil {
return nil, 0, err return nil, err
} }
// ensure COM is initialized before use // ensure COM is initialized before use
@ -697,22 +697,33 @@ func initializeVssCOMInterface() (*ole.IUnknown, uintptr, error) {
var oleIUnknown *ole.IUnknown var oleIUnknown *ole.IUnknown
result, _, _ := vssInstance.Call(uintptr(unsafe.Pointer(&oleIUnknown))) result, _, _ := vssInstance.Call(uintptr(unsafe.Pointer(&oleIUnknown)))
hresult := HRESULT(result)
return oleIUnknown, result, nil switch hresult {
case S_OK:
case E_ACCESSDENIED:
return oleIUnknown, newVssError(
"The caller does not have sufficient backup privileges or is not an administrator",
hresult)
default:
return oleIUnknown, newVssError("Failed to create VSS instance", hresult)
}
if oleIUnknown == nil {
return nil, newVssError("Failed to initialize COM interface", hresult)
}
return oleIUnknown, nil
} }
// HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS. // HasSufficientPrivilegesForVSS returns nil if the user is allowed to use VSS.
func HasSufficientPrivilegesForVSS() bool { func HasSufficientPrivilegesForVSS() error {
oleIUnknown, result, err := initializeVssCOMInterface() oleIUnknown, err := initializeVssCOMInterface()
if oleIUnknown != nil { if oleIUnknown != nil {
oleIUnknown.Release() oleIUnknown.Release()
} }
if err != nil { return err
return false
}
return !(HRESULT(result) == E_ACCESSDENIED)
} }
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't // NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't
@ -734,24 +745,12 @@ func NewVssSnapshot(
timeoutInMillis := uint32(timeoutInSeconds * 1000) timeoutInMillis := uint32(timeoutInSeconds * 1000)
oleIUnknown, result, err := initializeVssCOMInterface() oleIUnknown, err := initializeVssCOMInterface()
if err != nil { if oleIUnknown != nil {
if oleIUnknown != nil { defer oleIUnknown.Release()
oleIUnknown.Release()
}
return VssSnapshot{}, err
} }
defer oleIUnknown.Release() if err != nil {
return VssSnapshot{}, err
switch HRESULT(result) {
case S_OK:
case E_ACCESSDENIED:
return VssSnapshot{}, newVssTextError(fmt.Sprintf("%s (%#x) The caller does not have "+
"sufficient backup privileges or is not an administrator.", HRESULT(result).Str(),
result))
default:
return VssSnapshot{}, newVssTextError(fmt.Sprintf("Failed to create VSS instance: %s (%#x)",
HRESULT(result).Str(), result))
} }
comInterface, err := queryInterface(oleIUnknown, UUID_IVSS) comInterface, err := queryInterface(oleIUnknown, UUID_IVSS)