From 0c8f8a62c75eca5f8d2e9496179e610f54f34a28 Mon Sep 17 00:00:00 2001 From: Zoltan Papp Date: Thu, 1 Aug 2024 16:46:55 +0200 Subject: [PATCH] Handling invalid UTF-8 character in sys info (#2360) In some operation systems, the sys info contains invalid characters. In this patch try to keep the original fallback logic but filter out the cases when the character is invalid. --- client/system/info_darwin_test.go | 5 +- client/system/info_linux.go | 63 +++++++-- client/system/sysinfo_linux.go | 12 ++ client/system/sysinfo_linux_test.go | 198 ++++++++++++++++++++++++++++ encryption/message.go | 2 +- 5 files changed, 264 insertions(+), 16 deletions(-) create mode 100644 client/system/sysinfo_linux.go create mode 100644 client/system/sysinfo_linux_test.go diff --git a/client/system/info_darwin_test.go b/client/system/info_darwin_test.go index 94e0b9e5e..5608bc776 100644 --- a/client/system/info_darwin_test.go +++ b/client/system/info_darwin_test.go @@ -1,11 +1,12 @@ package system import ( - log "github.com/sirupsen/logrus" "testing" + + log "github.com/sirupsen/logrus" ) -func Test_sysInfo(t *testing.T) { +func Test_sysInfoMac(t *testing.T) { t.Skip("skipping darwin test") serialNum, prodName, manufacturer := sysInfo() if serialNum == "" { diff --git a/client/system/info_linux.go b/client/system/info_linux.go index db58d913f..b6a142bce 100644 --- a/client/system/info_linux.go +++ b/client/system/info_linux.go @@ -21,6 +21,26 @@ import ( "github.com/netbirdio/netbird/version" ) +type SysInfoGetter interface { + GetSysInfo() SysInfo +} + +type SysInfoWrapper struct { + si sysinfo.SysInfo +} + +func (s SysInfoWrapper) GetSysInfo() SysInfo { + s.si.GetSysInfo() + return SysInfo{ + ChassisSerial: s.si.Chassis.Serial, + ProductSerial: s.si.Product.Serial, + BoardSerial: s.si.Board.Serial, + ProductName: s.si.Product.Name, + BoardName: s.si.Board.Name, + ProductVendor: s.si.Product.Vendor, + } +} + // GetInfo retrieves and parses the system information func GetInfo(ctx context.Context) *Info { info := _getInfo() @@ -45,7 +65,8 @@ func GetInfo(ctx context.Context) *Info { log.Warnf("failed to discover network addresses: %s", err) } - serialNum, prodName, manufacturer := sysInfo() + si := SysInfoWrapper{} + serialNum, prodName, manufacturer := sysInfo(si.GetSysInfo()) env := Environment{ Cloud: detect_cloud.Detect(ctx), @@ -87,20 +108,36 @@ func _getInfo() string { return out.String() } -func sysInfo() (serialNumber string, productName string, manufacturer string) { - var si sysinfo.SysInfo - si.GetSysInfo() +func sysInfo(si SysInfo) (string, string, string) { isascii := regexp.MustCompile("^[[:ascii:]]+$") - serial := si.Chassis.Serial - if (serial == "Default string" || serial == "") && si.Product.Serial != "" { - serial = si.Product.Serial + + serials := []string{si.ChassisSerial, si.ProductSerial} + serial := "" + + for _, s := range serials { + if isascii.MatchString(s) { + serial = s + if s != "Default string" { + break + } + } } - if (!isascii.MatchString(serial)) && si.Board.Serial != "" { - serial = si.Board.Serial + + if serial == "" && isascii.MatchString(si.BoardSerial) { + serial = si.BoardSerial } - name := si.Product.Name - if (!isascii.MatchString(name)) && si.Board.Name != "" { - name = si.Board.Name + + var name string + for _, n := range []string{si.ProductName, si.BoardName} { + if isascii.MatchString(n) { + name = n + break + } } - return serial, name, si.Product.Vendor + + var manufacturer string + if isascii.MatchString(si.ProductVendor) { + manufacturer = si.ProductVendor + } + return serial, name, manufacturer } diff --git a/client/system/sysinfo_linux.go b/client/system/sysinfo_linux.go new file mode 100644 index 000000000..df0f5574c --- /dev/null +++ b/client/system/sysinfo_linux.go @@ -0,0 +1,12 @@ +package system + +// SysInfo used to moc out the sysinfo getter +type SysInfo struct { + ChassisSerial string + ProductSerial string + BoardSerial string + + ProductName string + BoardName string + ProductVendor string +} diff --git a/client/system/sysinfo_linux_test.go b/client/system/sysinfo_linux_test.go new file mode 100644 index 000000000..f6a0b7058 --- /dev/null +++ b/client/system/sysinfo_linux_test.go @@ -0,0 +1,198 @@ +package system + +import "testing" + +func Test_sysInfo(t *testing.T) { + tests := []struct { + name string + sysInfo SysInfo + wantSerialNum string + wantProdName string + wantManufacturer string + }{ + { + name: "Test Case 1", + sysInfo: SysInfo{ + ChassisSerial: "Default string", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Empty Chassis Serial", + sysInfo: SysInfo{ + ChassisSerial: "", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Empty Chassis Serial", + sysInfo: SysInfo{ + ChassisSerial: "", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Fallback to Product Serial", + sysInfo: SysInfo{ + ChassisSerial: "Default string", + ProductSerial: "Product serial", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "Product serial", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Fallback to Product Serial with default string", + sysInfo: SysInfo{ + ChassisSerial: "Default string", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Non UTF-8 in Chassis Serial", + sysInfo: SysInfo{ + ChassisSerial: "\x80", + ProductSerial: "Product serial", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "Product serial", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Non UTF-8 in Chassis Serial and Product Serial", + sysInfo: SysInfo{ + ChassisSerial: "\x80", + ProductSerial: "\x80", + BoardSerial: "M80-G8013200245", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "M80-G8013200245", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + { + name: "Non UTF-8 in Chassis Serial and Product Serial and BoardSerial", + sysInfo: SysInfo{ + ChassisSerial: "\x80", + ProductSerial: "\x80", + BoardSerial: "\x80", + ProductName: "B650M-HDV/M.2", + BoardName: "B650M-HDV/M.2", + ProductVendor: "ASRock", + }, + wantSerialNum: "", + wantProdName: "B650M-HDV/M.2", + wantManufacturer: "ASRock", + }, + + { + name: "Empty Product Name", + sysInfo: SysInfo{ + ChassisSerial: "Default string", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "", + BoardName: "boardname", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "boardname", + wantManufacturer: "ASRock", + }, + { + name: "Invalid Product Name", + sysInfo: SysInfo{ + ChassisSerial: "Default string", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "\x80", + BoardName: "boardname", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "boardname", + wantManufacturer: "ASRock", + }, + { + name: "Invalid BoardName Name", + sysInfo: SysInfo{ + ChassisSerial: "Default string", + ProductSerial: "Default string", + BoardSerial: "M80-G8013200245", + ProductName: "\x80", + BoardName: "\x80", + ProductVendor: "ASRock", + }, + wantSerialNum: "Default string", + wantProdName: "", + wantManufacturer: "ASRock", + }, + { + name: "Invalid chars", + sysInfo: SysInfo{ + ChassisSerial: "\x80", + ProductSerial: "\x80", + BoardSerial: "\x80", + ProductName: "\x80", + BoardName: "\x80", + ProductVendor: "\x80", + }, + wantSerialNum: "", + wantProdName: "", + wantManufacturer: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotSerialNum, gotProdName, gotManufacturer := sysInfo(tt.sysInfo) + if gotSerialNum != tt.wantSerialNum { + t.Errorf("sysInfo() gotSerialNum = %v, want %v", gotSerialNum, tt.wantSerialNum) + } + if gotProdName != tt.wantProdName { + t.Errorf("sysInfo() gotProdName = %v, want %v", gotProdName, tt.wantProdName) + } + if gotManufacturer != tt.wantManufacturer { + t.Errorf("sysInfo() gotManufacturer = %v, want %v", gotManufacturer, tt.wantManufacturer) + } + }) + } +} diff --git a/encryption/message.go b/encryption/message.go index a646fa679..6e4cd7391 100644 --- a/encryption/message.go +++ b/encryption/message.go @@ -10,7 +10,7 @@ import ( func EncryptMessage(remotePubKey wgtypes.Key, ourPrivateKey wgtypes.Key, message pb.Message) ([]byte, error) { byteResp, err := pb.Marshal(message) if err != nil { - log.Errorf("failed marshalling message %v", err) + log.Errorf("failed marshalling message %v, %+v", err, message.String()) return nil, err }