Skip to content

Commit fe76b77

Browse files
rikysyaalexbrainman
authored andcommitted
windows: fix -d=checkptr slice failures
This CL fixes unsafe casts to slices that are missing length or capacity. Running tests with -d=checkptr enabled may panic on casting unsafe.Pointer to a static array of large predefined length, that is most likely much bigger than the size of the actual array in memory. Checkptr check is not satisfied if slicing operator misses length and capacity arguments `(*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]`, or when there is no slicing at all `(*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))`. To find all potential cases I used `grep -nr ")(unsafe.Pointer(" ./windows`, then filtered out safe casts when object size is always static and known at compile time. To reproduce the issue run tests with checkptr enabled `go test -a -gcflags=all=-d=checkptr ./windows/...`. Updates golang/go#34972 Fixes golang/go#38355 Change-Id: I9dd2084b4f9fb7618cdb140fb2f38b56b6d6cc04 GitHub-Last-Rev: 73288ad GitHub-Pull-Request: #65 Reviewed-on: https://go-review.googlesource.com/c/sys/+/225418 Run-TryBot: Alex Brainman <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Alex Brainman <[email protected]>
1 parent 1151b9d commit fe76b77

File tree

8 files changed

+92
-52
lines changed

8 files changed

+92
-52
lines changed

windows/env_windows.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package windows
88

99
import (
1010
"syscall"
11-
"unicode/utf16"
1211
"unsafe"
1312
)
1413

@@ -40,17 +39,11 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
4039
defer DestroyEnvironmentBlock(block)
4140
blockp := uintptr(unsafe.Pointer(block))
4241
for {
43-
entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:]
44-
for i, v := range entry {
45-
if v == 0 {
46-
entry = entry[:i]
47-
break
48-
}
49-
}
42+
entry := UTF16PtrToString((*uint16)(unsafe.Pointer(blockp)))
5043
if len(entry) == 0 {
5144
break
5245
}
53-
env = append(env, string(utf16.Decode(entry)))
46+
env = append(env, entry)
5447
blockp += 2 * (uintptr(len(entry)) + 1)
5548
}
5649
return env, nil

windows/security_windows.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package windows
77
import (
88
"syscall"
99
"unsafe"
10+
11+
"golang.org/x/sys/internal/unsafeheader"
1012
)
1113

1214
const (
@@ -1229,7 +1231,7 @@ func (sd *SECURITY_DESCRIPTOR) String() string {
12291231
return ""
12301232
}
12311233
defer LocalFree(Handle(unsafe.Pointer(sddl)))
1232-
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(sddl))[:])
1234+
return UTF16PtrToString(sddl)
12331235
}
12341236

12351237
// ToAbsolute converts a self-relative security descriptor into an absolute one.
@@ -1307,9 +1309,17 @@ func (absoluteSD *SECURITY_DESCRIPTOR) ToSelfRelative() (selfRelativeSD *SECURIT
13071309
}
13081310

13091311
func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR {
1310-
sdBytes := make([]byte, selfRelativeSD.Length())
1311-
copy(sdBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(selfRelativeSD))[:len(sdBytes)])
1312-
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&sdBytes[0]))
1312+
sdLen := (int)(selfRelativeSD.Length())
1313+
1314+
var src []byte
1315+
h := (*unsafeheader.Slice)(unsafe.Pointer(&src))
1316+
h.Data = unsafe.Pointer(selfRelativeSD)
1317+
h.Len = sdLen
1318+
h.Cap = sdLen
1319+
1320+
dst := make([]byte, sdLen)
1321+
copy(dst, src)
1322+
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
13131323
}
13141324

13151325
// SecurityDescriptorFromString converts an SDDL string describing a security descriptor into a
@@ -1391,6 +1401,6 @@ func ACLFromEntries(explicitEntries []EXPLICIT_ACCESS, mergedACL *ACL) (acl *ACL
13911401
}
13921402
defer LocalFree(Handle(unsafe.Pointer(winHeapACL)))
13931403
aclBytes := make([]byte, winHeapACL.aclSize)
1394-
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes)])
1404+
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes):len(aclBytes)])
13951405
return (*ACL)(unsafe.Pointer(&aclBytes[0])), nil
13961406
}

windows/svc/mgr/config.go

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package mgr
88

99
import (
1010
"syscall"
11-
"unicode/utf16"
1211
"unsafe"
1312

1413
"golang.org/x/sys/windows"
@@ -46,28 +45,21 @@ type Config struct {
4645
DelayedAutoStart bool // the service is started after other auto-start services are started plus a short delay
4746
}
4847

49-
func toString(p *uint16) string {
50-
if p == nil {
51-
return ""
52-
}
53-
return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
54-
}
55-
5648
func toStringSlice(ps *uint16) []string {
57-
if ps == nil {
58-
return nil
59-
}
6049
r := make([]string, 0)
61-
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
62-
if p[i] == 0 {
63-
// empty string marks the end
64-
if i <= from {
65-
break
66-
}
67-
r = append(r, string(utf16.Decode(p[from:i])))
68-
from = i + 1
50+
p := unsafe.Pointer(ps)
51+
52+
for {
53+
s := windows.UTF16PtrToString((*uint16)(p))
54+
if len(s) == 0 {
55+
break
6956
}
57+
58+
r = append(r, s)
59+
offset := unsafe.Sizeof(uint16(0)) * (uintptr)(len(s)+1)
60+
p = unsafe.Pointer(uintptr(p) + offset)
7061
}
62+
7163
return r
7264
}
7365

@@ -110,13 +102,13 @@ func (s *Service) Config() (Config, error) {
110102
ServiceType: p.ServiceType,
111103
StartType: p.StartType,
112104
ErrorControl: p.ErrorControl,
113-
BinaryPathName: toString(p.BinaryPathName),
114-
LoadOrderGroup: toString(p.LoadOrderGroup),
105+
BinaryPathName: windows.UTF16PtrToString(p.BinaryPathName),
106+
LoadOrderGroup: windows.UTF16PtrToString(p.LoadOrderGroup),
115107
TagId: p.TagId,
116108
Dependencies: toStringSlice(p.Dependencies),
117-
ServiceStartName: toString(p.ServiceStartName),
118-
DisplayName: toString(p.DisplayName),
119-
Description: toString(p2.Description),
109+
ServiceStartName: windows.UTF16PtrToString(p.ServiceStartName),
110+
DisplayName: windows.UTF16PtrToString(p.DisplayName),
111+
Description: windows.UTF16PtrToString(p2.Description),
120112
DelayedAutoStart: delayedStart,
121113
}, nil
122114
}

windows/svc/mgr/mgr.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"unicode/utf16"
1818
"unsafe"
1919

20+
"golang.org/x/sys/internal/unsafeheader"
2021
"golang.org/x/sys/windows"
2122
)
2223

@@ -73,7 +74,7 @@ func (m *Mgr) LockStatus() (*LockStatus, error) {
7374
status := &LockStatus{
7475
IsLocked: lockStatus.IsLocked != 0,
7576
Age: time.Duration(lockStatus.LockDuration) * time.Second,
76-
Owner: windows.UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(lockStatus.LockOwner))[:]),
77+
Owner: windows.UTF16PtrToString(lockStatus.LockOwner),
7778
}
7879
return status, nil
7980
}
@@ -201,10 +202,16 @@ func (m *Mgr) ListServices() ([]string, error) {
201202
if servicesReturned == 0 {
202203
return nil, nil
203204
}
204-
services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned]
205+
206+
var services []windows.ENUM_SERVICE_STATUS_PROCESS
207+
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&services))
208+
hdr.Data = unsafe.Pointer(&buf[0])
209+
hdr.Len = int(servicesReturned)
210+
hdr.Cap = int(servicesReturned)
211+
205212
var names []string
206213
for _, s := range services {
207-
name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:])
214+
name := windows.UTF16PtrToString(s.ServiceName)
208215
names = append(names, name)
209216
}
210217
return names, nil

windows/svc/mgr/recovery.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313
"unsafe"
1414

15+
"golang.org/x/sys/internal/unsafeheader"
1516
"golang.org/x/sys/windows"
1617
)
1718

@@ -68,8 +69,13 @@ func (s *Service) RecoveryActions() ([]RecoveryAction, error) {
6869
return nil, err
6970
}
7071

72+
var actions []windows.SC_ACTION
73+
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&actions))
74+
hdr.Data = unsafe.Pointer(p.Actions)
75+
hdr.Len = int(p.ActionsCount)
76+
hdr.Cap = int(p.ActionsCount)
77+
7178
var recoveryActions []RecoveryAction
72-
actions := (*[1024]windows.SC_ACTION)(unsafe.Pointer(p.Actions))[:p.ActionsCount]
7379
for _, action := range actions {
7480
recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond})
7581
}
@@ -112,7 +118,7 @@ func (s *Service) RebootMessage() (string, error) {
112118
return "", err
113119
}
114120
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
115-
return toString(p.RebootMsg), nil
121+
return windows.UTF16PtrToString(p.RebootMsg), nil
116122
}
117123

118124
// SetRecoveryCommand sets the command line of the process to execute in response to the RunCommand service controller action.
@@ -131,5 +137,5 @@ func (s *Service) RecoveryCommand() (string, error) {
131137
return "", err
132138
}
133139
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
134-
return toString(p.Command), nil
140+
return windows.UTF16PtrToString(p.Command), nil
135141
}

windows/svc/security.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
package svc
88

99
import (
10-
"unsafe"
11-
1210
"golang.org/x/sys/windows"
1311
)
1412

@@ -48,9 +46,8 @@ func IsAnInteractiveSession() (bool, error) {
4846
if err != nil {
4947
return false, err
5048
}
51-
p := unsafe.Pointer(&gs.Groups[0])
52-
groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
53-
for _, g := range groups {
49+
50+
for _, g := range gs.AllGroups() {
5451
if windows.EqualSid(g.Sid, interSid) {
5552
return true, nil
5653
}

windows/svc/service.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"syscall"
1515
"unsafe"
1616

17+
"golang.org/x/sys/internal/unsafeheader"
1718
"golang.org/x/sys/windows"
1819
)
1920

@@ -224,10 +225,16 @@ const (
224225
func (s *service) run() {
225226
s.goWaits.Wait()
226227
s.h = windows.Handle(ssHandle)
227-
argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
228+
229+
var argv []*uint16
230+
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&argv))
231+
hdr.Data = unsafe.Pointer(sArgv)
232+
hdr.Len = int(sArgc)
233+
hdr.Cap = int(sArgc)
234+
228235
args := make([]string, len(argv))
229236
for i, a := range argv {
230-
args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
237+
args[i] = windows.UTF16PtrToString(a)
231238
}
232239

233240
cmdsToHandler := make(chan ChangeRequest)

windows/syscall_windows.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"time"
1414
"unicode/utf16"
1515
"unsafe"
16+
17+
"golang.org/x/sys/internal/unsafeheader"
1618
)
1719

1820
type Handle uintptr
@@ -117,6 +119,32 @@ func UTF16PtrFromString(s string) (*uint16, error) {
117119
return &a[0], nil
118120
}
119121

122+
// UTF16PtrToString takes a pointer to a UTF-16 sequence and returns the corresponding UTF-8 encoded string.
123+
// If the pointer is nil, this returns the empty string. This assumes that the UTF-16 sequence is terminated
124+
// at a zero word; if the zero word is not present, the program may crash.
125+
func UTF16PtrToString(p *uint16) string {
126+
if p == nil {
127+
return ""
128+
}
129+
if *p == 0 {
130+
return ""
131+
}
132+
133+
// Find NUL terminator.
134+
n := 0
135+
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
136+
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
137+
}
138+
139+
var s []uint16
140+
h := (*unsafeheader.Slice)(unsafe.Pointer(&s))
141+
h.Data = unsafe.Pointer(p)
142+
h.Len = n
143+
h.Cap = n
144+
145+
return string(utf16.Decode(s))
146+
}
147+
120148
func Getpagesize() int { return 4096 }
121149

122150
// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention.
@@ -1383,7 +1411,7 @@ func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, e
13831411
return "", err
13841412
}
13851413
defer CoTaskMemFree(unsafe.Pointer(p))
1386-
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil
1414+
return UTF16PtrToString(p), nil
13871415
}
13881416

13891417
// RtlGetVersion returns the version of the underlying operating system, ignoring

0 commit comments

Comments
 (0)