in rule/rule.go [614:786]
func addFilter(rule *ruleData, lhs, comparator, rhs string) error {
op, found := operatorsTable[comparator]
if !found {
return fmt.Errorf("invalid operator '%v'", comparator)
}
field, found := fieldsTable[lhs]
if !found {
return fmt.Errorf("invalid field '%v' on left", lhs)
}
// Only newer kernel versions support exclude for credential types. Older
// kernels only support exclude on the msgtype field.
// https://github.com/torvalds/linux/blob/v5.16/kernel/auditfilter.c#L1343
if rule.flags == excludeFilter {
switch field {
case pidField, uidField, gidField, auidField, msgTypeField,
subjectUserField, subjectRoleField, subjectTypeField,
subjectSensitivityField, subjectClearanceField,
exeField:
default:
return fmt.Errorf("field '%v' cannot be used the exclude flag", lhs)
}
}
switch field {
case uidField, euidField, suidField, fsuidField, auidField, objectUIDField:
// Convert RHS to number.
// Or attempt to lookup the name to get the number.
uid, err := getUID(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, uid)
case gidField, egidField, sgidField, fsgidField, objectGIDField:
gid, err := getGID(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, gid)
case exitField:
// Flag must be FilterExit.
if rule.flags != exitFilter {
return errors.New("exit filter can only be applied to syscall exit")
}
exitCode, err := getExitCode(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, uint32(exitCode))
case msgTypeField:
// Flag must be exclude or user.
if rule.flags != userFilter && rule.flags != excludeFilter {
return errors.New("msgtype filter can only be applied to the user or exclude lists")
}
msgType, err := getAuditMsgType(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, msgType)
case objectUserField, objectRoleField, objectTypeField, objectLevelLowField,
objectLevelHighField, pathField, dirField:
// Flag must be FilterExit.
if rule.flags != exitFilter {
return fmt.Errorf("%v filter can only be applied to the syscall exit", lhs)
}
fallthrough
case subjectUserField, subjectRoleField, subjectTypeField,
subjectSensitivityField, subjectClearanceField, keyField, exeField:
// Add string to strings.
if field == keyField && len(rhs) > maxKeyLength {
return fmt.Errorf("%v cannot be longer than %v", lhs, maxKeyLength)
} else if len(rhs) > pathMax {
return fmt.Errorf("%v cannot be longer than %v", lhs, pathMax)
}
rule.values = append(rule.values, uint32(len(rhs)))
rule.strings = append(rule.strings, rhs)
case archField:
// Arch should come before syscall.
// Arch only supports = and !=.
if op != equalOperator && op != notEqualOperator {
return fmt.Errorf("arch only supports the = and != operators")
}
// Or convert name to arch or validate given arch.
archName, arch, err := getArch(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, arch)
rule.arch = archName
case permField:
// Perm is only valid for exit.
if rule.flags != exitFilter {
return fmt.Errorf("perm filter can only be applied to the syscall exit")
}
// Perm is only valid for =.
if op != equalOperator {
return fmt.Errorf("perm only support the = operator")
}
perm, err := getPerm(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, perm)
case filetypeField:
// Filetype is only valid for exit.
if rule.flags != exitFilter {
return fmt.Errorf("filetype filter can only be applied to the syscall exit")
}
filetype, err := getFiletype(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, uint32(filetype))
case arg0Field, arg1Field, arg2Field, arg3Field:
// Convert RHS to a number.
arg, err := parseNum(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, arg)
// case SessionIDField:
case inodeField:
// Flag must be FilterExit.
if rule.flags != exitFilter {
return fmt.Errorf("inode filter can only be applied to the syscall exit")
}
// Comparator must be = or !=.
if op != equalOperator && op != notEqualOperator {
return fmt.Errorf("inode only supports the = and != operators")
}
// Convert RHS to number.
inode, err := parseNum(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, inode)
case saddrFamField:
// Convert RHS to number.
num, err := parseNum(rhs)
if err != nil {
return err
}
const (
// include/linux/socket.h
afInet = 2
afInet6 = 10
)
switch num {
case afInet, afInet6:
default:
return fmt.Errorf("saddr_fam must be 2 or 10: have %d", num)
}
rule.values = append(rule.values, num)
case devMajorField, devMinorField, successField, ppidField:
// Flag must be FilterExit.
if rule.flags != exitFilter {
return fmt.Errorf("%v filter can only be applied to the syscall exit", lhs)
}
fallthrough
default:
// Convert RHS to number.
num, err := parseNum(rhs)
if err != nil {
return err
}
rule.values = append(rule.values, num)
}
rule.fields = append(rule.fields, field)
rule.fieldFlags = append(rule.fieldFlags, op)
return nil
}