Skip to content

Commit

Permalink
etw: Add test for provider name to GUID conversion
Browse files Browse the repository at this point in the history
Also simplified the name to GUID conversion code, and improved the
comments.

Signed-off-by: Kevin Parsons <[email protected]>
  • Loading branch information
kevpar committed Jul 10, 2019
1 parent 177d2ec commit c20fb68
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 13 deletions.
27 changes: 14 additions & 13 deletions pkg/etw/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,27 @@ func providerCallbackAdapter(sourceID *guid.GUID, state uintptr, level uintptr,
// uses the same algorithm as used by .NET's EventSource class, which is based
// on RFC 4122. More information on the algorithm can be found here:
// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/
// The algorithm is roughly:
// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
//
// The algorithm is roughly the RFC 4122 algorithm for a V5 UUID, but differs in
// the following ways:
// - The input name is first upper-cased, UTF16-encoded, and converted to
// big-endian.
// - No variant is set on the result UUID.
// - The result UUID is treated as being in little-endian format, rather than
// big-endian.
func providerIDFromName(name string) guid.GUID {
buffer := sha1.New()

namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
buffer.Write(namespace)

namespace := guid.GUID{0x482C2DB2, 0xC390, 0x47C8, [8]byte{0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}}
namespaceBytes := namespace.ToArray()
buffer.Write(namespaceBytes[:])
binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))

sum := buffer.Sum(nil)
sum[7] = (sum[7] & 0xf) | 0x50

return guid.GUID{
Data1: binary.LittleEndian.Uint32(sum[0:4]),
Data2: binary.LittleEndian.Uint16(sum[4:6]),
Data3: binary.LittleEndian.Uint16(sum[6:8]),
Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]},
}
a := [16]byte{}
copy(a[:], sum)
return guid.FromWindowsArray(a)
}

// NewProvider creates and registers a new ETW provider. The provider ID is
Expand Down
34 changes: 34 additions & 0 deletions pkg/etw/provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package etw

import (
"testing"

"github.com/Microsoft/go-winio/pkg/guid"
)

func mustGUIDFromString(t *testing.T, s string) guid.GUID {
g, err := guid.FromString(s)
if err != nil {
t.Fatal(err)
}
return g
}

func Test_ProviderIDFromName(t *testing.T) {
type testCase struct {
name string
g guid.GUID
}
testCases := []testCase{
{"wincni", mustGUIDFromString(t, "c822b598-f4cc-5a72-7933-ce2a816d033f")},
{"Moby", mustGUIDFromString(t, "6996f090-c5de-5082-a81e-5841acc3a635")},
{"ContainerD", mustGUIDFromString(t, "2acb92c0-eb9b-571a-69cf-8f3410f383ad")},
{"Microsoft.Virtualization.RunHCS", mustGUIDFromString(t, "0B52781F-B24D-5685-DDF6-69830ED40EC3")},
}
for _, tc := range testCases {
g := providerIDFromName(tc.name)
if g != tc.g {
t.Fatalf("Incorrect provider GUID.\nExpected: %s\nActual: %s", tc.g, g)
}
}
}

0 comments on commit c20fb68

Please sign in to comment.