github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/model_test.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the Apache License Version 2.0.
     3  // This product includes software developed at Datadog (https://www.datadoghq.com/).
     4  // Copyright 2016-present Datadog, Inc.
     5  
     6  // Package eval holds eval related files
     7  package eval
     8  
     9  import (
    10  	"container/list"
    11  	"fmt"
    12  	"net"
    13  	"reflect"
    14  	"syscall"
    15  	"unsafe"
    16  )
    17  
    18  var legacyFields = map[Field]Field{
    19  	"process.legacy_name": "process.name",
    20  }
    21  
    22  type testItem struct {
    23  	key   int
    24  	value string
    25  	flag  bool
    26  }
    27  
    28  type testProcess struct {
    29  	name      string
    30  	argv0     string
    31  	uid       int
    32  	gid       int
    33  	pid       int
    34  	isRoot    bool
    35  	list      *list.List
    36  	array     []*testItem
    37  	createdAt int64
    38  
    39  	// overridden values
    40  	orName        string
    41  	orNameValues  func() *StringValues
    42  	orArray       []*testItem
    43  	orArrayValues func() *StringValues
    44  }
    45  
    46  type testItemListIterator struct {
    47  	prev *list.Element
    48  }
    49  
    50  func (t *testItemListIterator) Front(ctx *Context) unsafe.Pointer {
    51  	if front := ctx.Event.(*testEvent).process.list.Front(); front != nil {
    52  		t.prev = front
    53  		return unsafe.Pointer(front)
    54  	}
    55  	return nil
    56  }
    57  
    58  func (t *testItemListIterator) Next() unsafe.Pointer {
    59  	if next := t.prev.Next(); next != nil {
    60  		t.prev = next
    61  		return unsafe.Pointer(next)
    62  	}
    63  	return nil
    64  }
    65  
    66  type testItemArrayIterator struct {
    67  	event *testEvent
    68  	index int
    69  }
    70  
    71  func (t *testItemArrayIterator) Front(ctx *Context) unsafe.Pointer {
    72  	t.event = ctx.Event.(*testEvent)
    73  
    74  	array := ctx.Event.(*testEvent).process.array
    75  	if t.index < len(array) {
    76  		t.index++
    77  		return unsafe.Pointer(array[0])
    78  	}
    79  	return nil
    80  }
    81  
    82  func (t *testItemArrayIterator) Next() unsafe.Pointer {
    83  	array := t.event.process.array
    84  	if t.index < len(array) {
    85  		value := array[t.index]
    86  		t.index++
    87  
    88  		return unsafe.Pointer(value)
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  type testOpen struct {
    95  	filename string
    96  	mode     int
    97  	flags    int
    98  	openedAt int64
    99  }
   100  
   101  type testMkdir struct {
   102  	filename string
   103  	mode     int
   104  }
   105  
   106  type testNetwork struct {
   107  	ip    net.IPNet
   108  	ips   []net.IPNet
   109  	cidr  net.IPNet
   110  	cidrs []net.IPNet
   111  }
   112  
   113  type testEvent struct {
   114  	id   string
   115  	kind string
   116  
   117  	process testProcess
   118  	network testNetwork
   119  	open    testOpen
   120  	mkdir   testMkdir
   121  
   122  	listEvaluated bool
   123  	uidEvaluated  bool
   124  	gidEvaluated  bool
   125  }
   126  
   127  type testModel struct {
   128  }
   129  
   130  func (e *testEvent) GetType() string {
   131  	return e.kind
   132  }
   133  
   134  func (e *testEvent) GetTags() []string {
   135  	return []string{}
   136  }
   137  
   138  func (m *testModel) NewEvent() Event {
   139  	return &testEvent{}
   140  }
   141  
   142  func (m *testModel) ValidateField(key string, value FieldValue) error {
   143  	switch key {
   144  	case "process.uid":
   145  		uid, ok := value.Value.(int)
   146  		if !ok {
   147  			return fmt.Errorf("invalid type for process.ui: %v", reflect.TypeOf(value.Value))
   148  		}
   149  
   150  		if uid < 0 {
   151  			return fmt.Errorf("process.uid cannot be negative: %d", uid)
   152  		}
   153  	}
   154  
   155  	return nil
   156  }
   157  
   158  func (m *testModel) GetIterator(field Field) (Iterator, error) {
   159  	switch field {
   160  	case "process.list":
   161  		return &testItemListIterator{}, nil
   162  	case "process.array":
   163  		return &testItemArrayIterator{}, nil
   164  	}
   165  
   166  	return nil, &ErrIteratorNotSupported{Field: field}
   167  }
   168  
   169  func (m *testModel) GetEvaluator(field Field, _ RegisterID) (Evaluator, error) {
   170  	switch field {
   171  
   172  	case "network.ip":
   173  
   174  		return &CIDREvaluator{
   175  			EvalFnc: func(ctx *Context) net.IPNet {
   176  				return ctx.Event.(*testEvent).network.ip
   177  			},
   178  			Field: field,
   179  		}, nil
   180  
   181  	case "network.cidr":
   182  
   183  		return &CIDREvaluator{
   184  			EvalFnc: func(ctx *Context) net.IPNet {
   185  				return ctx.Event.(*testEvent).network.cidr
   186  			},
   187  			Field: field,
   188  		}, nil
   189  
   190  	case "network.ips":
   191  
   192  		return &CIDRArrayEvaluator{
   193  			EvalFnc: func(ctx *Context) []net.IPNet {
   194  				var ipnets []net.IPNet
   195  				ipnets = append(ipnets, ctx.Event.(*testEvent).network.ips...)
   196  				return ipnets
   197  			},
   198  		}, nil
   199  
   200  	case "network.cidrs":
   201  
   202  		return &CIDRArrayEvaluator{
   203  			EvalFnc: func(ctx *Context) []net.IPNet {
   204  				return ctx.Event.(*testEvent).network.cidrs
   205  			},
   206  			Field: field,
   207  		}, nil
   208  
   209  	case "process.name":
   210  
   211  		return &StringEvaluator{
   212  			EvalFnc:     func(ctx *Context) string { return ctx.Event.(*testEvent).process.name },
   213  			Field:       field,
   214  			OpOverrides: GlobCmp,
   215  		}, nil
   216  
   217  	case "process.argv0":
   218  
   219  		return &StringEvaluator{
   220  			EvalFnc: func(ctx *Context) string { return ctx.Event.(*testEvent).process.argv0 },
   221  			Field:   field,
   222  		}, nil
   223  
   224  	case "process.uid":
   225  
   226  		return &IntEvaluator{
   227  			EvalFnc: func(ctx *Context) int {
   228  				// to test optimisation
   229  				ctx.Event.(*testEvent).uidEvaluated = true
   230  
   231  				return ctx.Event.(*testEvent).process.uid
   232  			},
   233  			Field: field,
   234  		}, nil
   235  
   236  	case "process.gid":
   237  
   238  		return &IntEvaluator{
   239  			EvalFnc: func(ctx *Context) int {
   240  				// to test optimisation
   241  				ctx.Event.(*testEvent).gidEvaluated = true
   242  
   243  				return ctx.Event.(*testEvent).process.gid
   244  			},
   245  			Field: field,
   246  		}, nil
   247  
   248  	case "process.pid":
   249  
   250  		return &IntEvaluator{
   251  			EvalFnc: func(ctx *Context) int {
   252  				// to test optimisation
   253  				ctx.Event.(*testEvent).uidEvaluated = true
   254  
   255  				return ctx.Event.(*testEvent).process.pid
   256  			},
   257  			Field: field,
   258  		}, nil
   259  
   260  	case "process.is_root":
   261  
   262  		return &BoolEvaluator{
   263  			EvalFnc: func(ctx *Context) bool { return ctx.Event.(*testEvent).process.isRoot },
   264  			Field:   field,
   265  		}, nil
   266  
   267  	case "process.list.key":
   268  
   269  		return &IntArrayEvaluator{
   270  			EvalFnc: func(ctx *Context) []int {
   271  				// to test optimisation
   272  				ctx.Event.(*testEvent).listEvaluated = true
   273  
   274  				var result []int
   275  
   276  				el := ctx.Event.(*testEvent).process.list.Front()
   277  				for el != nil {
   278  					result = append(result, el.Value.(*testItem).key)
   279  					el = el.Next()
   280  				}
   281  
   282  				return result
   283  			},
   284  			Field:  field,
   285  			Weight: IteratorWeight,
   286  		}, nil
   287  
   288  	case "process.list.value":
   289  
   290  		return &StringArrayEvaluator{
   291  			EvalFnc: func(ctx *Context) []string {
   292  				// to test optimisation
   293  				ctx.Event.(*testEvent).listEvaluated = true
   294  
   295  				var values []string
   296  
   297  				el := ctx.Event.(*testEvent).process.list.Front()
   298  				for el != nil {
   299  					values = append(values, el.Value.(*testItem).value)
   300  					el = el.Next()
   301  				}
   302  
   303  				return values
   304  			},
   305  			Field:  field,
   306  			Weight: IteratorWeight,
   307  		}, nil
   308  
   309  	case "process.list.flag":
   310  
   311  		return &BoolArrayEvaluator{
   312  			EvalFnc: func(ctx *Context) []bool {
   313  				// to test optimisation
   314  				ctx.Event.(*testEvent).listEvaluated = true
   315  
   316  				var result []bool
   317  
   318  				el := ctx.Event.(*testEvent).process.list.Front()
   319  				for el != nil {
   320  					result = append(result, el.Value.(*testItem).flag)
   321  					el = el.Next()
   322  				}
   323  
   324  				return result
   325  			},
   326  			Field:  field,
   327  			Weight: IteratorWeight,
   328  		}, nil
   329  
   330  	case "process.array.key":
   331  
   332  		return &IntArrayEvaluator{
   333  			EvalFnc: func(ctx *Context) []int {
   334  				var result []int
   335  
   336  				for _, el := range ctx.Event.(*testEvent).process.array {
   337  					result = append(result, el.key)
   338  				}
   339  
   340  				return result
   341  			},
   342  			Field:  field,
   343  			Weight: IteratorWeight,
   344  		}, nil
   345  
   346  	case "process.array.value":
   347  
   348  		return &StringArrayEvaluator{
   349  			EvalFnc: func(ctx *Context) []string {
   350  				var values []string
   351  
   352  				for _, el := range ctx.Event.(*testEvent).process.array {
   353  					values = append(values, el.value)
   354  				}
   355  
   356  				return values
   357  			},
   358  			Field:  field,
   359  			Weight: IteratorWeight,
   360  		}, nil
   361  
   362  	case "process.array.flag":
   363  
   364  		return &BoolArrayEvaluator{
   365  			EvalFnc: func(ctx *Context) []bool {
   366  				var result []bool
   367  
   368  				for _, el := range ctx.Event.(*testEvent).process.array {
   369  					result = append(result, el.flag)
   370  				}
   371  
   372  				return result
   373  			},
   374  			Field:  field,
   375  			Weight: IteratorWeight,
   376  		}, nil
   377  
   378  	case "process.created_at":
   379  
   380  		return &IntEvaluator{
   381  			EvalFnc: func(ctx *Context) int {
   382  				return int(ctx.Event.(*testEvent).process.createdAt)
   383  			},
   384  			Field: field,
   385  		}, nil
   386  
   387  	case "process.or_name":
   388  
   389  		return &StringEvaluator{
   390  			EvalFnc: func(ctx *Context) string {
   391  				return ctx.Event.(*testEvent).process.orName
   392  			},
   393  			Field: field,
   394  			OpOverrides: &OpOverrides{
   395  				StringValuesContains: func(a *StringEvaluator, b *StringValuesEvaluator, state *State) (*BoolEvaluator, error) {
   396  					evaluator := StringValuesEvaluator{
   397  						EvalFnc: func(ctx *Context) *StringValues {
   398  							return ctx.Event.(*testEvent).process.orNameValues()
   399  						},
   400  					}
   401  
   402  					return StringValuesContains(a, &evaluator, state)
   403  				},
   404  				StringEquals: func(a *StringEvaluator, b *StringEvaluator, state *State) (*BoolEvaluator, error) {
   405  					evaluator := StringValuesEvaluator{
   406  						EvalFnc: func(ctx *Context) *StringValues {
   407  							return ctx.Event.(*testEvent).process.orNameValues()
   408  						},
   409  					}
   410  
   411  					return StringValuesContains(a, &evaluator, state)
   412  				},
   413  			},
   414  		}, nil
   415  
   416  	case "process.or_array.value":
   417  
   418  		return &StringArrayEvaluator{
   419  			EvalFnc: func(ctx *Context) []string {
   420  				var values []string
   421  
   422  				for _, el := range ctx.Event.(*testEvent).process.orArray {
   423  					values = append(values, el.value)
   424  				}
   425  
   426  				return values
   427  			},
   428  			Field: field,
   429  			OpOverrides: &OpOverrides{
   430  				StringArrayContains: func(a *StringEvaluator, b *StringArrayEvaluator, state *State) (*BoolEvaluator, error) {
   431  					evaluator := StringValuesEvaluator{
   432  						EvalFnc: func(ctx *Context) *StringValues {
   433  							return ctx.Event.(*testEvent).process.orArrayValues()
   434  						},
   435  					}
   436  
   437  					return StringArrayMatches(b, &evaluator, state)
   438  				},
   439  				StringArrayMatches: func(a *StringArrayEvaluator, b *StringValuesEvaluator, state *State) (*BoolEvaluator, error) {
   440  					evaluator := StringValuesEvaluator{
   441  						EvalFnc: func(ctx *Context) *StringValues {
   442  							return ctx.Event.(*testEvent).process.orArrayValues()
   443  						},
   444  					}
   445  
   446  					return StringArrayMatches(a, &evaluator, state)
   447  				},
   448  			},
   449  		}, nil
   450  
   451  	case "open.filename":
   452  
   453  		return &StringEvaluator{
   454  			EvalFnc: func(ctx *Context) string { return ctx.Event.(*testEvent).open.filename },
   455  			Field:   field,
   456  		}, nil
   457  
   458  	case "open.flags":
   459  
   460  		return &IntEvaluator{
   461  			EvalFnc: func(ctx *Context) int { return ctx.Event.(*testEvent).open.flags },
   462  			Field:   field,
   463  		}, nil
   464  
   465  	case "open.mode":
   466  
   467  		return &IntEvaluator{
   468  			EvalFnc: func(ctx *Context) int { return ctx.Event.(*testEvent).open.mode },
   469  			Field:   field,
   470  		}, nil
   471  
   472  	case "open.opened_at":
   473  
   474  		return &IntEvaluator{
   475  			EvalFnc: func(ctx *Context) int {
   476  				return int(ctx.Event.(*testEvent).open.openedAt)
   477  			},
   478  			Field: field,
   479  		}, nil
   480  
   481  	case "mkdir.filename":
   482  
   483  		return &StringEvaluator{
   484  			EvalFnc: func(ctx *Context) string { return ctx.Event.(*testEvent).mkdir.filename },
   485  			Field:   field,
   486  		}, nil
   487  
   488  	case "mkdir.mode":
   489  
   490  		return &IntEvaluator{
   491  			EvalFnc: func(ctx *Context) int { return ctx.Event.(*testEvent).mkdir.mode },
   492  			Field:   field,
   493  		}, nil
   494  	}
   495  
   496  	return nil, &ErrFieldNotFound{Field: field}
   497  }
   498  
   499  func (e *testEvent) Init() {}
   500  
   501  func (e *testEvent) GetFieldValue(field Field) (interface{}, error) {
   502  	switch field {
   503  
   504  	case "network.ip":
   505  		return e.network.ip, nil
   506  
   507  	case "network.ips":
   508  		return e.network.ips, nil
   509  
   510  	case "network.cidr":
   511  		return e.network.cidr, nil
   512  
   513  	case "network.cidrs":
   514  		return e.network.cidrs, nil
   515  
   516  	case "process.name":
   517  
   518  		return e.process.name, nil
   519  
   520  	case "process.argv0":
   521  
   522  		return e.process.argv0, nil
   523  
   524  	case "process.uid":
   525  
   526  		return e.process.uid, nil
   527  
   528  	case "process.gid":
   529  
   530  		return e.process.gid, nil
   531  
   532  	case "process.pid":
   533  
   534  		return e.process.pid, nil
   535  
   536  	case "process.is_root":
   537  
   538  		return e.process.isRoot, nil
   539  
   540  	case "process.created_at":
   541  
   542  		return e.process.createdAt, nil
   543  
   544  	case "open.filename":
   545  
   546  		return e.open.filename, nil
   547  
   548  	case "open.flags":
   549  
   550  		return e.open.flags, nil
   551  
   552  	case "open.mode":
   553  
   554  		return e.open.mode, nil
   555  
   556  	case "open.opened_at":
   557  
   558  		return e.open.openedAt, nil
   559  
   560  	case "mkdir.filename":
   561  
   562  		return e.mkdir.filename, nil
   563  
   564  	case "mkdir.mode":
   565  
   566  		return e.mkdir.mode, nil
   567  
   568  	}
   569  
   570  	return nil, &ErrFieldNotFound{Field: field}
   571  }
   572  
   573  func (e *testEvent) GetFieldEventType(field Field) (string, error) {
   574  	switch field {
   575  
   576  	case "network.ip":
   577  
   578  		return "network", nil
   579  
   580  	case "network.ips":
   581  
   582  		return "network", nil
   583  
   584  	case "network.cidr":
   585  
   586  		return "network", nil
   587  
   588  	case "network.cidrs":
   589  
   590  		return "network", nil
   591  
   592  	case "process.name":
   593  
   594  		return "*", nil
   595  
   596  	case "process.argv0":
   597  
   598  		return "*", nil
   599  
   600  	case "process.uid":
   601  
   602  		return "*", nil
   603  
   604  	case "process.gid":
   605  
   606  		return "*", nil
   607  
   608  	case "process.pid":
   609  
   610  		return "*", nil
   611  
   612  	case "process.is_root":
   613  
   614  		return "*", nil
   615  
   616  	case "process.list.key":
   617  
   618  		return "*", nil
   619  
   620  	case "process.list.value":
   621  
   622  		return "*", nil
   623  
   624  	case "process.list.flag":
   625  
   626  		return "*", nil
   627  
   628  	case "process.array.key":
   629  
   630  		return "*", nil
   631  
   632  	case "process.array.value":
   633  
   634  		return "*", nil
   635  
   636  	case "process.array.flag":
   637  
   638  		return "*", nil
   639  
   640  	case "process.created_at":
   641  
   642  		return "*", nil
   643  
   644  	case "process.or_name":
   645  
   646  		return "*", nil
   647  
   648  	case "process.or_array.value":
   649  
   650  		return "*", nil
   651  
   652  	case "open.filename":
   653  
   654  		return "open", nil
   655  
   656  	case "open.flags":
   657  
   658  		return "open", nil
   659  
   660  	case "open.mode":
   661  
   662  		return "open", nil
   663  
   664  	case "open.opened_at":
   665  
   666  		return "open", nil
   667  
   668  	case "mkdir.filename":
   669  
   670  		return "mkdir", nil
   671  
   672  	case "mkdir.mode":
   673  
   674  		return "mkdir", nil
   675  
   676  	}
   677  
   678  	return "", &ErrFieldNotFound{Field: field}
   679  }
   680  
   681  func (e *testEvent) SetFieldValue(field Field, value interface{}) error {
   682  	switch field {
   683  
   684  	case "network.ip":
   685  
   686  		e.network.ip = value.(net.IPNet)
   687  		return nil
   688  
   689  	case "network.ips":
   690  
   691  		e.network.ips = value.([]net.IPNet)
   692  
   693  	case "network.cidr":
   694  
   695  		e.network.cidr = value.(net.IPNet)
   696  		return nil
   697  
   698  	case "network.cidrs":
   699  
   700  		e.network.cidrs = value.([]net.IPNet)
   701  		return nil
   702  
   703  	case "process.name":
   704  
   705  		e.process.name = value.(string)
   706  		return nil
   707  
   708  	case "process.argv0":
   709  
   710  		e.process.argv0 = value.(string)
   711  		return nil
   712  
   713  	case "process.uid":
   714  
   715  		e.process.uid = value.(int)
   716  		return nil
   717  
   718  	case "process.gid":
   719  
   720  		e.process.gid = value.(int)
   721  		return nil
   722  
   723  	case "process.pid":
   724  
   725  		e.process.pid = value.(int)
   726  		return nil
   727  
   728  	case "process.is_root":
   729  
   730  		e.process.isRoot = value.(bool)
   731  		return nil
   732  
   733  	case "process.created_at":
   734  
   735  		e.process.createdAt = value.(int64)
   736  		return nil
   737  
   738  	case "open.filename":
   739  
   740  		e.open.filename = value.(string)
   741  		return nil
   742  
   743  	case "open.flags":
   744  
   745  		e.open.flags = value.(int)
   746  		return nil
   747  
   748  	case "open.mode":
   749  
   750  		e.open.mode = value.(int)
   751  		return nil
   752  
   753  	case "open.opened_at":
   754  
   755  		e.open.openedAt = value.(int64)
   756  		return nil
   757  
   758  	case "mkdir.filename":
   759  
   760  		e.mkdir.filename = value.(string)
   761  		return nil
   762  
   763  	case "mkdir.mode":
   764  
   765  		e.mkdir.mode = value.(int)
   766  		return nil
   767  
   768  	}
   769  
   770  	return &ErrFieldNotFound{Field: field}
   771  }
   772  
   773  func (e *testEvent) GetFieldType(field Field) (reflect.Kind, error) {
   774  	switch field {
   775  
   776  	case "network.ip":
   777  
   778  		return reflect.Struct, nil
   779  
   780  	case "network.ips":
   781  
   782  		return reflect.Array, nil
   783  
   784  	case "network.cidr":
   785  
   786  		return reflect.Struct, nil
   787  
   788  	case "network.cidrs":
   789  
   790  		return reflect.Array, nil
   791  
   792  	case "process.name":
   793  
   794  		return reflect.String, nil
   795  
   796  	case "process.argv0":
   797  
   798  		return reflect.String, nil
   799  
   800  	case "process.uid":
   801  
   802  		return reflect.Int, nil
   803  
   804  	case "process.gid":
   805  
   806  		return reflect.Int, nil
   807  
   808  	case "process.pid":
   809  
   810  		return reflect.Int, nil
   811  
   812  	case "process.is_root":
   813  
   814  		return reflect.Bool, nil
   815  
   816  	case "process.list.key":
   817  		return reflect.Int, nil
   818  
   819  	case "process.list.value":
   820  		return reflect.Int, nil
   821  
   822  	case "process.list.flag":
   823  		return reflect.Bool, nil
   824  
   825  	case "process.array.key":
   826  		return reflect.Int, nil
   827  
   828  	case "process.array.value":
   829  		return reflect.String, nil
   830  
   831  	case "process.array.flag":
   832  		return reflect.Bool, nil
   833  
   834  	case "open.filename":
   835  
   836  		return reflect.String, nil
   837  
   838  	case "open.flags":
   839  
   840  		return reflect.Int, nil
   841  
   842  	case "open.mode":
   843  
   844  		return reflect.Int, nil
   845  
   846  	case "mkdir.filename":
   847  
   848  		return reflect.String, nil
   849  
   850  	case "mkdir.mode":
   851  
   852  		return reflect.Int, nil
   853  
   854  	}
   855  
   856  	return reflect.Invalid, &ErrFieldNotFound{Field: field}
   857  }
   858  
   859  var testConstants = map[string]interface{}{
   860  	// boolean
   861  	"true":  &BoolEvaluator{Value: true},
   862  	"false": &BoolEvaluator{Value: false},
   863  
   864  	// open flags
   865  	"O_RDONLY": &IntEvaluator{Value: syscall.O_RDONLY},
   866  	"O_WRONLY": &IntEvaluator{Value: syscall.O_WRONLY},
   867  	"O_RDWR":   &IntEvaluator{Value: syscall.O_RDWR},
   868  	"O_APPEND": &IntEvaluator{Value: syscall.O_APPEND},
   869  	"O_CREAT":  &IntEvaluator{Value: syscall.O_CREAT},
   870  	"O_EXCL":   &IntEvaluator{Value: syscall.O_EXCL},
   871  	"O_SYNC":   &IntEvaluator{Value: syscall.O_SYNC},
   872  	"O_TRUNC":  &IntEvaluator{Value: syscall.O_TRUNC},
   873  }