From ddd1cdae3914f5a0551f70c54d86856786d80101 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 8 Apr 2015 14:02:03 +1000 Subject: [PATCH] windows: fix race when allocating buffer for some windows syscalls From main repo: https://go-review.googlesource.com/#/c/4940 Change-Id: I56fe7f6aedc0fd350abb94299ad500fcb80c049a Reviewed-on: https://go-review.googlesource.com/8604 Reviewed-by: Brad Fitzpatrick --- windows/env_windows.go | 20 ++++---- windows/exec_windows.go | 18 ++----- windows/security_windows.go | 98 +++++++++++++++++-------------------- 3 files changed, 59 insertions(+), 77 deletions(-) diff --git a/windows/env_windows.go b/windows/env_windows.go index 4789b9de..68d26938 100644 --- a/windows/env_windows.go +++ b/windows/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/windows/exec_windows.go b/windows/exec_windows.go index b9b4271f..3606c3a8 100644 --- a/windows/exec_windows.go +++ b/windows/exec_windows.go @@ -6,8 +6,6 @@ package windows -import "syscall" - // EscapeArg rewrites command line argument s as prescribed // in http://msdn.microsoft.com/en-us/library/ms880421. // This function returns "" (2 double quotes) if s is empty. @@ -85,21 +83,15 @@ 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 "", syscall.EINVAL + if n <= uint32(len(buf)) { + return UTF16ToString(buf[:n]), nil } } - return UTF16ToString(buf[:n]), nil } diff --git a/windows/security_windows.go b/windows/security_windows.go index 23bb02f0..8fe37371 100644 --- a/windows/security_windows.go +++ b/windows/security_windows.go @@ -42,21 +42,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 ( @@ -137,26 +136,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 @@ -198,24 +194,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 ( @@ -327,21 +321,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. @@ -367,19 +360,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 }