Skip to content

Commit

Permalink
support for nil and invalid value in the encoding tree (#42)
Browse files Browse the repository at this point in the history
- [x] Replace nil errors by nil wafObject values
- [x] Replace invalid types by invalid wafObject values
- [x] Remove most errors from encoder functions
- [x] Keep map key even if the encoded value is nil or invalid
- [x] Keep struct field even if the encoded value is nil or invalid
- [x] Discard nil or invalid wafObject in arrays
- [x] Change current tests to match new implemntation
- [x] Write Run() tests to check if the waf supported these types
- [x] Refactor `EncoderTest` testsuite because it does not test was we
would like anymore

---------

Signed-off-by: Eliott Bouhana <[email protected]>
  • Loading branch information
eliottness authored Nov 13, 2023
1 parent f4a6958 commit 5296850
Show file tree
Hide file tree
Showing 8 changed files with 869 additions and 965 deletions.
24 changes: 6 additions & 18 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,27 +85,15 @@ func (context *Context) Run(addressData RunAddressData, timeout time.Duration) (
context.totalOverallRuntimeNs.Add(uint64(dt.Nanoseconds()))
}()

persistentEncoder := encoder{
stringMaxSize: wafMaxStringLength,
containerMaxSize: wafMaxContainerSize,
objectMaxDepth: wafMaxContainerDepth,
}
persistentData, err := persistentEncoder.Encode(addressData.Persistent)
if err != nil {
return res, err
}
// We can ignore the encoding error because it can only tell us that the user values are incompatible with the WAF
// which is not something we care about here.
persistentEncoder := newLimitedEncoder()
persistentData, _ := persistentEncoder.Encode(addressData.Persistent)

// The WAF releases ephemeral address data at the end of each run call, so we need not keep the Go values live beyond
// that in the same way we need for persistent data. We hence use a separate encoder.
ephemeralEncoder := encoder{
stringMaxSize: wafMaxStringLength,
containerMaxSize: wafMaxContainerSize,
objectMaxDepth: wafMaxContainerDepth,
}
ephemeralData, err := ephemeralEncoder.Encode(addressData.Ephemeral)
if err != nil {
return res, err
}
ephemeralEncoder := newLimitedEncoder()
ephemeralData, _ := ephemeralEncoder.Encode(addressData.Ephemeral)

// ddwaf_run cannot run concurrently and the next append write on the context state so we need a mutex
context.mutex.Lock()
Expand Down
11 changes: 11 additions & 0 deletions ctypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ type wafObject struct {
// packed (apart from breaking all tracers of course)
}

// isNil determines whether this WAF Object is nil or not.
func (w *wafObject) isNil() bool {
return w._type == wafNilType
}

// isArray determines whether this WAF Object is an array or not.
func (w *wafObject) isArray() bool {
return w._type == wafArrayType
Expand All @@ -68,6 +73,12 @@ func (w *wafObject) isMap() bool {
return w._type == wafMapType
}

// IsUnusable returns true if the wafObject has no impact on the WAF execution
// But we still need this kind of objects to forward map keys in case the value of the map is invalid
func (wo *wafObject) IsUnusable() bool {
return wo._type == wafInvalidType || wo._type == wafNilType
}

type wafConfig struct {
limits wafConfigLimits
obfuscator wafConfigObfuscator
Expand Down
18 changes: 15 additions & 3 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ func decodeErrors(obj *wafObject) (map[string][]string, error) {
wafErrors := map[string][]string{}
for i := uint64(0); i < obj.nbEntries; i++ {
objElem := castWithOffset[wafObject](obj.value, i)
if objElem._type != wafArrayType {
return nil, errInvalidObjectType
}

errorMessage := gostringSized(cast[byte](objElem.parameterName), objElem.parameterNameLength)
ruleIds, err := decodeStringArray(objElem)
Expand Down Expand Up @@ -141,6 +138,11 @@ func decodeDiagnosticAddresses(obj *wafObject) (res DiagnosticAddresses, err err
}

func decodeStringArray(obj *wafObject) ([]string, error) {
// We consider that nil is an empty array
if obj.isNil() {
return nil, nil
}

if !obj.isArray() {
return nil, errInvalidObjectType
}
Expand Down Expand Up @@ -178,12 +180,18 @@ func decodeObject(obj *wafObject) (any, error) {
return uintptrToNative[float64](obj.value), nil
case wafBoolType:
return uintptrToNative[bool](obj.value), nil
case wafNilType:
return nil, nil
default:
return nil, errUnsupportedValue
}
}

func decodeArray(obj *wafObject) ([]any, error) {
if obj.isNil() {
return nil, nil
}

if !obj.isArray() {
return nil, errInvalidObjectType
}
Expand All @@ -203,6 +211,10 @@ func decodeArray(obj *wafObject) ([]any, error) {
}

func decodeMap(obj *wafObject) (map[string]any, error) {
if obj.isNil() {
return nil, nil
}

if !obj.isMap() {
return nil, errInvalidObjectType
}
Expand Down
150 changes: 0 additions & 150 deletions decoder_test.go

This file was deleted.

Loading

0 comments on commit 5296850

Please sign in to comment.