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{}
if runtime.GOOS == "windows" && opts.UseFsSnapshot {
if !fs.HasSufficientPrivilegesForVSS() {
return errors.Fatal("user doesn't have sufficient privileges to use VSS snapshots\n")
if err = fs.HasSufficientPrivilegesForVSS(); err != nil {
return err
}
errorHandler := func(item string, err error) error {

View File

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

View File

@ -26,8 +26,8 @@ type VssSnapshot struct {
}
// HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS.
func HasSufficientPrivilegesForVSS() bool {
return false
func HasSufficientPrivilegesForVSS() error {
return errors.New("VSS snapshots are only supported on windows")
}
// 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
func initializeVssCOMInterface() (*ole.IUnknown, uintptr, error) {
func initializeVssCOMInterface() (*ole.IUnknown, error) {
vssInstance, err := loadIVssBackupComponentsConstructor()
if err != nil {
return nil, 0, err
return nil, err
}
// ensure COM is initialized before use
@ -697,22 +697,33 @@ func initializeVssCOMInterface() (*ole.IUnknown, uintptr, error) {
var oleIUnknown *ole.IUnknown
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.
func HasSufficientPrivilegesForVSS() bool {
oleIUnknown, result, err := initializeVssCOMInterface()
// HasSufficientPrivilegesForVSS returns nil if the user is allowed to use VSS.
func HasSufficientPrivilegesForVSS() error {
oleIUnknown, err := initializeVssCOMInterface()
if oleIUnknown != nil {
oleIUnknown.Release()
}
if err != nil {
return false
}
return !(HRESULT(result) == E_ACCESSDENIED)
return err
}
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't
@ -734,24 +745,12 @@ func NewVssSnapshot(
timeoutInMillis := uint32(timeoutInSeconds * 1000)
oleIUnknown, result, err := initializeVssCOMInterface()
if err != nil {
if oleIUnknown != nil {
oleIUnknown.Release()
}
return VssSnapshot{}, err
oleIUnknown, err := initializeVssCOMInterface()
if oleIUnknown != nil {
defer oleIUnknown.Release()
}
defer oleIUnknown.Release()
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))
if err != nil {
return VssSnapshot{}, err
}
comInterface, err := queryInterface(oleIUnknown, UUID_IVSS)