Skip to content

Commit

Permalink
all: fix race when allocating buffer for some windows syscalls
Browse files Browse the repository at this point in the history
Fixes #9753

Change-Id: I6c641ed7ef4f687a108e7d937ab4b9c24d5baf5d
Reviewed-on: https://go-review.googlesource.com/4940
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information
alexbrainman committed Apr 8, 2015
1 parent 2f16ddc commit 32e75ba
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 102 deletions.
22 changes: 10 additions & 12 deletions src/os/file_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
27 changes: 12 additions & 15 deletions src/path/filepath/symlink_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
20 changes: 9 additions & 11 deletions src/syscall/env_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
16 changes: 5 additions & 11 deletions src/syscall/exec_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
98 changes: 45 additions & 53 deletions src/syscall/security_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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.
Expand All @@ -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
}

0 comments on commit 32e75ba

Please sign in to comment.