Skip to content

Commit

Permalink
Add go:notinheap annotations to all the WFP API types.
Browse files Browse the repository at this point in the history
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 <danderson@tailscale.com>
  • Loading branch information
danderson committed Mar 14, 2021
1 parent 3c2c0fd commit 96105dd
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 36 deletions.
21 changes: 21 additions & 0 deletions compose.go
Expand Up @@ -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{
Expand Down
26 changes: 10 additions & 16 deletions firewall.go
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down
30 changes: 16 additions & 14 deletions parse.go
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion syscall.go
Expand Up @@ -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

Expand Down
23 changes: 19 additions & 4 deletions types.go
Expand Up @@ -4,6 +4,7 @@ import (
"golang.org/x/sys/windows"
)

//go:notinheap
type fwpmDisplayData0 struct {
Name *uint16
Description *uint16
Expand All @@ -13,6 +14,7 @@ type fwpmSession0Flags uint32

const fwpmSession0FlagDynamic = 1

//go:notinheap
type fwpmSession0 struct {
SessionKey windows.GUID
DisplayData fwpmDisplayData0
Expand All @@ -31,6 +33,7 @@ const (
authnServiceDefault authnService = 0xffffffff
)

//go:notinheap
type fwpmLayerEnumTemplate0 struct {
reserved uint64
}
Expand All @@ -44,6 +47,7 @@ const (
fwpmLayerFlagsBuffered
)

//go:notinheap
type fwpmLayer0 struct {
LayerKey windows.GUID
DisplayData fwpmDisplayData0
Expand Down Expand Up @@ -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
Expand All @@ -112,6 +119,7 @@ type fwpmSublayerFlags uint32

const fwpmSublayerFlagsPersistent fwpmSublayerFlags = 1

//go:notinheap
type fwpmSublayer0 struct {
SublayerKey windows.GUID
DisplayData fwpmDisplayData0
Expand All @@ -121,17 +129,14 @@ type fwpmSublayer0 struct {
Weight uint16
}

type fwpmProviderEnumTemplate0 struct {
Reserved uint64
}

type fwpmProviderFlags uint32

const (
fwpmProviderFlagsPersistent fwpmProviderFlags = 0x01
fwpmProviderFlagsDisabled fwpmProviderFlags = 0x10
)

//go:notinheap
type fwpmProvider0 struct {
ProviderKey windows.GUID
DisplayData fwpmDisplayData0
Expand All @@ -140,6 +145,7 @@ type fwpmProvider0 struct {
ServiceName *uint16
}

//go:notinheap
type fwpValue0 struct {
Type dataType
Value uintptr // unioned value
Expand All @@ -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
Expand All @@ -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
Expand All @@ -217,6 +231,7 @@ type fwpmFilterEnumTemplate0 struct {
CalloutKey *windows.GUID
}

//go:notinheap
type fwpRange0 struct {
From, To fwpValue0
}
Expand Down
2 changes: 1 addition & 1 deletion zsyscall_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 96105dd

Please sign in to comment.