From 4bf1736a83d8e73eb917fdc7302c04622e80c361 Mon Sep 17 00:00:00 2001
From: Vladimir Stoilov <vladimir@safing.io>
Date: Fri, 28 Jun 2024 13:20:18 +0300
Subject: [PATCH] [service] Add check for kext command size

---
 .../interception/windowskext2/handler.go      |   9 +
 windows_kext/kextinterface/info.go            | 206 +++++++++++++-----
 windows_kext/kextinterface/protocol_test.go   |   9 +
 .../kextinterface/testdata/rust_info_test.bin | Bin 57546 -> 58213 bytes
 windows_kext/protocol/src/info.rs             |  17 ++
 .../protocol/testdata/go_command_test.bin     | Bin 43436 -> 42792 bytes
 6 files changed, 186 insertions(+), 55 deletions(-)

diff --git a/service/firewall/interception/windowskext2/handler.go b/service/firewall/interception/windowskext2/handler.go
index bb6348dd..166ebbc2 100644
--- a/service/firewall/interception/windowskext2/handler.go
+++ b/service/firewall/interception/windowskext2/handler.go
@@ -5,11 +5,13 @@ package windowskext
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net"
 	"time"
 
 	"github.com/safing/portmaster/service/process"
+	"github.com/safing/portmaster/windows_kext/kextinterface"
 
 	"github.com/tevino/abool"
 
@@ -32,8 +34,15 @@ func (v *VersionInfo) String() string {
 func Handler(ctx context.Context, packets chan packet.Packet, bandwidthUpdate chan *packet.BandwidthUpdate) {
 	for {
 		packetInfo, err := RecvVerdictRequest()
+
+		if errors.Is(err, kextinterface.ErrUnexpectedInfoSize) || errors.Is(err, kextinterface.ErrUnexpectedReadError) {
+			log.Criticalf("unexpected kext info data: %s", err)
+			continue // Depending on the info type this may not affect the functionality. Try to continue reading the next commands.
+		}
+
 		if err != nil {
 			log.Warningf("failed to get packet from windows kext: %s", err)
+			// Probably IO error, nothing else we can do.
 			return
 		}
 
diff --git a/windows_kext/kextinterface/info.go b/windows_kext/kextinterface/info.go
index 763c3e8e..a2f5cd91 100644
--- a/windows_kext/kextinterface/info.go
+++ b/windows_kext/kextinterface/info.go
@@ -3,6 +3,7 @@ package kextinterface
 import (
 	"encoding/binary"
 	"errors"
+	"fmt"
 	"io"
 )
 
@@ -18,6 +19,7 @@ const (
 
 var (
 	ErrUnknownInfoType     = errors.New("unknown info type")
+	ErrUnexpectedInfoSize  = errors.New("unexpected info size")
 	ErrUnexpectedReadError = errors.New("unexpected read error")
 )
 
@@ -135,117 +137,215 @@ type Info struct {
 	BandwidthStats  *BandwidthStatsArray
 }
 
-func RecvInfo(reader io.Reader) (*Info, error) {
-	var infoType byte
-	err := binary.Read(reader, binary.LittleEndian, &infoType)
+type readHelper struct {
+	infoType    byte
+	commandSize uint32
+
+	readSize int
+
+	reader io.Reader
+}
+
+func newReadHelper(reader io.Reader) (*readHelper, error) {
+	helper := &readHelper{reader: reader}
+
+	err := binary.Read(reader, binary.LittleEndian, &helper.infoType)
 	if err != nil {
 		return nil, err
 	}
 
-	// Read size of data
-	var size uint32
-	err = binary.Read(reader, binary.LittleEndian, &size)
+	err = binary.Read(reader, binary.LittleEndian, &helper.commandSize)
 	if err != nil {
 		return nil, err
 	}
 
+	return helper, nil
+}
+
+func (r *readHelper) ReadData(data any) error {
+	err := binary.Read(r, binary.LittleEndian, data)
+	if err != nil {
+		return errors.Join(ErrUnexpectedReadError, err)
+	}
+
+	if err := r.checkOverRead(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Passing size = 0 will read the rest of the command.
+func (r *readHelper) ReadBytes(size uint32) ([]byte, error) {
+	if uint32(r.readSize) >= r.commandSize {
+		return nil, errors.Join(fmt.Errorf("cannot read more bytes than the command size: %d >= %d", r.readSize, r.commandSize), ErrUnexpectedReadError)
+	}
+
+	if size == 0 {
+		size = r.commandSize - uint32(r.readSize)
+	}
+
+	if r.commandSize < uint32(r.readSize)+size {
+		return nil, ErrUnexpectedInfoSize
+	}
+
+	bytes := make([]byte, size)
+	err := binary.Read(r, binary.LittleEndian, bytes)
+	if err != nil {
+		return nil, errors.Join(ErrUnexpectedReadError, err)
+	}
+
+	return bytes, nil
+}
+
+func (r *readHelper) ReadUntilTheEnd() {
+	_, _ = r.ReadBytes(0)
+}
+
+func (r *readHelper) checkOverRead() error {
+	if uint32(r.readSize) > r.commandSize {
+		return ErrUnexpectedInfoSize
+	}
+
+	return nil
+}
+
+func (r *readHelper) Read(p []byte) (n int, err error) {
+	n, err = r.reader.Read(p)
+	r.readSize += n
+	return
+}
+
+func RecvInfo(reader io.Reader) (*Info, error) {
+	helper, err := newReadHelper(reader)
+	if err != nil {
+		return nil, err
+	}
+
+	// Make sure the whole command is read before return.
+	defer helper.ReadUntilTheEnd()
+
 	// Read data
-	switch infoType {
+	switch helper.infoType {
 	case InfoConnectionIpv4:
 		{
+			parseError := fmt.Errorf("failed to parse InfoConnectionIpv4")
+			newInfo := ConnectionV4{}
 			var fixedSizeValues connectionV4Internal
-			err = binary.Read(reader, binary.LittleEndian, &fixedSizeValues)
+			// Read fixed size values.
+			err = helper.ReadData(&fixedSizeValues)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err, fmt.Errorf("fixed"))
 			}
-			// Read size of payload
-			var size uint32
-			err = binary.Read(reader, binary.LittleEndian, &size)
+			newInfo.connectionV4Internal = fixedSizeValues
+			// Read size of payload.
+			var payloadSize uint32
+			err = helper.ReadData(&payloadSize)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err, fmt.Errorf("payloadsize"))
 			}
-			newInfo := ConnectionV4{connectionV4Internal: fixedSizeValues, Payload: make([]byte, size)}
-			err = binary.Read(reader, binary.LittleEndian, &newInfo.Payload)
-			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+
+			// Check if there is payload.
+			if payloadSize > 0 {
+				// Read payload.
+				newInfo.Payload, err = helper.ReadBytes(payloadSize)
+				if err != nil {
+					return nil, errors.Join(parseError, err, fmt.Errorf("payload"))
+				}
 			}
 			return &Info{ConnectionV4: &newInfo}, nil
 		}
 	case InfoConnectionIpv6:
 		{
-			var fixedSizeValues connectionV6Internal
-			err = binary.Read(reader, binary.LittleEndian, &fixedSizeValues)
+			parseError := fmt.Errorf("failed to parse InfoConnectionIpv6")
+			newInfo := ConnectionV6{}
+
+			// Read fixed size values.
+			err = helper.ReadData(&newInfo.connectionV6Internal)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
-			// Read size of payload
-			var size uint32
-			err = binary.Read(reader, binary.LittleEndian, &size)
+
+			// Read size of payload.
+			var payloadSize uint32
+			err = helper.ReadData(&payloadSize)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
-			newInfo := ConnectionV6{connectionV6Internal: fixedSizeValues, Payload: make([]byte, size)}
-			err = binary.Read(reader, binary.LittleEndian, &newInfo.Payload)
-			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+
+			// Check if there is payload.
+			if payloadSize > 0 {
+				// Read payload.
+				newInfo.Payload, err = helper.ReadBytes(payloadSize)
+				if err != nil {
+					return nil, errors.Join(parseError, err)
+				}
 			}
+
 			return &Info{ConnectionV6: &newInfo}, nil
 		}
 	case InfoConnectionEndEventV4:
 		{
+			parseError := fmt.Errorf("failed to parse InfoConnectionEndEventV4")
 			var connectionEnd ConnectionEndV4
-			err = binary.Read(reader, binary.LittleEndian, &connectionEnd)
+
+			// Read fixed size values.
+			err = helper.ReadData(&connectionEnd)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			return &Info{ConnectionEndV4: &connectionEnd}, nil
 		}
 	case InfoConnectionEndEventV6:
 		{
+			parseError := fmt.Errorf("failed to parse InfoConnectionEndEventV6")
 			var connectionEnd ConnectionEndV6
-			err = binary.Read(reader, binary.LittleEndian, &connectionEnd)
+
+			// Read fixed size values.
+			err = helper.ReadData(&connectionEnd)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			return &Info{ConnectionEndV6: &connectionEnd}, nil
 		}
 	case InfoLogLine:
 		{
+			parseError := fmt.Errorf("failed to parse InfoLogLine")
 			logLine := LogLine{}
 			// Read severity
-			err = binary.Read(reader, binary.LittleEndian, &logLine.Severity)
+			err = helper.ReadData(&logLine.Severity)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			// Read string
-			line := make([]byte, size-1) // -1 for the severity enum.
-			err = binary.Read(reader, binary.LittleEndian, &line)
+			bytes, err := helper.ReadBytes(0)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
-			logLine.Line = string(line)
+			logLine.Line = string(bytes)
 			return &Info{LogLine: &logLine}, nil
 		}
 	case InfoBandwidthStatsV4:
 		{
+			parseError := fmt.Errorf("failed to parse InfoBandwidthStatsV4")
 			// Read Protocol
 			var protocol uint8
-			err = binary.Read(reader, binary.LittleEndian, &protocol)
+			err = helper.ReadData(&protocol)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			// Read size of array
 			var size uint32
-			err = binary.Read(reader, binary.LittleEndian, &size)
+			err = helper.ReadData(&size)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			// Read array
 			statsArray := make([]BandwidthValueV4, size)
 			for i := range int(size) {
-				err = binary.Read(reader, binary.LittleEndian, &statsArray[i])
+				err = helper.ReadData(&statsArray[i])
 				if err != nil {
-					return nil, errors.Join(ErrUnexpectedReadError, err)
+					return nil, errors.Join(parseError, err)
 				}
 			}
 
@@ -253,24 +353,25 @@ func RecvInfo(reader io.Reader) (*Info, error) {
 		}
 	case InfoBandwidthStatsV6:
 		{
+			parseError := fmt.Errorf("failed to parse InfoBandwidthStatsV6")
 			// Read Protocol
 			var protocol uint8
-			err = binary.Read(reader, binary.LittleEndian, &protocol)
+			err = helper.ReadData(&protocol)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			// Read size of array
 			var size uint32
-			err = binary.Read(reader, binary.LittleEndian, &size)
+			err = helper.ReadData(&size)
 			if err != nil {
-				return nil, errors.Join(ErrUnexpectedReadError, err)
+				return nil, errors.Join(parseError, err)
 			}
 			// Read array
 			statsArray := make([]BandwidthValueV6, size)
 			for i := range int(size) {
-				err = binary.Read(reader, binary.LittleEndian, &statsArray[i])
+				err = helper.ReadData(&statsArray[i])
 				if err != nil {
-					return nil, errors.Join(ErrUnexpectedReadError, err)
+					return nil, errors.Join(parseError, err)
 				}
 			}
 
@@ -278,10 +379,5 @@ func RecvInfo(reader io.Reader) (*Info, error) {
 		}
 	}
 
-	// Command not recognized, read until the end of command and return.
-	// During normal operation this should not happen.
-	unknownData := make([]byte, size)
-	_, _ = reader.Read(unknownData)
-
 	return nil, ErrUnknownInfoType
 }
diff --git a/windows_kext/kextinterface/protocol_test.go b/windows_kext/kextinterface/protocol_test.go
index cf047442..c09cf286 100644
--- a/windows_kext/kextinterface/protocol_test.go
+++ b/windows_kext/kextinterface/protocol_test.go
@@ -18,8 +18,17 @@ func TestRustInfoFile(t *testing.T) {
 	defer func() {
 		_ = file.Close()
 	}()
+	first := true
 	for {
 		info, err := RecvInfo(file)
+		// First info should be with invalid size.
+		if first {
+			if !errors.Is(err, ErrUnexpectedInfoSize) {
+				t.Errorf("unexpected error: %s\n", err)
+			}
+			first = false
+			continue
+		}
 		if err != nil {
 			if errors.Is(err, ErrUnexpectedReadError) {
 				t.Errorf("unexpected error: %s\n", err)
diff --git a/windows_kext/kextinterface/testdata/rust_info_test.bin b/windows_kext/kextinterface/testdata/rust_info_test.bin
index 3f9049a9d776e2eedec281a37386a26f05a396e1..3b8588c7f89039b308ff0da53345ebd70d20134a 100644
GIT binary patch
literal 58213
zcmeHJ+l~|k5bfES0mLgWKJx?m0VY2BDQHYI80EpwcgEdFfMX@+GN-#)h-9T_tLogU
zdJaD=%W}B<z5cno|FIlThr8qH{N(Ag&z^t&#g|`w{mpy-d~sf$EKi?be*Nt)KKcFM
zf4=kVzWA`bUw*e7A4Z)Xe!lH<UvvJT<}&c%cb`4{JpXw4pTiaOwfcU_|8&0Z_Cbf`
z#kKg4KVSX)>)$`TeDmtBH!pvC{mbFI>(k5M>z{Wuxe@`~kKbN?^S_GY70&fHPs@41
zBl=<u5QmSpBe9R<^!*1WO%cDE=MU{0Ezslxzei#ER`e(GPTs{{03UZJe8+EkI)~={
zWc4TdH)abRaBeC`I=7I0^Z7&Oo6XPUD?TYne}m4&IM<0c-j8QLIyt?BdxsAvFMN&!
zKRd-?Q{MzIDZ$}^)#Kh4pM5U${j0;TnXeblwBOh7AncVtbl6M*Pd`Gr_~$wa!sUkh
zk?5P)pXjT^->yE(T&numeTQ=Fg@w-E)uCJ8nE?#H6nuqXhEU?i4}a0%`SuMK<icc`
zr^3+Og7dC0)OO)uA0(F0U%Xr_d@RGQ%)#W-%U7(ro;WEy3BJNlfFPVdG?%R*zydSg
zfMLEbQxs1BfJWi_Y7SQ61s)1`YCe7p5<eBP-_M5tQYi6-&s{5Q79S=-20XfNI!|_3
z!<;jHA-0rDAx}aHj-b$}Q^F^euh?^dhrPs3uPKkeZ9IB^rr%*OX$?ZTybCvA&_d{z
zqcY&)JrbBi=MT;L@7SD2_@epy$s6p?%&FpI;raJd)Srmc*2lrSlgn10?HXwo&b3g2
z^OW-{*Xh<seUC9hzc0UQd<DkN_sRLq&*m#I>opwf-?Yat5&Mgu3db`S_P!azxAB-h
z{6Y?>`VwIscv5}j{fUEdt1gy*%W(?u(?JD3HhjgZN(;mLG0k0UKUjibLdg(GpF&Q~
zT&I4hd>sW}`RjmBmjCpT2!7K=;@#}4o?Fper@jjPi8;0SlnI9^2iL!=__ztAa3dce
z?+9NZ(B+5p*8*G8$FZfn3s(CX#zy#k`4A4T=$uQ#5UfN$k{AaKoHw9Ru|}|jz2c?F
zMO1)0go9@?G|Q13h6wz5l70^Hn)c5{f8yX>E+AX%G!P#?;=_rfl~ZH@>+c0mcYq_@
zf}z_^6dV}v;_?;4_*)0Ff6M&5V@-tM=F+)G8GR!J$+34nls#LS!@k8%!*Pq{XPDtf
ztH0a)8zg7EuNRO0ruN~B(>GNJ`<7fCJlchpeUSZ$gGc;Q=E5f=zpouW6FCtEZv=gK
zJNb$ncmJJ|!!r2L51rtAP6=T+A0oU~ejqB~b6WSKm9pwq1`d0;XW93R-QUU_dp^GX
z6|3AJVTkWzU(4Yf2nq-#zG(PT_NDAk<d@Y~yU+45OkBgsHD=~sRCw#N=M2y2=aF}6
z&;gSYE;nxEUl^V(Uy;k<ptLW=o+a+DNzPPZ8+@~cp*hAre4N#O3VbH38qpVQxM0{*
zU*S!W6zmpCa;v)PaQ;=xSM<~2Cwf(Tg+%l<=5rv>5=wmUhXX3$;dL73^UVar(fK^$
zRab8hd*mmaH-)dj-!=B2Z!Um+w!`k`Xklyj8xen@ge$wLZ1ln8(%8q&Cq2h@Sa7_S
z_-S7>i~~O%NDdzfONhq{jXEU*`CP(so&39s{mCKBb>eTrU}k?idH8*dIkWs=@_Oaa
z^RxL1ym-Qu^QF!S=VR%Iez+1bkA@k(WJB{*Ec>qXCk`^^79`gRXEWDdxI}!~R)y<t
z9#7bxnUn0+3G%u69V$zWh4jJu9fT#uWbo7ekroII5%2}xg#y^T+#&I0%wfp}B-^bY
z7T=j+dxnqtO!-%FALFVi7oyB-iZ2a*+SecB5QOPN=dIu?hJEInVXar)0G@;pjg1cB
zVPOOLKK)%0T+8Lsf8%bUL*FzUH^EAw1kd(;$fZgk#c!%GB*)NK+wXvLzzdmEWq2iT
zWkoAwu``1@LYDCi-hE-TA6*_Mri-5rLg(zybsFFfANeNqS5nB@ZIi-x7bplNJT5;D
zL)LgWL$iMDa;wS<;rr6pYcQ{pWqj4~(>1*n#PH*gBfR%u4KeLg^Nr<i3tu55Rw(JK
zKSV*m&+FP}+@I(t-0zU}S%}8!0QhX;_a@(Gpq_gt`4P!s5#rI`%BYWn#rzyWzMOZt
zPOH*L?QTvEJ_r6v53$4o_1DlRnX`zN>*EnoSXQBAOJ)o3`4#3Xh79t}e7(1laGty1
zuP+x5Gk3i{-R|YE-2b^d9`25(%YWz7a$a~-`cevM6-tKVlFOmLMfm9OHV$+J@%Z_|
zkbd%V#tU?LO>=Ploc7J)^}@U4a~I6cS%*pG`U~XtkcB=*Y?L4`AN;M5&84!>Xn2A4
z!SE4?rLRwRP=5GmQ#g6QguBpZj6;Q=@)B%?508A6uN3~!+<Eq~^v&NR=A2`~y%~<L
z(5-KHe<Hq&yAVqN*(veYHk;$28@7Ka7(U8vet!)<Qd-zv{B)3@?}xuaxiscF@n75e
z%IDbb8T+P|fsc*wp5ur3J36Q=FzDyaS3scY4;^IBZNI>5z=dB~_-Q`}4X!t}JxhQ;
zCD_PZ82gd9H6vbQz9O3ntO$OZojlx?iYS=lRx-J@!?G1!wt^$O3%Q#*Y!wbX^E3w&
IPwkug4@6CXZ2$lO

literal 57546
zcmeHN$!=X$5PY8E5QfAX*7*VW03?=tN<c`UAjpEx=h?APhH^<=Rkz+fcC5sX&h_c8
zuA%Q+<l_6o;c#~Rd;4{Madv)jdHi#AdAK?}`}25oc7FHmc=YW0`ByK#{^r~7UcNdz
z{^myqH|K|o+XBb0%lAKy7eD@$tIzH{J6zxY?(_Sfmp>l=@iCYW+kR5<<`(3|!}!mC
z`LNo3i;K%ofqh!_IQZfE#qHJqp9r|let59?ZCTKSOfoMfAU@pOBL3^|H^2V=?@zDa
zz4_<e>p$N9);9shAq;d<{qYo6Ki~Q4-dyiv^gwjp$K|t#>_rbeUykzroFso+4@+A6
zj=|uCJPB8D@0DFrS;aYmHg%R@h<>d70L>-$d-i$4QS~Pw4#X|Vg-y}qLWk#CA}xgc
zz9oIR{R)H-@~F=h_MAUIuA9q>kP3gOzC81H2qwOd9OJ;JIa}l^k(3JFo9pPib>5TA
z?8E6>aMN)F6Z9DnKoZi{39s)~LPM5R(r6xF0h&)0wgs6h{-__Uxis?|f|!Ka6*v+m
z7OvzzBlI~X0+UAqNu-*;G3HtDd*UrMM<Q^UGaON6KFRzB=CGdvjDwKVhd3v<kC70z
zQ_BkBBSZR2WmlTbEr)ZI(|%X<><Y|WtE~0s{rmK7?M{KwTr_f($b!o?@mFOI3mJH8
z%ZyvkbB0F{yxI?JPU1dxf#BS@G0llT{RA%|%BBnmCYdh)p-Eqven*@U-_?&)Ad&;}
zs4wfB{yxU77k#e&m)-I5)y?PsKYVVo#*LipB+<Dhb4pfDDxnm=iRSdoZ{)-j76oC1
zJi=tH?2JD4en<af6|qEroRj9p=dw@Od^O>m=ZMGk=Q#UZV&wRAKF|CHNv3brIUGy`
z0h#lZKQ0E3Pjk41mv>5++z^-~e7cv=`iAi<kYotH5U%(mY;7W8DD1l&Pytfk^h<!u
zX)@o5eMz!u&v8d^;VAiAqfdU0u3RM{ql^1I$KA>fnu~~Y*ymupD#jP~GO3Ww-Cn_*
z3UF~D|8=nPS`cVV<=-dXuaJ{&kCplxcJ2+bVzoy(Ay%NzkHB0qyhnvif(!L&Cr0!6
z#Y5uL{^+^1_)Pf~`uxRQPdtddB6MDn;Q4y$n_!MHCaK_pSnn0>gopPh@hb>QlAV#;
z>y;+`%x-0b{v<@8Cl01Re!nA8fBstP!=Gam_N2d@3Cn)*tya;dpf@ev_hIgRiPg;2
z&sCadkBB}mCIq?f3o@}Ee1QSs3N|DeY%V2kAz+=i&c(sk)2}d}Um#hyf(6cTPu$qg
zyugoer9W3iu1XVPmr8<2|E-fUpU>Y)egz>PIU`|7@M*5=%K7eNCyDBV@%@g?C8R*O
z;-jDMn7&4sVSL(0C&-4O3x!UhKZ&mo=Oi3pIp)bA%tVWkK95QPtczfgIs1(p{Z)kt
z-PBH`c>EC_&yNJIoBQ}kh!D))x7F(Sb4t$F#u5VK0N~RnMFDYsKZgB|bFKRrw_5)~
zaD6C#g<UyzQ4Z&}7Y6Mo1@H5{;Mmmqb47EX8TthKRPLcdpSONT97(dnePLEMHl}NG
zy2PR;`sdWkRT4P$ZR}SdER#prY&kM>mFDj}Jewe|aD`B=J?by>oOER3ToXS*eg(lO
z!WADU5yUU<SIC(HuK*w6NmTP;V>;%W)ko4_XFldH6%Kb_TgOufmv9AVq3=twi*rQx
z$I4;HLiu6Db%`AFJ-IUND@@zxH@0Zz^yU(^Rd#X+`@)jk<3-_<n4^n;_hFLaLK^12
z?|Wg65nDu{N4VlEJfGL^*;m!a>{lRJ>JuV(O}H{Q*ZhV6%hyt9TG{vlF1)_xIuLu$
zi}eG6X~3rf%Q^Kiq+I<z^?n?;=45W*t!5%A(;nrFldI&D*EjLpA}8G<Ik9q;<`m9v
zoDwYwC|+RXLT-+JRQz}oVuV!rcyelBBlI<zCu@Gg=Y0<qa@zaToW%S>Q|xk~&?!tu
zmJfO4i%W{nX%M)M_Maop<%|rnGnFbc3sw-W^j~4VmKFMam@86?-vBwnPq|-mQ>^HX
zO}DGCcnF@HP>&~qTL&|%pdXN&2QYKQe)|XSBlIf}0{f}UxuuVN{z~-4>ra{8FG4lp
zO3qazEWVh+WCYLLjzWKb=)Qw}%zg!;o1j9UL;Nnz<t$f8pi{U)^dyhw5$!9zsn`4C
z5H<Q>1f%7GL74D0UuQpTO2ZSgRL-2f1BGn$)#`VgzjAPteSvUYe7XWpeT-yv^}+at
z5E7ePIM{cDVSE9f=3o*)^JLF&_#*oia%9fue<HE+Me-{M+rV$y*B37ge-eSdT(Erj
z^Jros1sZUn965cD^*fT+l%NQyhQ(Ta;GEeoKY|9h&^)F>>%N*xfW(UAtdpyRk>b<7
z*krr(!3fU7Jnm{L3{jYMfvIA%=JH2a!)X1_Z=_{ERP(nKre$77uy{`PIow=tqJO1{
zK>VC8p-FCdY|(zW`W<r|<|+wRSeZC%zIlRH<{)RDId7Hq+81X|1U91o`K3QQo`eW3
ztQ_HrPh~DAgp3Azd+~&zBBm!5H(b3>*L<En##|b5mHI4@B$G#b@!78Unwx$vG|rI|
cZ|q8wTr{y(bLND1#=J>igB;PhN^{=+1DT4+>i_@%

diff --git a/windows_kext/protocol/src/info.rs b/windows_kext/protocol/src/info.rs
index b8eb0c79..fc50d589 100644
--- a/windows_kext/protocol/src/info.rs
+++ b/windows_kext/protocol/src/info.rs
@@ -441,6 +441,22 @@ fn generate_test_info_file() -> Result<(), std::io::Error> {
     for _ in 0..selected.capacity() {
         selected.push(enums.choose(&mut rng).unwrap().clone());
     }
+    // Write wrong size data.
+    let mut info = connection_info_v6(
+        1,
+        2,
+        3,
+        4,
+        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+        [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
+        5,
+        6,
+        7,
+        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    );
+    info.assert_size();
+    info.0[0] = InfoType::ConnectionIpv4 as u8;
+    file.write_all(&info.0)?;
 
     for value in selected {
         file.write_all(&match value {
@@ -548,5 +564,6 @@ fn generate_test_info_file() -> Result<(), std::io::Error> {
             }
         })?;
     }
+
     return Ok(());
 }
diff --git a/windows_kext/protocol/testdata/go_command_test.bin b/windows_kext/protocol/testdata/go_command_test.bin
index 586c70adf31fba822a9baddee108d6f8a36b6763..d518dbf12a3ac354dd6381a8f4a530e549449206 100644
GIT binary patch
literal 42792
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
Tp79?V4C>}vZI{q>d*A;9LH~IY

literal 43436
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
D1$2qa