wincred icon indicating copy to clipboard operation
wincred copied to clipboard

Unsafe syscall usage, may cause random panic (very rarely)

Open dangodangodango opened this issue 1 month ago • 0 comments

	procCredWrite     proc = modadvapi32.NewProc("CredWriteW")
	procCredDelete    proc = modadvapi32.NewProc("CredDeleteW")
	procCredFree      proc = modadvapi32.NewProc("CredFree")

Go use //go:uintptrescapes to make uintptr(unsafe.Pointer(pcred)) in procCredDelete.Call(...)(Proc.Call) argument list safe by:

  1. Enforce pcred escape to heap;
  2. Keep pcred alive during the call.

src\syscall\dll_windows.go:

// Call executes procedure p with arguments a.
//
// The returned error is always non-nil, constructed from the result of GetLastError.
// Callers must inspect the primary return value to decide whether an error occurred
// (according to the semantics of the specific function being called) before consulting
// the error. The error always has type [Errno].
//
// On amd64, Call can pass and return floating-point values. To pass
// an argument x with C type "float", use
// uintptr(math.Float32bits(x)). To pass an argument with C type
// "double", use uintptr(math.Float64bits(x)). Floating-point return
// values are returned in r2. The return value for C type "float" is
// [math.Float32frombits](uint32(r2)). For C type "double", it is
// [math.Float64frombits](uint64(r2)).
//
//go:uintptrescapes
func (p *Proc) Call(a ...uintptr) (uintptr, uintptr, error) {
	return SyscallN(p.Addr(), a...)
}

But the proc interface indirection break this safety guarantee, compiler can't see the //go:uintptrescapes at procCredDelete.Call.

runtime.KeepAlive wont work if the pcred is alloc in the stack, stack grow will change its address, the C api gonna receive a wrong address.

dangodangodango avatar Nov 05 '25 08:11 dangodangodango