aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-21 13:13:32 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-22 15:26:54 +0200
commitd41f190c7f164d2141d1c26eff3ffb8feda04618 (patch)
tree25fa246ec63edfc6380239aae3a925905e984982
parentREADME: avoid confusion about downloads (diff)
downloadwireguard-windows-d41f190c7f164d2141d1c26eff3ffb8feda04618.tar.xz
wireguard-windows-d41f190c7f164d2141d1c26eff3ffb8feda04618.zip
firewall: use service-specific SID
-rw-r--r--manager/install.go9
-rw-r--r--tunnel/firewall/blocker.go10
-rw-r--r--tunnel/firewall/helpers.go50
-rw-r--r--tunnel/firewall/rules.go2
-rw-r--r--tunnel/firewall/syscall_windows.go16
-rw-r--r--tunnel/firewall/types_windows.go56
-rw-r--r--tunnel/firewall/zsyscall_windows.go58
7 files changed, 155 insertions, 46 deletions
diff --git a/manager/install.go b/manager/install.go
index 4a570297..2eddbbbe 100644
--- a/manager/install.go
+++ b/manager/install.go
@@ -9,6 +9,7 @@ import (
"errors"
"os"
"time"
+ "unsafe"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
@@ -165,6 +166,14 @@ func InstallTunnel(configPath string) error {
if err != nil {
return err
}
+ sidType := uint32(windows.SERVICE_SID_TYPE_UNRESTRICTED)
+ err = windows.ChangeServiceConfig2(service.Handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType)))
+ if err != nil {
+ service.Delete()
+ service.Close()
+ return err
+ }
+
err = service.Start()
go trackTunnelService(name, service) // Pass off reference to handle.
return err
diff --git a/tunnel/firewall/blocker.go b/tunnel/firewall/blocker.go
index 8034935d..cdb656b0 100644
--- a/tunnel/firewall/blocker.go
+++ b/tunnel/firewall/blocker.go
@@ -124,6 +124,11 @@ func EnableFirewall(luid uint64, restrictToDNSServers []net.IP, restrictAll bool
return wrapErr(err)
}
+ err = permitWireGuardService(session, baseObjects, 15)
+ if err != nil {
+ return wrapErr(err)
+ }
+
if len(restrictToDNSServers) > 0 {
err = blockDNS(restrictToDNSServers, session, baseObjects, 15, 14)
if err != nil {
@@ -143,11 +148,6 @@ func EnableFirewall(luid uint64, restrictToDNSServers []net.IP, restrictAll bool
return wrapErr(err)
}
- err = permitWireGuardService(session, baseObjects, 12)
- if err != nil {
- return wrapErr(err)
- }
-
if restrictAll {
err = permitDHCPIPv4(session, baseObjects, 12)
if err != nil {
diff --git a/tunnel/firewall/helpers.go b/tunnel/firewall/helpers.go
index e340b802..6bc71806 100644
--- a/tunnel/firewall/helpers.go
+++ b/tunnel/firewall/helpers.go
@@ -72,16 +72,58 @@ func wrapErr(err error) error {
}
func getCurrentProcessSecurityDescriptor() (*wtFwpByteBlob, error) {
- procHandle, err := windows.GetCurrentProcess()
+ processToken, err := windows.OpenCurrentProcessToken()
if err != nil {
- panic(err)
+ return nil, wrapErr(err)
+ }
+ defer processToken.Close()
+ gs, err := processToken.GetTokenGroups()
+ if err != nil {
+ return nil, wrapErr(err)
+ }
+ var sid *windows.SID
+ groups := (*[(1 << 28) - 1]windows.SIDAndAttributes)(unsafe.Pointer(&gs.Groups[0]))[:gs.GroupCount]
+ for _, g := range groups {
+ if g.Attributes != windows.SE_GROUP_ENABLED|windows.SE_GROUP_ENABLED_BY_DEFAULT|windows.SE_GROUP_OWNER {
+ continue
+ }
+ if *(*byte)(unsafe.Pointer(g.Sid)) != 1 { // The revision.
+ continue
+ }
+ if *getSidIdentifierAuthority(g.Sid) != windows.SECURITY_NT_AUTHORITY {
+ continue
+ }
+ // We could be checking != 6, but hopefully Microsoft will update
+ // RtlCreateServiceSid to use SHA2, which will then likely bump
+ // this up. So instead just roll with a minimum.
+ if *getSidSubAuthorityCount(g.Sid) < 6 {
+ continue
+ }
+ if *getSidSubAuthority(g.Sid, 0) != 80 {
+ continue
+ }
+
+ sid = g.Sid
+ break
+ }
+ if sid == nil {
+ return nil, wrapErr(windows.ERROR_NO_SUCH_GROUP)
+ }
+
+ access := &wtExplicitAccess{
+ accessPermissions: cFWP_ACTRL_MATCH_FILTER,
+ accessMode: cGRANT_ACCESS,
+ trustee: wtTrustee{
+ trusteeForm: cTRUSTEE_IS_SID,
+ trusteeType: cTRUSTEE_IS_GROUP,
+ sid: sid,
+ },
}
blob := &wtFwpByteBlob{}
- err = getSecurityInfo(procHandle, cSE_KERNEL_OBJECT, cDACL_SECURITY_INFORMATION, nil, nil, nil, nil, (*uintptr)(unsafe.Pointer(&blob.data)))
+ err = buildSecurityDescriptor(nil, nil, 1, access, 0, nil, nil, &blob.size, &blob.data)
if err != nil {
return nil, wrapErr(err)
}
- blob.size = getSecurityDescriptorLength(uintptr(unsafe.Pointer(blob.data)))
return blob, nil
}
diff --git a/tunnel/firewall/rules.go b/tunnel/firewall/rules.go
index 76e2a85b..1f28d3ab 100644
--- a/tunnel/firewall/rules.go
+++ b/tunnel/firewall/rules.go
@@ -149,7 +149,7 @@ func permitWireGuardService(session uintptr, baseObjects *baseObjects, weight ui
//
// Second condition is the SECURITY_DESCRIPTOR of the current process.
- // This prevents low privileged applications hosted in the same exe from matching this filter.
+ // This prevents other processes hosted in the same exe from matching this filter.
//
sd, err := getCurrentProcessSecurityDescriptor()
if err != nil {
diff --git a/tunnel/firewall/syscall_windows.go b/tunnel/firewall/syscall_windows.go
index 5ec41b0b..0f247d85 100644
--- a/tunnel/firewall/syscall_windows.go
+++ b/tunnel/firewall/syscall_windows.go
@@ -35,8 +35,16 @@ package firewall
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmprovideradd0
//sys fwpmProviderAdd0(engineHandle uintptr, provider *wtFwpmProvider0, sd uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmProviderAdd0
-// https://docs.microsoft.com/sv-se/windows/desktop/api/aclapi/nf-aclapi-getsecurityinfo
-//sys getSecurityInfo(handle windows.Handle, objectType wtObjectType, si uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *uintptr, sacl *uintptr, securityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo
+//TODO: Add these to x/sys/windows:
-// https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-getsecuritydescriptorlength
-//sys getSecurityDescriptorLength(securityDescriptor uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
+// https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-getsididentifierauthority
+//sys getSidIdentifierAuthority(sid *windows.SID) (authority *windows.SidIdentifierAuthority) = advapi32.GetSidIdentifierAuthority
+
+// https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-getsidsubauthoritycount
+//sys getSidSubAuthorityCount(sid *windows.SID) (count *uint8) = advapi32.GetSidSubAuthorityCount
+
+// https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-getsidsubauthority
+//sys getSidSubAuthority(sid *windows.SID, index uint32) (subAuthority *uint32) = advapi32.GetSidSubAuthority
+
+// https://docs.microsoft.com/en-us/windows/desktop/api/aclapi/nf-aclapi-buildsecuritydescriptorw
+//sys buildSecurityDescriptor(owner *wtTrustee, group *wtTrustee, countAccessEntries uint32, accessEntries *wtExplicitAccess, countAuditEntries uint32, auditEntries *wtExplicitAccess, oldSd **byte, sizeNewSd *uint32, newSd **byte) (ret error) = advapi32.BuildSecurityDescriptorW
diff --git a/tunnel/firewall/types_windows.go b/tunnel/firewall/types_windows.go
index e06f7d2b..6f86571f 100644
--- a/tunnel/firewall/types_windows.go
+++ b/tunnel/firewall/types_windows.go
@@ -393,14 +393,6 @@ type wtFwpmProvider0 struct {
serviceName *uint16
}
-type wtObjectType uint32
-
-const (
- cSE_KERNEL_OBJECT wtObjectType = 6
-
- cDACL_SECURITY_INFORMATION = 4
-)
-
type wtIfType uint32
const (
@@ -415,3 +407,51 @@ const (
cIPPROTO_TCP wtIPProto = 6
cIPPROTO_UDP wtIPProto = 17
)
+
+type wtExplicitAccess struct {
+ accessPermissions uint32
+ accessMode uint32
+ inheritance uint32
+ trustee wtTrustee
+}
+
+type wtTrustee struct {
+ multipleTrustee *wtTrustee
+ multipleTrusteeOperation uint32
+ trusteeForm uint32
+ trusteeType uint32
+ sid *windows.SID
+}
+
+const (
+ cTRUSTEE_IS_UNKNOWN = iota
+ cTRUSTEE_IS_USER
+ cTRUSTEE_IS_GROUP
+ cTRUSTEE_IS_DOMAIN
+ cTRUSTEE_IS_ALIAS
+ cTRUSTEE_IS_WELL_KNOWN_GROUP
+ cTRUSTEE_IS_DELETED
+ cTRUSTEE_IS_INVALID
+ cTRUSTEE_IS_COMPUTER
+)
+const (
+ cTRUSTEE_IS_SID = iota
+ cTRUSTEE_IS_NAME
+ cTRUSTEE_BAD_FORM
+ cTRUSTEE_IS_OBJECTS_AND_SID
+ cTRUSTEE_IS_OBJECTS_AND_NAME
+)
+
+const (
+ cNOT_USED_ACCESS = iota
+ cGRANT_ACCESS
+ cSET_ACCESS
+ cDENY_ACCESS
+ cREVOKE_ACCESS
+ cSET_AUDIT_SUCCESS
+ cSET_AUDIT_FAILURE
+)
+
+const (
+ cFWP_ACTRL_MATCH_FILTER = 1
+)
diff --git a/tunnel/firewall/zsyscall_windows.go b/tunnel/firewall/zsyscall_windows.go
index 15e72703..82129d97 100644
--- a/tunnel/firewall/zsyscall_windows.go
+++ b/tunnel/firewall/zsyscall_windows.go
@@ -40,18 +40,20 @@ var (
modfwpuclnt = windows.NewLazySystemDLL("fwpuclnt.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
- procFwpmEngineOpen0 = modfwpuclnt.NewProc("FwpmEngineOpen0")
- procFwpmEngineClose0 = modfwpuclnt.NewProc("FwpmEngineClose0")
- procFwpmSubLayerAdd0 = modfwpuclnt.NewProc("FwpmSubLayerAdd0")
- procFwpmGetAppIdFromFileName0 = modfwpuclnt.NewProc("FwpmGetAppIdFromFileName0")
- procFwpmFreeMemory0 = modfwpuclnt.NewProc("FwpmFreeMemory0")
- procFwpmFilterAdd0 = modfwpuclnt.NewProc("FwpmFilterAdd0")
- procFwpmTransactionBegin0 = modfwpuclnt.NewProc("FwpmTransactionBegin0")
- procFwpmTransactionCommit0 = modfwpuclnt.NewProc("FwpmTransactionCommit0")
- procFwpmTransactionAbort0 = modfwpuclnt.NewProc("FwpmTransactionAbort0")
- procFwpmProviderAdd0 = modfwpuclnt.NewProc("FwpmProviderAdd0")
- procGetSecurityInfo = modadvapi32.NewProc("GetSecurityInfo")
- procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
+ procFwpmEngineOpen0 = modfwpuclnt.NewProc("FwpmEngineOpen0")
+ procFwpmEngineClose0 = modfwpuclnt.NewProc("FwpmEngineClose0")
+ procFwpmSubLayerAdd0 = modfwpuclnt.NewProc("FwpmSubLayerAdd0")
+ procFwpmGetAppIdFromFileName0 = modfwpuclnt.NewProc("FwpmGetAppIdFromFileName0")
+ procFwpmFreeMemory0 = modfwpuclnt.NewProc("FwpmFreeMemory0")
+ procFwpmFilterAdd0 = modfwpuclnt.NewProc("FwpmFilterAdd0")
+ procFwpmTransactionBegin0 = modfwpuclnt.NewProc("FwpmTransactionBegin0")
+ procFwpmTransactionCommit0 = modfwpuclnt.NewProc("FwpmTransactionCommit0")
+ procFwpmTransactionAbort0 = modfwpuclnt.NewProc("FwpmTransactionAbort0")
+ procFwpmProviderAdd0 = modfwpuclnt.NewProc("FwpmProviderAdd0")
+ procGetSidIdentifierAuthority = modadvapi32.NewProc("GetSidIdentifierAuthority")
+ procGetSidSubAuthorityCount = modadvapi32.NewProc("GetSidSubAuthorityCount")
+ procGetSidSubAuthority = modadvapi32.NewProc("GetSidSubAuthority")
+ procBuildSecurityDescriptorW = modadvapi32.NewProc("BuildSecurityDescriptorW")
)
func fwpmEngineOpen0(serverName *uint16, authnService wtRpcCAuthN, authIdentity *uintptr, session *wtFwpmSession0, engineHandle unsafe.Pointer) (err error) {
@@ -167,20 +169,28 @@ func fwpmProviderAdd0(engineHandle uintptr, provider *wtFwpmProvider0, sd uintpt
return
}
-func getSecurityInfo(handle windows.Handle, objectType wtObjectType, si uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *uintptr, sacl *uintptr, securityDescriptor *uintptr) (err error) {
- r1, _, e1 := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(securityDescriptor)), 0)
- if r1 != 0 {
- if e1 != 0 {
- err = errnoErr(e1)
- } else {
- err = syscall.EINVAL
- }
- }
+func getSidIdentifierAuthority(sid *windows.SID) (authority *windows.SidIdentifierAuthority) {
+ r0, _, _ := syscall.Syscall(procGetSidIdentifierAuthority.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+ authority = (*windows.SidIdentifierAuthority)(unsafe.Pointer(r0))
return
}
-func getSecurityDescriptorLength(securityDescriptor uintptr) (len uint32) {
- r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(securityDescriptor), 0, 0)
- len = uint32(r0)
+func getSidSubAuthorityCount(sid *windows.SID) (count *uint8) {
+ r0, _, _ := syscall.Syscall(procGetSidSubAuthorityCount.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+ count = (*uint8)(unsafe.Pointer(r0))
+ return
+}
+
+func getSidSubAuthority(sid *windows.SID, index uint32) (subAuthority *uint32) {
+ r0, _, _ := syscall.Syscall(procGetSidSubAuthority.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(index), 0)
+ subAuthority = (*uint32)(unsafe.Pointer(r0))
+ return
+}
+
+func buildSecurityDescriptor(owner *wtTrustee, group *wtTrustee, countAccessEntries uint32, accessEntries *wtExplicitAccess, countAuditEntries uint32, auditEntries *wtExplicitAccess, oldSd **byte, sizeNewSd *uint32, newSd **byte) (ret error) {
+ r0, _, _ := syscall.Syscall9(procBuildSecurityDescriptorW.Addr(), 9, uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(countAccessEntries), uintptr(unsafe.Pointer(accessEntries)), uintptr(countAuditEntries), uintptr(unsafe.Pointer(auditEntries)), uintptr(unsafe.Pointer(oldSd)), uintptr(unsafe.Pointer(sizeNewSd)), uintptr(unsafe.Pointer(newSd)))
+ if r0 != 0 {
+ ret = syscall.Errno(r0)
+ }
return
}