Skip to content

Commit 32e75ba

Browse files
committed
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 <[email protected]>
1 parent 2f16ddc commit 32e75ba

File tree

5 files changed

+81
-102
lines changed

5 files changed

+81
-102
lines changed

src/os/file_windows.go

+10-12
Original file line numberDiff line numberDiff line change
@@ -481,20 +481,18 @@ func Pipe() (r *File, w *File, err error) {
481481

482482
// TempDir returns the default directory to use for temporary files.
483483
func TempDir() string {
484-
const pathSep = '\\'
485-
dirw := make([]uint16, syscall.MAX_PATH)
486-
n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
487-
if n > uint32(len(dirw)) {
488-
dirw = make([]uint16, n)
489-
n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
490-
if n > uint32(len(dirw)) {
491-
n = 0
484+
n := uint32(syscall.MAX_PATH)
485+
for {
486+
b := make([]uint16, n)
487+
n, _ = syscall.GetTempPath(uint32(len(b)), &b[0])
488+
if n > uint32(len(b)) {
489+
continue
492490
}
491+
if n > 0 && b[n-1] == '\\' {
492+
n--
493+
}
494+
return string(utf16.Decode(b[:n]))
493495
}
494-
if n > 0 && dirw[n-1] == pathSep {
495-
n--
496-
}
497-
return string(utf16.Decode(dirw[0:n]))
498496
}
499497

500498
// Link creates newname as a hard link to the oldname file.

src/path/filepath/symlink_windows.go

+12-15
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,17 @@ func toShort(path string) (string, error) {
1414
return "", err
1515
}
1616
b := p // GetShortPathName says we can reuse buffer
17-
n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
18-
if err != nil {
19-
return "", err
20-
}
21-
if n > uint32(len(b)) {
22-
b = make([]uint16, n)
17+
n := uint32(len(b))
18+
for {
2319
n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
2420
if err != nil {
2521
return "", err
2622
}
23+
if n <= uint32(len(b)) {
24+
return syscall.UTF16ToString(b[:n]), nil
25+
}
26+
b = make([]uint16, n)
2727
}
28-
return syscall.UTF16ToString(b), nil
2928
}
3029

3130
func toLong(path string) (string, error) {
@@ -34,19 +33,17 @@ func toLong(path string) (string, error) {
3433
return "", err
3534
}
3635
b := p // GetLongPathName says we can reuse buffer
37-
n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
38-
if err != nil {
39-
return "", err
40-
}
41-
if n > uint32(len(b)) {
42-
b = make([]uint16, n)
36+
n := uint32(len(b))
37+
for {
4338
n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
4439
if err != nil {
4540
return "", err
4641
}
42+
if n <= uint32(len(b)) {
43+
return syscall.UTF16ToString(b[:n]), nil
44+
}
45+
b = make([]uint16, n)
4746
}
48-
b = b[:n]
49-
return syscall.UTF16ToString(b), nil
5047
}
5148

5249
func evalSymlinks(path string) (string, error) {

src/syscall/env_windows.go

+9-11
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,17 @@ func Getenv(key string) (value string, found bool) {
1616
if err != nil {
1717
return "", false
1818
}
19-
b := make([]uint16, 100)
20-
n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
21-
if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
22-
return "", false
23-
}
24-
if n > uint32(len(b)) {
25-
b = make([]uint16, n)
26-
n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
27-
if n > uint32(len(b)) {
28-
n = 0
19+
n := uint32(100)
20+
for {
21+
b := make([]uint16, n)
22+
n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
23+
if n == 0 && err == ERROR_ENVVAR_NOT_FOUND {
24+
return "", false
25+
}
26+
if n <= uint32(len(b)) {
27+
return string(utf16.Decode(b[:n])), true
2928
}
3029
}
31-
return string(utf16.Decode(b[0:n])), true
3230
}
3331

3432
func Setenv(key, value string) error {

src/syscall/exec_windows.go

+5-11
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,17 @@ func FullPath(name string) (path string, err error) {
135135
if err != nil {
136136
return "", err
137137
}
138-
buf := make([]uint16, 100)
139-
n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
140-
if err != nil {
141-
return "", err
142-
}
143-
if n > uint32(len(buf)) {
144-
// Windows is asking for bigger buffer.
145-
buf = make([]uint16, n)
138+
n := uint32(100)
139+
for {
140+
buf := make([]uint16, n)
146141
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
147142
if err != nil {
148143
return "", err
149144
}
150-
if n > uint32(len(buf)) {
151-
return "", EINVAL
145+
if n <= uint32(len(buf)) {
146+
return UTF16ToString(buf[:n]), nil
152147
}
153148
}
154-
return UTF16ToString(buf[:n]), nil
155149
}
156150

157151
func isSlash(c uint8) bool {

src/syscall/security_windows.go

+45-53
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,20 @@ func TranslateAccountName(username string, from, to uint32, initSize int) (strin
4141
if e != nil {
4242
return "", e
4343
}
44-
b := make([]uint16, 50)
45-
n := uint32(len(b))
46-
e = TranslateName(u, from, to, &b[0], &n)
47-
if e != nil {
44+
n := uint32(50)
45+
for {
46+
b := make([]uint16, n)
47+
e = TranslateName(u, from, to, &b[0], &n)
48+
if e == nil {
49+
return UTF16ToString(b[:n]), nil
50+
}
4851
if e != ERROR_INSUFFICIENT_BUFFER {
4952
return "", e
5053
}
51-
// make receive buffers of requested size and try again
52-
b = make([]uint16, n)
53-
e = TranslateName(u, from, to, &b[0], &n)
54-
if e != nil {
54+
if n <= uint32(len(b)) {
5555
return "", e
5656
}
5757
}
58-
return UTF16ToString(b), nil
5958
}
6059

6160
const (
@@ -136,26 +135,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
136135
return nil, "", 0, e
137136
}
138137
}
139-
db := make([]uint16, 50)
140-
dn := uint32(len(db))
141-
b := make([]byte, 50)
142-
n := uint32(len(b))
143-
sid = (*SID)(unsafe.Pointer(&b[0]))
144-
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
145-
if e != nil {
138+
n := uint32(50)
139+
dn := uint32(50)
140+
for {
141+
b := make([]byte, n)
142+
db := make([]uint16, dn)
143+
sid = (*SID)(unsafe.Pointer(&b[0]))
144+
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
145+
if e == nil {
146+
return sid, UTF16ToString(db), accType, nil
147+
}
146148
if e != ERROR_INSUFFICIENT_BUFFER {
147149
return nil, "", 0, e
148150
}
149-
// make receive buffers of requested size and try again
150-
b = make([]byte, n)
151-
sid = (*SID)(unsafe.Pointer(&b[0]))
152-
db = make([]uint16, dn)
153-
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
154-
if e != nil {
151+
if n <= uint32(len(b)) {
155152
return nil, "", 0, e
156153
}
157154
}
158-
return sid, UTF16ToString(db), accType, nil
159155
}
160156

161157
// String converts sid to a string format
@@ -197,24 +193,22 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui
197193
return "", "", 0, err
198194
}
199195
}
200-
b := make([]uint16, 50)
201-
n := uint32(len(b))
202-
db := make([]uint16, 50)
203-
dn := uint32(len(db))
204-
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
205-
if e != nil {
196+
n := uint32(50)
197+
dn := uint32(50)
198+
for {
199+
b := make([]uint16, n)
200+
db := make([]uint16, dn)
201+
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
202+
if e == nil {
203+
return UTF16ToString(b), UTF16ToString(db), accType, nil
204+
}
206205
if e != ERROR_INSUFFICIENT_BUFFER {
207206
return "", "", 0, e
208207
}
209-
// make receive buffers of requested size and try again
210-
b = make([]uint16, n)
211-
db = make([]uint16, dn)
212-
e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
213-
if e != nil {
208+
if n <= uint32(len(b)) {
214209
return "", "", 0, e
215210
}
216211
}
217-
return UTF16ToString(b), UTF16ToString(db), accType, nil
218212
}
219213

220214
const (
@@ -326,21 +320,20 @@ func (t Token) Close() error {
326320

327321
// getInfo retrieves a specified type of information about an access token.
328322
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
329-
b := make([]byte, initSize)
330-
var n uint32
331-
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
332-
if e != nil {
323+
n := uint32(initSize)
324+
for {
325+
b := make([]byte, n)
326+
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
327+
if e == nil {
328+
return unsafe.Pointer(&b[0]), nil
329+
}
333330
if e != ERROR_INSUFFICIENT_BUFFER {
334331
return nil, e
335332
}
336-
// make receive buffers of requested size and try again
337-
b = make([]byte, n)
338-
e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
339-
if e != nil {
333+
if n <= uint32(len(b)) {
340334
return nil, e
341335
}
342336
}
343-
return unsafe.Pointer(&b[0]), nil
344337
}
345338

346339
// GetTokenUser retrieves access token t user account information.
@@ -366,19 +359,18 @@ func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
366359
// GetUserProfileDirectory retrieves path to the
367360
// root directory of the access token t user's profile.
368361
func (t Token) GetUserProfileDirectory() (string, error) {
369-
b := make([]uint16, 100)
370-
n := uint32(len(b))
371-
e := GetUserProfileDirectory(t, &b[0], &n)
372-
if e != nil {
362+
n := uint32(100)
363+
for {
364+
b := make([]uint16, n)
365+
e := GetUserProfileDirectory(t, &b[0], &n)
366+
if e == nil {
367+
return UTF16ToString(b), nil
368+
}
373369
if e != ERROR_INSUFFICIENT_BUFFER {
374370
return "", e
375371
}
376-
// make receive buffers of requested size and try again
377-
b = make([]uint16, n)
378-
e = GetUserProfileDirectory(t, &b[0], &n)
379-
if e != nil {
372+
if n <= uint32(len(b)) {
380373
return "", e
381374
}
382375
}
383-
return UTF16ToString(b), nil
384376
}

0 commit comments

Comments
 (0)