func addFilter()

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
}