Skip to content

Commit c507910

Browse files
neildgopherbot
authored andcommitted
windows: document safe usage of TrusteeValue
Failure to pin the memory pointed to by a TrusteeValue (a uintptr) can lead to the GC collecting the memory while it is still being referenced. Fixes #79923 Change-Id: Ie28884856298cd60693c903843be6aa06a6a6964 Reviewed-on: https://go-review.googlesource.com/c/sys/+/789000 Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
1 parent d58dcfa commit c507910

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

windows/security_windows.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,17 +1109,53 @@ const (
11091109
)
11101110

11111111
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
1112+
//
1113+
// Go pointers stored in a TrusteeValue must be pinned using [runtime.Pinner]
1114+
// for the lifetime of the TrusteeValue.
11121115
type TrusteeValue uintptr
11131116

1117+
// TrusteeValueFromString is unsafe and should not be used.
1118+
//
1119+
// It returns a uintptr containing a reference to newly-allocated memory
1120+
// which will be freed by the garbage collector.
1121+
// There is no way for the caller to safely reference this memory.
1122+
//
1123+
// To create a [TrusteeValue] from a string, use:
1124+
//
1125+
// p, err := windows.UTF16PtrFromString(s)
1126+
// if err != nil {
1127+
// // handle error
1128+
// }
1129+
//
1130+
// // Pin the string for as long as it is used.
1131+
// var pinner runtime.Pinner
1132+
// pinner.Pin(p)
1133+
// defer pinner.Unpin()
1134+
//
1135+
// tv := TrusteeValue(unsafe.Pointer(p))
1136+
//
1137+
// Deprecated: TrusteeValueFromString is unsafe and should not be used.
11141138
func TrusteeValueFromString(str string) TrusteeValue {
11151139
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
11161140
}
1141+
1142+
// TrusteeValueFromSID returns a [TrusteeValue] referencing sid.
1143+
//
1144+
// The caller must pin sid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
11171145
func TrusteeValueFromSID(sid *SID) TrusteeValue {
11181146
return TrusteeValue(unsafe.Pointer(sid))
11191147
}
1148+
1149+
// TrusteeValueFromObjectsAndSid returns a [TrusteeValue] referencing objectsAndSid.
1150+
//
1151+
// The caller must pin objectsAndSid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
11201152
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
11211153
return TrusteeValue(unsafe.Pointer(objectsAndSid))
11221154
}
1155+
1156+
// TrusteeValueFromObjectsAndName returns a [TrusteeValue] referencing objectsAndName.
1157+
//
1158+
// The caller must pin objectsAndName using a [runtime.Pinner] for the lifetime of the TrusteeValue.
11231159
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
11241160
return TrusteeValue(unsafe.Pointer(objectsAndName))
11251161
}

windows/syscall_windows_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ func TestBuildSecurityDescriptor(t *testing.T) {
294294
t.Fatal(err)
295295
}
296296

297+
var pinner runtime.Pinner
298+
defer pinner.Unpin()
299+
pinner.Pin(adminSid)
300+
pinner.Pin(systemSid)
301+
297302
access := []windows.EXPLICIT_ACCESS{{
298303
AccessPermissions: windows.GENERIC_ALL,
299304
AccessMode: windows.GRANT_ACCESS,

0 commit comments

Comments
 (0)