From 32e75bace0ed5e09819760a76d741430116e821e Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 13 Feb 2015 16:12:07 +1100 Subject: [PATCH] all: fix race when allocating buffer for some windows syscalls Fixes #9753 Change-Id: I6c641ed7ef4f687a108e7d937ab4b9c24d5baf5d Reviewed-on: https://go-review.googlesource.com/4940 Reviewed-by: Brad Fitzpatrick --- src/os/file_windows.go | 22 +++---- src/path/filepath/symlink_windows.go | 27 ++++---- src/syscall/env_windows.go | 20 +++--- src/syscall/exec_windows.go | 16 ++--- src/syscall/security_windows.go | 98 +++++++++++++--------------- 5 files changed, 81 insertions(+), 102 deletions(-) diff --git a/src/os/file_windows.go b/src/os/file_windows.go index fa0736753c..63be8c2e9f 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -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. diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go index 327c2c89a3..4b38f6fac3 100644 --- a/src/path/filepath/symlink_windows.go +++ b/src/path/filepath/symlink_windows.go @@ -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) { diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go index bc21690d9f..1cb475428d 100644 --- a/src/syscall/env_windows.go +++ b/src/syscall/env_windows.go @@ -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 { diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 936aeb577b..cc1abc4d03 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -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 { diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go index b22ecf578e..1625b07ae4 100644 --- a/src/syscall/security_windows.go +++ b/src/syscall/security_windows.go @@ -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 } -- 2.48.1