]> Cypherpunks repositories - gostls13.git/commitdiff
all: fix race when allocating buffer for some windows syscalls
authorAlex Brainman <alex.brainman@gmail.com>
Fri, 13 Feb 2015 05:12:07 +0000 (16:12 +1100)
committerAlex Brainman <alex.brainman@gmail.com>
Wed, 8 Apr 2015 02:06:31 +0000 (02:06 +0000)
Fixes #9753

Change-Id: I6c641ed7ef4f687a108e7d937ab4b9c24d5baf5d
Reviewed-on: https://go-review.googlesource.com/4940
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/os/file_windows.go
src/path/filepath/symlink_windows.go
src/syscall/env_windows.go
src/syscall/exec_windows.go
src/syscall/security_windows.go

index fa0736753c857aaf8d13cca109d52ca5564ea268..63be8c2e9fc6005800c460207d0dc3ab2bbd16e0 100644 (file)
@@ -481,20 +481,18 @@ func Pipe() (r *File, w *File, err error) {
 
 // TempDir returns the default directory to use for temporary files.
 func TempDir() string {
-       const pathSep = '\\'
-       dirw := make([]uint16, syscall.MAX_PATH)
-       n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-       if n > uint32(len(dirw)) {
-               dirw = make([]uint16, n)
-               n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-               if n > uint32(len(dirw)) {
-                       n = 0
+       n := uint32(syscall.MAX_PATH)
+       for {
+               b := make([]uint16, n)
+               n, _ = syscall.GetTempPath(uint32(len(b)), &b[0])
+               if n > uint32(len(b)) {
+                       continue
                }
+               if n > 0 && b[n-1] == '\\' {
+                       n--
+               }
+               return string(utf16.Decode(b[:n]))
        }
-       if n > 0 && dirw[n-1] == pathSep {
-               n--
-       }
-       return string(utf16.Decode(dirw[0:n]))
 }
 
 // Link creates newname as a hard link to the oldname file.
index 327c2c89a37eddd1b28f44868491a4ce5bc69dcc..4b38f6fac3f33002ae1f06188316661c30affbc1 100644 (file)
@@ -14,18 +14,17 @@ func toShort(path string) (string, error) {
                return "", err
        }
        b := p // GetShortPathName says we can reuse buffer
-       n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
-       if err != nil {
-               return "", err
-       }
-       if n > uint32(len(b)) {
-               b = make([]uint16, n)
+       n := uint32(len(b))
+       for {
                n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
                if err != nil {
                        return "", err
                }
+               if n <= uint32(len(b)) {
+                       return syscall.UTF16ToString(b[:n]), nil
+               }
+               b = make([]uint16, n)
        }
-       return syscall.UTF16ToString(b), nil
 }
 
 func toLong(path string) (string, error) {
@@ -34,19 +33,17 @@ func toLong(path string) (string, error) {
                return "", err
        }
        b := p // GetLongPathName says we can reuse buffer
-       n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
-       if err != nil {
-               return "", err
-       }
-       if n > uint32(len(b)) {
-               b = make([]uint16, n)
+       n := uint32(len(b))
+       for {
                n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
                if err != nil {
                        return "", err
                }
+               if n <= uint32(len(b)) {
+                       return syscall.UTF16ToString(b[:n]), nil
+               }
+               b = make([]uint16, n)
        }
-       b = b[:n]
-       return syscall.UTF16ToString(b), nil
 }
 
 func evalSymlinks(path string) (string, error) {
index bc21690d9fd70e583f8fc460b99bc3ff292f7d86..1cb475428d73ad5b7f8accb4e252b3009dff133a 100644 (file)
@@ -16,19 +16,17 @@ func Getenv(key string) (value string, found bool) {
        if err != nil {
                return "", false
        }
-       b := make([]uint16, 100)
-       n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-       if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
-               return "", false
-       }
-       if n > uint32(len(b)) {
-               b = make([]uint16, n)
-               n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-               if n > uint32(len(b)) {
-                       n = 0
+       n := uint32(100)
+       for {
+               b := make([]uint16, n)
+               n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
+               if n == 0 && err == ERROR_ENVVAR_NOT_FOUND {
+                       return "", false
+               }
+               if n <= uint32(len(b)) {
+                       return string(utf16.Decode(b[:n])), true
                }
        }
-       return string(utf16.Decode(b[0:n])), true
 }
 
 func Setenv(key, value string) error {
index 936aeb577bc1c2fd76b55273117854a6b96ad059..cc1abc4d0354359d423b4e2c9dbbf8c82c365fc4 100644 (file)
@@ -135,23 +135,17 @@ func FullPath(name string) (path string, err error) {
        if err != nil {
                return "", err
        }
-       buf := make([]uint16, 100)
-       n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
-       if err != nil {
-               return "", err
-       }
-       if n > uint32(len(buf)) {
-               // Windows is asking for bigger buffer.
-               buf = make([]uint16, n)
+       n := uint32(100)
+       for {
+               buf := make([]uint16, n)
                n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
                if err != nil {
                        return "", err
                }
-               if n > uint32(len(buf)) {
-                       return "", EINVAL
+               if n <= uint32(len(buf)) {
+                       return UTF16ToString(buf[:n]), nil
                }
        }
-       return UTF16ToString(buf[:n]), nil
 }
 
 func isSlash(c uint8) bool {
index b22ecf578e0a08b779ea3e34a19a5c8002ffe055..1625b07ae4b949cd45954d4166462f77db5aa8b6 100644 (file)
@@ -41,21 +41,20 @@ func TranslateAccountName(username string, from, to uint32, initSize int) (strin
        if e != nil {
                return "", e
        }
-       b := make([]uint16, 50)
-       n := uint32(len(b))
-       e = TranslateName(u, from, to, &b[0], &n)
-       if e != nil {
+       n := uint32(50)
+       for {
+               b := make([]uint16, n)
+               e = TranslateName(u, from, to, &b[0], &n)
+               if e == nil {
+                       return UTF16ToString(b[:n]), nil
+               }
                if e != ERROR_INSUFFICIENT_BUFFER {
                        return "", e
                }
-               // make receive buffers of requested size and try again
-               b = make([]uint16, n)
-               e = TranslateName(u, from, to, &b[0], &n)
-               if e != nil {
+               if n <= uint32(len(b)) {
                        return "", e
                }
        }
-       return UTF16ToString(b), nil
 }
 
 const (
@@ -136,26 +135,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
                        return nil, "", 0, e
                }
        }
-       db := make([]uint16, 50)
-       dn := uint32(len(db))
-       b := make([]byte, 50)
-       n := uint32(len(b))
-       sid = (*SID)(unsafe.Pointer(&b[0]))
-       e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-       if e != nil {
+       n := uint32(50)
+       dn := uint32(50)
+       for {
+               b := make([]byte, n)
+               db := make([]uint16, dn)
+               sid = (*SID)(unsafe.Pointer(&b[0]))
+               e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+               if e == nil {
+                       return sid, UTF16ToString(db), accType, nil
+               }
                if e != ERROR_INSUFFICIENT_BUFFER {
                        return nil, "", 0, e
                }
-               // make receive buffers of requested size and try again
-               b = make([]byte, n)
-               sid = (*SID)(unsafe.Pointer(&b[0]))
-               db = make([]uint16, dn)
-               e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-               if e != nil {
+               if n <= uint32(len(b)) {
                        return nil, "", 0, e
                }
        }
-       return sid, UTF16ToString(db), accType, nil
 }
 
 // String converts sid to a string format
@@ -197,24 +193,22 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui
                        return "", "", 0, err
                }
        }
-       b := make([]uint16, 50)
-       n := uint32(len(b))
-       db := make([]uint16, 50)
-       dn := uint32(len(db))
-       e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
-       if e != nil {
+       n := uint32(50)
+       dn := uint32(50)
+       for {
+               b := make([]uint16, n)
+               db := make([]uint16, dn)
+               e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+               if e == nil {
+                       return UTF16ToString(b), UTF16ToString(db), accType, nil
+               }
                if e != ERROR_INSUFFICIENT_BUFFER {
                        return "", "", 0, e
                }
-               // make receive buffers of requested size and try again
-               b = make([]uint16, n)
-               db = make([]uint16, dn)
-               e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
-               if e != nil {
+               if n <= uint32(len(b)) {
                        return "", "", 0, e
                }
        }
-       return UTF16ToString(b), UTF16ToString(db), accType, nil
 }
 
 const (
@@ -326,21 +320,20 @@ func (t Token) Close() error {
 
 // getInfo retrieves a specified type of information about an access token.
 func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
-       b := make([]byte, initSize)
-       var n uint32
-       e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-       if e != nil {
+       n := uint32(initSize)
+       for {
+               b := make([]byte, n)
+               e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+               if e == nil {
+                       return unsafe.Pointer(&b[0]), nil
+               }
                if e != ERROR_INSUFFICIENT_BUFFER {
                        return nil, e
                }
-               // make receive buffers of requested size and try again
-               b = make([]byte, n)
-               e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-               if e != nil {
+               if n <= uint32(len(b)) {
                        return nil, e
                }
        }
-       return unsafe.Pointer(&b[0]), nil
 }
 
 // GetTokenUser retrieves access token t user account information.
@@ -366,19 +359,18 @@ func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
 // GetUserProfileDirectory retrieves path to the
 // root directory of the access token t user's profile.
 func (t Token) GetUserProfileDirectory() (string, error) {
-       b := make([]uint16, 100)
-       n := uint32(len(b))
-       e := GetUserProfileDirectory(t, &b[0], &n)
-       if e != nil {
+       n := uint32(100)
+       for {
+               b := make([]uint16, n)
+               e := GetUserProfileDirectory(t, &b[0], &n)
+               if e == nil {
+                       return UTF16ToString(b), nil
+               }
                if e != ERROR_INSUFFICIENT_BUFFER {
                        return "", e
                }
-               // make receive buffers of requested size and try again
-               b = make([]uint16, n)
-               e = GetUserProfileDirectory(t, &b[0], &n)
-               if e != nil {
+               if n <= uint32(len(b)) {
                        return "", e
                }
        }
-       return UTF16ToString(b), nil
 }