// SPDX-License-Identifier: GPL-3.0-or-later package rootcheck import ( "reflect" "testing" ) func setInts(values ...int) map[int]bool { result := map[int]bool{} for _, value := range values { result[value] = true } return result } func setStrings(values ...string) map[string]bool { result := map[string]bool{} for _, value := range values { result[value] = true } return result } func TestCheckIsQuietWhenCrossViewsAgree(t *testing.T) { alerts := Check(Views{ VisiblePIDs: setInts(1, 2), AlivePIDs: setInts(1, 2), PSPIDs: setInts(1, 2), PSAvailable: true, PIDAlive: func(int) bool { return true }, ProcPIDExists: func(int) bool { return true }, ProcModules: setStrings("ext4"), SysLiveModules: setStrings("ext4"), }, Options{}) if len(alerts) != 0 { t.Fatalf("alerts = %+v, want none", alerts) } } func TestCheckReportsRootkitCrossViewSignalsInPythonOrder(t *testing.T) { alerts := Check(Views{ VisiblePIDs: setInts(1), AlivePIDs: setInts(1), PSPIDs: setInts(1), PSAvailable: true, PIDAlive: func(int) bool { return true }, ProcPIDExists: func(int) bool { return true }, ProcModules: setStrings("ext4"), SysLiveModules: setStrings("ext4", "diamorphine"), ModuleTaints: map[string]string{"vendor_gpu": "OE"}, KernelTaint: (1 << 12) | (1 << 13), ProcTCPPorts: setInts(22, 31337), SSTCPPorts: setInts(22), ProcUDPPorts: setInts(53, 4444), SSUDPPorts: setInts(53), ProcRawProtocols: setInts(1, 58), SSRawProtocols: setInts(58), ProcProtocolKinds: setStrings("sctp", "packet"), SSProtocolKinds: setStrings("packet"), PromiscuousIfaces: []string{"eth0"}, }, Options{}) got := make([]int, len(alerts)) for index, alert := range alerts { got[index] = alert.SID } want := []int{SIDHiddenModule, SIDKnownRootkitModule, SIDTaintedModule, SIDKernelTainted, SIDHiddenPort, SIDHiddenUDPPort, SIDHiddenRawSocket, SIDRawICMPSocket, SIDHiddenProtocolSocket, SIDPromiscuous} if !reflect.DeepEqual(got, want) { t.Fatalf("SIDs = %v, want %v", got, want) } if alerts[0].Severity != "CRITICAL" || alerts[1].Signature != "rootkit_known_module" || alerts[3].Severity != "HIGH" || alerts[7].Key != "rk:rawicmp:1" { t.Fatalf("unexpected alert detail: %+v", alerts) } } func TestCheckRechecksProcessCandidatesAndLimitsRenderedPIDs(t *testing.T) { alive := map[int]bool{} for pid := 1; pid <= 25; pid++ { alive[pid] = true } alerts := Check(Views{AlivePIDs: alive, VisiblePIDs: map[int]bool{}, PIDAlive: func(pid int) bool { return pid != 1 }, ProcPIDExists: func(int) bool { return false }, }, Options{}) if len(alerts) != 1 { t.Fatalf("alerts = %+v, want one", alerts) } if len(alerts[0].PIDs) != 20 || alerts[0].PIDs[0] != 2 || alerts[0].PIDs[19] != 21 { t.Fatalf("pids = %v, want [2..21]", alerts[0].PIDs) } } func TestCheckHonorsNormalizedModuleAllowlist(t *testing.T) { alerts := Check(Views{ModuleTaints: map[string]string{"vendor-gpu": "OE"}}, Options{ AllowedModules: setStrings("vendor_gpu"), }) if len(alerts) != 0 { t.Fatalf("alerts = %+v, want none", alerts) } }