github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/agent/daemon/enrichment/enrichers_test.go (about)

     1  package enrichment
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"path/filepath"
     8  	"strconv"
     9  	"testing"
    10  	"testing/fstest"
    11  	"time"
    12  
    13  	castpb "github.com/castai/kvisor/api/v1/runtime"
    14  	"github.com/castai/kvisor/pkg/ebpftracer/types"
    15  	"github.com/castai/kvisor/pkg/logging"
    16  	"github.com/castai/kvisor/pkg/proc"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestFileHashEnricher(t *testing.T) {
    21  	t.Run("should set sha256 hash of file", func(t *testing.T) {
    22  		r := require.New(t)
    23  		containerID := "12354"
    24  		fileName := "test"
    25  		pid := uint32(22)
    26  		testFile := generateExecutableTestMapFile(2048)
    27  		wantedSum := sha256.Sum256(testFile.Data)
    28  		fsys := fstest.MapFS{
    29  			filepath.Join(strconv.Itoa(int(pid)), "root", fileName): testFile,
    30  		}
    31  
    32  		enricher := EnrichWithFileHash(
    33  			logging.New(&logging.Config{}),
    34  			createDummyMntNSPIDStore(0, 10),
    35  			fsys)
    36  
    37  		event := &castpb.Event{
    38  			EventType:   castpb.EventType_EVENT_EXEC,
    39  			ContainerId: containerID,
    40  			Data: &castpb.Event_Exec{
    41  				Exec: &castpb.Exec{
    42  					Path: filepath.Join(fileName),
    43  					Args: []string{},
    44  				},
    45  			},
    46  		}
    47  
    48  		enricher.Enrich(context.TODO(), &EnrichRequest{
    49  			Event: event,
    50  			EbpfEvent: &types.Event{
    51  				Context: &types.EventContext{
    52  					NodeHostPid: pid,
    53  				},
    54  				Args: types.SchedProcessExecArgs{},
    55  			},
    56  		})
    57  
    58  		r.Equal(wantedSum[:], event.GetExec().GetMeta().GetHashSha256())
    59  	})
    60  
    61  	t.Run("should ignore missing file", func(t *testing.T) {
    62  		r := require.New(t)
    63  		containerID := "12354"
    64  		fileName := "test"
    65  		fsys := fstest.MapFS{}
    66  
    67  		enricher := EnrichWithFileHash(logging.New(&logging.Config{}),
    68  			createDummyMntNSPIDStore(0, 1),
    69  			fsys)
    70  
    71  		event := &castpb.Event{
    72  			EventType:   castpb.EventType_EVENT_EXEC,
    73  			ContainerId: containerID,
    74  			Data: &castpb.Event_Exec{
    75  				Exec: &castpb.Exec{
    76  					Path: filepath.Join(fileName),
    77  					Args: []string{},
    78  				},
    79  			},
    80  		}
    81  
    82  		enricher.Enrich(context.TODO(), &EnrichRequest{
    83  			Event: event,
    84  			EbpfEvent: &types.Event{
    85  				Context: &types.EventContext{},
    86  				Args:    types.SchedProcessExecArgs{},
    87  			},
    88  		})
    89  
    90  		r.Nil(event.GetExec().Meta)
    91  	})
    92  
    93  	t.Run("should ignore non exec event", func(t *testing.T) {
    94  		r := require.New(t)
    95  		containerID := "12354"
    96  		fsys := fstest.MapFS{}
    97  
    98  		enricher := EnrichWithFileHash(logging.New(&logging.Config{}),
    99  			createDummyMntNSPIDStore(0, 1),
   100  			fsys)
   101  
   102  		event := &castpb.Event{
   103  			EventType:   castpb.EventType_EVENT_DNS,
   104  			ContainerId: containerID,
   105  		}
   106  
   107  		enricher.Enrich(context.TODO(), &EnrichRequest{
   108  			Event: event,
   109  			EbpfEvent: &types.Event{
   110  				Context: &types.EventContext{},
   111  				Args:    types.SchedProcessExecArgs{},
   112  			},
   113  		})
   114  
   115  		r.Nil(event.GetExec())
   116  	})
   117  
   118  	t.Run("should set sha256 hash of file for two same events", func(t *testing.T) {
   119  		r := require.New(t)
   120  		containerID := "12354"
   121  		fileName := "test"
   122  		pid := proc.PID(22)
   123  		testFile := generateExecutableTestMapFile(2048)
   124  		wantedSum := sha256.Sum256(testFile.Data)
   125  		fsys := fstest.MapFS{
   126  			filepath.Join(strconv.Itoa(int(pid)), "root", fileName): testFile,
   127  		}
   128  
   129  		enricher := EnrichWithFileHash(
   130  			logging.New(&logging.Config{}),
   131  			createDummyMntNSPIDStore(0, pid),
   132  			fsys)
   133  
   134  		event := &castpb.Event{
   135  			EventType:   castpb.EventType_EVENT_EXEC,
   136  			ContainerId: containerID,
   137  			Data: &castpb.Event_Exec{
   138  				Exec: &castpb.Exec{
   139  					Path: filepath.Join(fileName),
   140  					Args: []string{},
   141  				},
   142  			},
   143  		}
   144  
   145  		enricher.Enrich(context.TODO(), &EnrichRequest{
   146  			Event: event,
   147  			EbpfEvent: &types.Event{
   148  				Context: &types.EventContext{
   149  					NodeHostPid: pid,
   150  				},
   151  				Args: types.SchedProcessExecArgs{},
   152  			},
   153  		})
   154  
   155  		r.Equal(wantedSum[:], event.GetExec().GetMeta().GetHashSha256())
   156  
   157  		event = &castpb.Event{
   158  			EventType:   castpb.EventType_EVENT_EXEC,
   159  			ContainerId: containerID,
   160  			Data: &castpb.Event_Exec{
   161  				Exec: &castpb.Exec{
   162  					Path: filepath.Join(fileName),
   163  					Args: []string{},
   164  				},
   165  			},
   166  		}
   167  
   168  		enricher.Enrich(context.TODO(), &EnrichRequest{
   169  			Event: event,
   170  			EbpfEvent: &types.Event{
   171  				Context: &types.EventContext{
   172  					NodeHostPid: pid,
   173  				},
   174  				Args: types.SchedProcessExecArgs{},
   175  			},
   176  		})
   177  
   178  		r.Equal(wantedSum[:], event.GetExec().GetMeta().GetHashSha256())
   179  	})
   180  
   181  	t.Run("should fallback to other pids in mount ns if file is missing", func(t *testing.T) {
   182  		r := require.New(t)
   183  		containerID := "12354"
   184  		fileName := "test"
   185  		pid := proc.PID(22)
   186  		mountNSID := proc.NamespaceID(10)
   187  		testFile := generateExecutableTestMapFile(2048)
   188  		wantedSum := sha256.Sum256(testFile.Data)
   189  		fsys := fstest.MapFS{
   190  			filepath.Join(strconv.Itoa(int(pid)), "root", fileName): testFile,
   191  		}
   192  
   193  		enricher := EnrichWithFileHash(
   194  			logging.New(&logging.Config{}),
   195  			createDummyMntNSPIDStore(mountNSID, pid),
   196  			fsys)
   197  
   198  		event := &castpb.Event{
   199  			EventType:   castpb.EventType_EVENT_EXEC,
   200  			ContainerId: containerID,
   201  			Data: &castpb.Event_Exec{
   202  				Exec: &castpb.Exec{
   203  					Path: filepath.Join(fileName),
   204  					Args: []string{},
   205  				},
   206  			},
   207  		}
   208  
   209  		enricher.Enrich(context.TODO(), &EnrichRequest{
   210  			Event: event,
   211  			EbpfEvent: &types.Event{
   212  				Context: &types.EventContext{
   213  					MntID: uint32(mountNSID),
   214  				},
   215  				Args: types.SchedProcessExecArgs{},
   216  			},
   217  		})
   218  
   219  		r.Equal(wantedSum[:], event.GetExec().GetMeta().GetHashSha256())
   220  	})
   221  }
   222  
   223  func generateTestData(size uint32) []byte {
   224  	result := make([]byte, size)
   225  	rand.Read(result)
   226  	return result
   227  }
   228  
   229  func generateExecutableTestMapFile(size uint32) *fstest.MapFile {
   230  	return &fstest.MapFile{
   231  		Data:    generateTestData(size),
   232  		Mode:    0777,
   233  		ModTime: time.Now(),
   234  	}
   235  }
   236  
   237  func createDummyMntNSPIDStore(ns proc.NamespaceID, pids ...proc.PID) *types.PIDsPerNamespace {
   238  	b, err := types.NewPIDsPerNamespaceCache(10, 5)
   239  	if err != nil {
   240  		panic(err)
   241  	}
   242  
   243  	for _, pid := range pids {
   244  		b.AddToBucket(ns, pid)
   245  	}
   246  
   247  	return b
   248  }