Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions pkg/winacl/api/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package api

import (
"runtime"
"syscall"
"unsafe"

Expand Down Expand Up @@ -92,24 +91,6 @@ func SetEntriesInAcl(entries []ExplicitAccess, oldAcl windows.Handle, newAcl *wi
return nil
}

// Pin every pointer the kernel will dereference *transitively* through
// the entries slice. The unsafe.Pointer->uintptr pinning rule inside
// syscall.SyscallN only pins what is passed directly as a uintptr arg
// (here, &entries[0]). The kernel also reads through
// entries[i].Trustee.Name -- a *uint16 that, depending on TrusteeForm,
// is either a UTF-16 string or a SID pointer (cast via
// (*uint16)(unsafe.Pointer(sid))). Those targets are NOT covered by
// the inline pinning rule, and the typed-as-*uint16 cast obscures the
// true allocation from escape analysis, which has been the source of
// delayed memory-corruption crashes on long-running Windows scanners.
var pinner runtime.Pinner
defer pinner.Unpin()
for i := range entries {
if entries[i].Trustee.Name != nil {
pinner.Pin(entries[i].Trustee.Name)
}
}

ret, _, _ := syscall.SyscallN(
procSetEntriesInAclW.Addr(),
uintptr(len(entries)),
Expand Down
25 changes: 25 additions & 0 deletions pkg/winacl/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package winacl

import (
"runtime"

"github.com/runZeroInc/go-rod/pkg/winacl/api"
"golang.org/x/sys/windows"
)
Expand All @@ -26,6 +28,28 @@ func Apply(name string, replace, inherit bool, entries ...api.ExplicitAccess) er
)
defer windows.LocalFree(secDesc)
}

// Pin every pointer the kernel will dereference *transitively* through
// the entries slice. The unsafe.Pointer->uintptr pinning rule inside
// syscall.SyscallN only pins what is passed directly as a uintptr arg
// (here, &entries[0]). The kernel also reads through
// entries[i].Trustee.Name -- a *uint16 that, depending on TrusteeForm,
// is either a UTF-16 string or a SID pointer (cast via
// (*uint16)(unsafe.Pointer(sid))). Those targets are NOT covered by
// the inline pinning rule, and the typed-as-*uint16 cast obscures the
// true allocation from escape analysis, which has been the source of
// delayed memory-corruption crashes on long-running Windows scanners.
var pinner runtime.Pinner
defer pinner.Unpin()
if len(entries) > 0 {
pinner.Pin(&entries[0])
}
for i := range entries {
if entries[i].Trustee.Name != nil {
pinner.Pin(entries[i].Trustee.Name)
}
}

var acl windows.Handle
if err := api.SetEntriesInAcl(
entries,
Expand All @@ -35,6 +59,7 @@ func Apply(name string, replace, inherit bool, entries ...api.ExplicitAccess) er
return err
}
defer windows.LocalFree(acl)

var secInfo uint32
if !inherit {
secInfo = api.PROTECTED_DACL_SECURITY_INFORMATION
Expand Down
33 changes: 19 additions & 14 deletions pkg/winaclx/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,24 @@ func osWindowsApplyACL(name string, replace, inherit bool, entries ...ExplicitAc
)
defer windows.LocalFree(secDesc)
}

// Pin every pointer the kernel will dereference *transitively* through
// entries[i].Trustee.Name. The unsafe.Pointer->uintptr pinning rule in
// syscall.SyscallN only pins direct arguments (&entries[0]); pointers
// nested inside that struct -- here, the SID or UTF-16 buffer cast to
// *uint16 -- are NOT covered, and the cast through a smaller type
// obscures the true allocation from escape analysis.
var pinner runtime.Pinner
defer pinner.Unpin()
if len(entries) > 0 {
pinner.Pin(&entries[0])
}
for i := range entries {
if entries[i].Trustee.Name != nil {
pinner.Pin(entries[i].Trustee.Name)
}
}

var acl windows.Handle
if err := SetEntriesInAcl(
entries,
Expand All @@ -244,6 +262,7 @@ func osWindowsApplyACL(name string, replace, inherit bool, entries ...ExplicitAc
return err
}
defer windows.LocalFree(acl)

var secInfo uint32
if !inherit {
secInfo = PROTECTED_DACL_SECURITY_INFORMATION
Expand Down Expand Up @@ -299,20 +318,6 @@ func SetEntriesInAcl(entries []ExplicitAccess, oldAcl windows.Handle, newAcl *wi
return nil
}

// Pin every pointer the kernel will dereference *transitively* through
// entries[i].Trustee.Name. The unsafe.Pointer->uintptr pinning rule in
// syscall.SyscallN only pins direct arguments (&entries[0]); pointers
// nested inside that struct -- here, the SID or UTF-16 buffer cast to
// *uint16 -- are NOT covered, and the cast through a smaller type
// obscures the true allocation from escape analysis.
var pinner runtime.Pinner
defer pinner.Unpin()
for i := range entries {
if entries[i].Trustee.Name != nil {
pinner.Pin(entries[i].Trustee.Name)
}
}

ret, _, _ := syscall.SyscallN(
procSetEntriesInAclW.Addr(),
uintptr(len(entries)),
Expand Down
Loading