From 96105dd4ea2d76a1dcd12dc579c2f5fd0fc92aea Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 7 Mar 2021 00:59:36 -0800 Subject: [PATCH] Add go:notinheap annotations to all the WFP API types. This should prevent us from accidentally passing Go memory to Windows. Also fix up a couple cases where we were, in fact, passing Go memory to Windows. Signed-off-by: David Anderson --- compose.go | 21 +++++++++++++++++++++ firewall.go | 26 ++++++++++---------------- parse.go | 30 ++++++++++++++++-------------- syscall.go | 2 +- types.go | 23 +++++++++++++++++++---- zsyscall_windows.go | 2 +- 6 files changed, 68 insertions(+), 36 deletions(-) diff --git a/compose.go b/compose.go index b36b5ce..d9ffb0f 100644 --- a/compose.go +++ b/compose.go @@ -8,6 +8,27 @@ import ( "golang.org/x/sys/windows" ) +func toSession0(a *arena, opts *SessionOptions) *fwpmSession0 { + ret := (*fwpmSession0)(a.alloc(unsafe.Sizeof(fwpmSession0{}))) + *ret = fwpmSession0{ + DisplayData: fwpmDisplayData0{ + Name: toUint16(a, opts.Name), + Description: toUint16(a, opts.Description), + }, + TxnWaitTimeoutMillis: uint32(opts.TransactionStartTimeout.Milliseconds()), + } + if opts.Dynamic { + ret.Flags = fwpmSession0FlagDynamic + } + return ret +} + +func toSublayerEnumTemplate0(a *arena, provider *windows.GUID) *fwpmSublayerEnumTemplate0 { + ret := (*fwpmSublayerEnumTemplate0)(a.alloc(unsafe.Sizeof(fwpmSublayerEnumTemplate0{}))) + ret.ProviderKey = toGUID(a, provider) + return ret +} + func toSublayer0(a *arena, sl *Sublayer) *fwpmSublayer0 { ret := (*fwpmSublayer0)(a.alloc(unsafe.Sizeof(fwpmSublayer0{}))) *ret = fwpmSublayer0{ diff --git a/firewall.go b/firewall.go index 72c24cc..8d63e17 100644 --- a/firewall.go +++ b/firewall.go @@ -56,20 +56,13 @@ func New(opts *SessionOptions) (*Session, error) { opts = &SessionOptions{} } - session := fwpmSession0{ - DisplayData: fwpmDisplayData0{ - Name: windows.StringToUTF16Ptr(opts.Name), - Description: windows.StringToUTF16Ptr(opts.Description), - }, - TxnWaitTimeoutMillis: uint32(opts.TransactionStartTimeout.Milliseconds()), - } - if opts.Dynamic { - session.Flags = fwpmSession0FlagDynamic - } + var a arena + defer a.dispose() - var handle windows.Handle + s0 := toSession0(&a, opts) - err := fwpmEngineOpen0(nil, authnServiceWinNT, nil, &session, &handle) + var handle windows.Handle + err := fwpmEngineOpen0(nil, authnServiceWinNT, nil, s0, &handle) if err != nil { return nil, err } @@ -232,12 +225,13 @@ type Sublayer struct { // Sublayers returns available Sublayers. If provider is non-nil, only // Sublayers registered to that Provider are returned. func (s *Session) Sublayers(provider *windows.GUID) ([]*Sublayer, error) { - tpl := fwpmSublayerEnumTemplate0{ - ProviderKey: provider, - } + var a arena + defer a.dispose() + + tpl := toSublayerEnumTemplate0(&a, provider) var enum windows.Handle - if err := fwpmSubLayerCreateEnumHandle0(s.handle, &tpl, &enum); err != nil { + if err := fwpmSubLayerCreateEnumHandle0(s.handle, tpl, &enum); err != nil { return nil, err } defer fwpmSubLayerDestroyEnumHandle0(s.handle, enum) diff --git a/parse.go b/parse.go index 089737f..5fcc0e6 100644 --- a/parse.go +++ b/parse.go @@ -91,8 +91,9 @@ func fromLayer0(array **fwpmLayer0, num uint32) ([]*Layer, error) { sh.Len = int(layer.NumFields) sh.Data = uintptr(unsafe.Pointer(layer.Fields)) - for _, field := range fields { - typ, err := fieldType(&field) + for i := range fields { + field := &fields[i] + typ, err := fieldType(field) if err != nil { return nil, fmt.Errorf("finding type of field %s: %w", GUIDName(*field.FieldKey), err) } @@ -124,7 +125,7 @@ func fromSublayer0(array **fwpmSublayer0, num uint32) []*Sublayer { Name: windows.UTF16PtrToString(sublayer.DisplayData.Name), Description: windows.UTF16PtrToString(sublayer.DisplayData.Description), Persistent: (sublayer.Flags & fwpmSublayerFlagsPersistent) != 0, - ProviderData: fromByteBlob(sublayer.ProviderData), + ProviderData: fromByteBlob(&sublayer.ProviderData), Weight: sublayer.Weight, } if sublayer.ProviderKey != nil { @@ -157,7 +158,7 @@ func fromProvider0(array **fwpmProvider0, num uint32) []*Provider { Description: windows.UTF16PtrToString(provider.DisplayData.Description), Persistent: (provider.Flags & fwpmProviderFlagsPersistent) != 0, Disabled: (provider.Flags & fwpmProviderFlagsDisabled) != 0, - Data: fromByteBlob(provider.ProviderData), + Data: fromByteBlob(&provider.ProviderData), ServiceName: windows.UTF16PtrToString(provider.ServiceName), } ret = append(ret, p) @@ -186,7 +187,7 @@ func fromFilter0(array **fwpmFilter0, num uint32, layerTypes layerTypes) ([]*Rul Persistent: (rule.Flags & fwpmFilterFlagsPersistent) != 0, BootTime: (rule.Flags & fwpmFilterFlagsBootTime) != 0, Provider: rule.ProviderKey, - ProviderData: fromByteBlob(rule.ProviderData), + ProviderData: fromByteBlob(&rule.ProviderData), Disabled: (rule.Flags & fwpmFilterFlagsDisabled) != 0, } if rule.EffectiveWeight.Type == dataTypeUint64 { @@ -226,13 +227,14 @@ func fromCondition0(condArray *fwpmFilterCondition0, num uint32, fieldTypes fiel var ret []*Match - for _, cond := range conditions { + for i := range conditions { + cond := &conditions[i] fieldType, ok := fieldTypes[cond.FieldKey] if !ok { return nil, fmt.Errorf("unknown field %s", cond.FieldKey) } - v, err := fromValue0(fwpValue0(cond.Value), fieldType) + v, err := fromValue0((*fwpValue0)(unsafe.Pointer(&cond.Value)), fieldType) if err != nil { return nil, fmt.Errorf("getting value for match [%s %s]: %w", GUIDName(cond.FieldKey), cond.MatchType, err) } @@ -249,7 +251,7 @@ func fromCondition0(condArray *fwpmFilterCondition0, num uint32, fieldTypes fiel } // fromValue converts a fwpValue0 to the corresponding Go value. -func fromValue0(v fwpValue0, ftype reflect.Type) (interface{}, error) { +func fromValue0(v *fwpValue0, ftype reflect.Type) (interface{}, error) { // For most types, the field type and raw data type match up. But // for some, the raw type can vary from the field type // (e.g. comparing an IP to a prefix). Get the complex matchups @@ -316,7 +318,7 @@ func fromValue0(v fwpValue0, ftype reflect.Type) (interface{}, error) { copy(ret[:], fromBytes(v.Value, 16)) return ret, nil case dataTypeByteBlob: - return fromByteBlob(**(**fwpByteBlob)(unsafe.Pointer(&v.Value))), nil + return fromByteBlob(*(**fwpByteBlob)(unsafe.Pointer(&v.Value))), nil case dataTypeSID: return parseSID(&v.Value) // case dataTypeSecurityDescriptor: @@ -373,18 +375,18 @@ func parseSID(v *uintptr) (*windows.SID, error) { func parseSecurityDescriptor(v *uintptr) (*windows.SECURITY_DESCRIPTOR, error) { // The security descriptor is embedded in the API response as // a byte slice. - bb := fromByteBlob(**(**fwpByteBlob)(unsafe.Pointer(v))) + bb := fromByteBlob(*(**fwpByteBlob)(unsafe.Pointer(v))) relSD := (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&bb[0])) return relSD, nil } func parseRange0(v *uintptr, ftype reflect.Type) (interface{}, error) { r := *(**fwpRange0)(unsafe.Pointer(v)) - from, err := fromValue0(r.From, ftype) + from, err := fromValue0(&r.From, ftype) if err != nil { return nil, err } - to, err := fromValue0(r.To, ftype) + to, err := fromValue0(&r.To, ftype) if err != nil { return nil, err } @@ -421,8 +423,8 @@ func fromBytes(bb uintptr, length int) []byte { // fromByteBlob extracts the bytes from bb and returns them as a // []byte that doesn't alias C memory. -func fromByteBlob(bb fwpByteBlob) []byte { - if bb.Size == 0 { +func fromByteBlob(bb *fwpByteBlob) []byte { + if bb == nil || bb.Size == 0 { return nil } diff --git a/syscall.go b/syscall.go index efd5bf7..e0bf768 100644 --- a/syscall.go +++ b/syscall.go @@ -22,7 +22,7 @@ package wf //sys fwpmSubLayerDeleteByKey0(engineHandle windows.Handle, guid *windows.GUID) (err error) [failretval!=0] = fwpuclnt.FwpmSubLayerDeleteByKey0 -//sys fwpmProviderCreateEnumHandle0(engineHandle windows.Handle, enumTemplate *fwpmProviderEnumTemplate0, handle *windows.Handle) (err error) [failretval!=0] = fwpuclnt.FwpmProviderCreateEnumHandle0 +//sys fwpmProviderCreateEnumHandle0(engineHandle windows.Handle, enumTemplate *struct{}, handle *windows.Handle) (err error) [failretval!=0] = fwpuclnt.FwpmProviderCreateEnumHandle0 //sys fwpmProviderDestroyEnumHandle0(engineHandle windows.Handle, enumHandle windows.Handle) (err error) [failretval!=0] = fwpuclnt.FwpmProviderDestroyEnumHandle0 diff --git a/types.go b/types.go index 85865ba..72de2e9 100644 --- a/types.go +++ b/types.go @@ -4,6 +4,7 @@ import ( "golang.org/x/sys/windows" ) +//go:notinheap type fwpmDisplayData0 struct { Name *uint16 Description *uint16 @@ -13,6 +14,7 @@ type fwpmSession0Flags uint32 const fwpmSession0FlagDynamic = 1 +//go:notinheap type fwpmSession0 struct { SessionKey windows.GUID DisplayData fwpmDisplayData0 @@ -31,6 +33,7 @@ const ( authnServiceDefault authnService = 0xffffffff ) +//go:notinheap type fwpmLayerEnumTemplate0 struct { reserved uint64 } @@ -44,6 +47,7 @@ const ( fwpmLayerFlagsBuffered ) +//go:notinheap type fwpmLayer0 struct { LayerKey windows.GUID DisplayData fwpmDisplayData0 @@ -93,16 +97,19 @@ const ( // dataTypeUnicodeString dataType = 17 // dataTypeBitmapArray64 dataType = 20 +//go:notinheap type fwpmField0 struct { FieldKey *windows.GUID Type fwpmFieldType DataType dataType } +//go:notinheap type fwpmSublayerEnumTemplate0 struct { ProviderKey *windows.GUID } +//go:notinheap type fwpByteBlob struct { Size uint32 Data *uint8 @@ -112,6 +119,7 @@ type fwpmSublayerFlags uint32 const fwpmSublayerFlagsPersistent fwpmSublayerFlags = 1 +//go:notinheap type fwpmSublayer0 struct { SublayerKey windows.GUID DisplayData fwpmDisplayData0 @@ -121,10 +129,6 @@ type fwpmSublayer0 struct { Weight uint16 } -type fwpmProviderEnumTemplate0 struct { - Reserved uint64 -} - type fwpmProviderFlags uint32 const ( @@ -132,6 +136,7 @@ const ( fwpmProviderFlagsDisabled fwpmProviderFlags = 0x10 ) +//go:notinheap type fwpmProvider0 struct { ProviderKey windows.GUID DisplayData fwpmDisplayData0 @@ -140,6 +145,7 @@ type fwpmProvider0 struct { ServiceName *uint16 } +//go:notinheap type fwpValue0 struct { Type dataType Value uintptr // unioned value @@ -157,11 +163,13 @@ const ( fwpmFilterFlagsIndexed ) +//go:notinheap type fwpmAction0 struct { Type Action GUID windows.GUID } +//go:notinheap type fwpmFilter0 struct { FilterKey windows.GUID DisplayData fwpmDisplayData0 @@ -180,31 +188,37 @@ type fwpmFilter0 struct { EffectiveWeight fwpValue0 } +//go:notinheap type fwpConditionValue0 struct { Type dataType Value uintptr } +//go:notinheap type fwpmFilterCondition0 struct { FieldKey windows.GUID MatchType MatchType Value fwpConditionValue0 } +//go:notinheap type fwpV4AddrAndMask struct { Addr, Mask uint32 } +//go:notinheap type fwpV6AddrAndMask struct { Addr [16]byte PrefixLength uint8 } +//go:notinheap type fwpmProviderContextEnumTemplate0 struct { ProviderKey *windows.GUID ProviderContextType uint32 } +//go:notinheap type fwpmFilterEnumTemplate0 struct { ProviderKey *windows.GUID LayerKey windows.GUID @@ -217,6 +231,7 @@ type fwpmFilterEnumTemplate0 struct { CalloutKey *windows.GUID } +//go:notinheap type fwpRange0 struct { From, To fwpValue0 } diff --git a/zsyscall_windows.go b/zsyscall_windows.go index 7958ae4..55b57a8 100644 --- a/zsyscall_windows.go +++ b/zsyscall_windows.go @@ -150,7 +150,7 @@ func fwpmProviderAdd0(engineHandle windows.Handle, provider *fwpmProvider0, nilF return } -func fwpmProviderCreateEnumHandle0(engineHandle windows.Handle, enumTemplate *fwpmProviderEnumTemplate0, handle *windows.Handle) (err error) { +func fwpmProviderCreateEnumHandle0(engineHandle windows.Handle, enumTemplate *struct{}, handle *windows.Handle) (err error) { r1, _, e1 := syscall.Syscall(procFwpmProviderCreateEnumHandle0.Addr(), 3, uintptr(engineHandle), uintptr(unsafe.Pointer(enumTemplate)), uintptr(unsafe.Pointer(handle))) if r1 != 0 { err = errnoErr(e1)