Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fuzzer/cmdi_detector/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
}

object_store store;
store.insert(std::move(root));
store.insert_and_apply(std::move(root));

ddwaf::timer deadline{2s};
condition_cache cache;
Expand Down
2 changes: 1 addition & 1 deletion fuzzer/lfi_detector/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
owned_object::make_string(resource, ddwaf::memory::get_default_resource()));

object_store store;
store.insert(std::move(root));
store.insert_and_apply(std::move(root));

ddwaf::timer deadline{2s};
condition_cache cache;
Expand Down
2 changes: 1 addition & 1 deletion fuzzer/shi_detector_array/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
}

object_store store;
store.insert(std::move(root));
store.insert_and_apply(std::move(root));

ddwaf::timer deadline{2s};
condition_cache cache;
Expand Down
2 changes: 1 addition & 1 deletion fuzzer/shi_detector_string/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
owned_object::make_string(resource, ddwaf::memory::get_default_resource()));

object_store store;
store.insert(std::move(root));
store.insert_and_apply(std::move(root));

ddwaf::timer deadline{2s};
condition_cache cache;
Expand Down
2 changes: 1 addition & 1 deletion fuzzer/sqli_detector/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
owned_object::make_string(resource, ddwaf::memory::get_default_resource()));

object_store store;
store.insert(std::move(root));
store.insert_and_apply(std::move(root));

ddwaf::timer deadline{2s};
condition_cache cache;
Expand Down
2 changes: 1 addition & 1 deletion fuzzer/ssrf_detector/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
owned_object::make_string(resource, ddwaf::memory::get_default_resource()));

object_store store;
store.insert(std::move(root));
store.insert_and_apply(std::move(root));

ddwaf::timer deadline{2s};
condition_cache cache;
Expand Down
179 changes: 179 additions & 0 deletions include/ddwaf.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ ddwaf_context ddwaf_context_init(const ddwaf_handle handle, ddwaf_allocator outp
* format: {tag, value}
* - keep: whether the data contained herein must override any
* transport sampling through the relevant mechanism.
* - evaluated: an unsigned integer indicating the number of input
* batches that were fully evaluated. For this single
* evaluation it is 1 when a non-empty batch was
* evaluated and 0 otherwise (e.g. an empty input or a
* timeout before evaluation completed). See
* ddwaf_context_multieval for the multi-batch case.
* This structure must be freed by the caller using the output
* allocator provided through ddwaf_context_init. The object will
* contain all specified keys when the value returned by
Expand Down Expand Up @@ -349,6 +355,90 @@ ddwaf_context ddwaf_context_init(const ddwaf_handle handle, ddwaf_allocator outp
DDWAF_RET_CODE ddwaf_context_eval(ddwaf_context context, ddwaf_object *data,
ddwaf_allocator alloc, ddwaf_object *result, uint64_t timeout);

/**
* Perform multiple matching operations on the provided data, evaluating each
* batch in sequence and returning a single combined result.
*
* This function operates identically to ddwaf_context_eval, with the
* distinction that data must be an array of maps. Each element is treated as
* a separate input batch and is evaluated in order. Addresses provided in
* earlier batches persist in the store and remain available when evaluating
* later batches, so a rule that requires multiple addresses can be satisfied
* by data spread across different batches within a single call. The result
* reflects all events, actions, and attributes accumulated across the entire
* sequence of batches.
*
* @param context WAF context to be used in this run, this will determine the
* ruleset which will be used and it will also ensure that
* parameters are taken into account across runs. (nonnull)
*
* @param data (nonnull) Array of input batches to evaluate. Each element must
* be a map of {string, <value>} where each key represents the relevant
* address associated to the value, which can be of an arbitrary type. The
* batches are evaluated in order. If the same address appears in multiple
* batches, the later value replaces the earlier one. Passing a non-array
* object will return DDWAF_ERR_INVALID_OBJECT.
* Ownership and lifetime semantics are identical to ddwaf_context_eval:
* the data is stored by the context and the provided allocator is used to
* free it once the context is destroyed.
*
* @param alloc (nullable) Allocator used to free the data provided. If NULL,
* the data will not be freed.
*
* @param result (nullable) Object map containing the following items:
* - events: an array of all events generated across all batches.
* - actions: a map of all actions generated across all batches
* in the format: "{action type: { <parameter map> }, ...}"
* - duration: an unsigned specifying the total runtime of the
* call in nanoseconds.
* - timeout: whether there has been a timeout during the call.
* - attributes: a map containing all derived objects in the
* format: {tag, value}
* - keep: whether the data contained herein must override any
* transport sampling through the relevant mechanism.
* - evaluated: an unsigned integer indicating the number of
* batches that were fully evaluated. In the normal
* case this equals the number of non-empty batches.
* On timeout or error occurring during batch I
* (0-based, counting only non-empty batches), this
* value equals I, which is also the index of the
* batch where the problem occurred. Empty batches are
* skipped and do not count towards this value.
* This structure must be freed by the caller using the output
* allocator provided through ddwaf_context_init. The object will
* contain all specified keys when the value returned by
* ddwaf_context_multieval is either DDWAF_OK or DDWAF_MATCH and
* will be empty otherwise.
* IMPORTANT: This object is not allocated with the allocator
* passed in this call. It uses the allocator given to
* ddwaf_context_init instead.
* @param timeout Maximum time budget in microseconds.
*
* @return Return code of the operation.
* @retval DDWAF_ERR_INVALID_ARGUMENT The context is invalid, the data will not
* be freed.
* @retval DDWAF_ERR_INVALID_OBJECT The data provided didn't match the desired
* structure or contained invalid objects, the
* data will be freed by this function.
* @retval DDWAF_ERR_INTERNAL There was an unexpected error and the operation did
* not succeed. The state of the WAF is undefined if
* this error is produced and the ownership of the
* data is unknown. The result structure will not be
* filled if this error occurs.
*
* Notes on addresses:
* - Within a single batch, addresses provided should be unique.
* If duplicate addresses are provided within the same batch, the latest one
* in the structure will be used for evaluation.
* - Addresses from earlier batches persist in the store and are accessible
* during evaluation of subsequent batches within the same call. If the same
* address appears in a later batch, the later value replaces the earlier one.
* - A rule that requires multiple addresses can be satisfied by data spread
* across different batches within a single call.
**/
DDWAF_RET_CODE ddwaf_context_multieval(ddwaf_context context, ddwaf_object *data,
ddwaf_allocator alloc, ddwaf_object *result, uint64_t timeout);

/**
* Performs the destruction of the context, freeing the data passed to it through
* ddwaf_context_eval using the provided allocator during evaluation.
Expand Down Expand Up @@ -395,6 +485,12 @@ ddwaf_subcontext ddwaf_subcontext_init(ddwaf_context context);
* format: {tag, value}
* - keep: whether the data contained herein must override any
* transport sampling through the relevant mechanism.
* - evaluated: an unsigned integer indicating the number of input
* batches that were fully evaluated. For this single
* evaluation it is 1 when a non-empty batch was
* evaluated and 0 otherwise (e.g. an empty input or a
* timeout before evaluation completed). See
* ddwaf_subcontext_multieval for the multi-batch case.
* This structure must be freed by the caller and will contain all
* specified keys when the value returned by ddwaf_subcontext_eval
* is either DDWAF_OK or DDWAF_MATCH and will be empty otherwise.
Expand Down Expand Up @@ -425,6 +521,89 @@ ddwaf_subcontext ddwaf_subcontext_init(ddwaf_context context);
DDWAF_RET_CODE ddwaf_subcontext_eval(ddwaf_subcontext subcontext, ddwaf_object *data,
ddwaf_allocator alloc, ddwaf_object *result, uint64_t timeout);

/**
* Perform multiple matching operations on the provided data, evaluating each
* batch in sequence and returning a single combined result.
*
* This function operates identically to ddwaf_subcontext_eval, with the
* distinction that data must be an array of maps. Each element is treated as
* a separate input batch and is evaluated in order. Addresses provided in
* earlier batches persist in the store and remain available when evaluating
* later batches, so a rule that requires multiple addresses can be satisfied
* by data spread across different batches within a single call. The result
* reflects all events, actions, and attributes accumulated across the entire
* sequence of batches.
*
* @param subcontext WAF subcontext to be used in this run, this will determine
* the ruleset which will be used and it will also ensure that
* parameters are taken into account across runs. (nonnull)
*
* @param data (nonnull) Array of input batches to evaluate. Each element must
* be a map of {string, <value>} where each key represents the relevant
* address associated to the value, which can be of an arbitrary type. The
* batches are evaluated in order. If the same address appears in multiple
* batches, the later value replaces the earlier one. Passing a non-array
* object will return DDWAF_ERR_INVALID_OBJECT.
* Ownership and lifetime semantics are identical to ddwaf_subcontext_eval:
* the data is stored by the subcontext and the provided allocator is used
* to free it once the subcontext is destroyed.
*
* @param alloc (nullable) Allocator used to free the data provided. If NULL,
* the data will not be freed.
*
* @param result (nullable) Object map containing the following items:
* - events: an array of all events generated across all batches.
* - actions: a map of all actions generated across all batches
* in the format: "{action type: { <parameter map> }, ...}"
* - duration: an unsigned specifying the total runtime of the
* call in nanoseconds.
* - timeout: whether there has been a timeout during the call.
* - attributes: a map containing all derived objects in the
* format: {tag, value}
* - keep: whether the data contained herein must override any
* transport sampling through the relevant mechanism.
* - evaluated: an unsigned integer indicating the number of
* batches that were fully evaluated. In the normal
* case this equals the number of non-empty batches.
* On timeout or error occurring during batch I
* (0-based, counting only non-empty batches), this
* value equals I, which is also the index of the
* batch where the problem occurred. Empty batches are
* skipped and do not count towards this value.
* This structure must be freed by the caller and will contain all
* specified keys when the value returned by
* ddwaf_subcontext_multieval is either DDWAF_OK or DDWAF_MATCH
* and will be empty otherwise.
* IMPORTANT: This object is not allocated with the allocator
* passed in this call. It uses the allocator given to
* ddwaf_context_init instead.
* @param timeout Maximum time budget in microseconds.
*
* @return Return code of the operation.
* @retval DDWAF_ERR_INVALID_ARGUMENT The subcontext is invalid, the data will
* not be freed.
* @retval DDWAF_ERR_INVALID_OBJECT The data provided didn't match the desired
* structure or contained invalid objects, the
* data will be freed by this function.
* @retval DDWAF_ERR_INTERNAL There was an unexpected error and the operation did
* not succeed. The state of the WAF is undefined if
* this error is produced and the ownership of the
* data is unknown. The result structure will not be
* filled if this error occurs.
*
* Notes on addresses:
* - Within a single batch, addresses provided should be unique.
* If duplicate addresses are provided within the same batch, the latest one
* in the structure will be used for evaluation.
* - Addresses from earlier batches persist in the store and are accessible
* during evaluation of subsequent batches within the same call. If the same
* address appears in a later batch, the later value replaces the earlier one.
* - A rule that requires multiple addresses can be satisfied by data spread
* across different batches within a single call.
**/
DDWAF_RET_CODE ddwaf_subcontext_multieval(ddwaf_subcontext subcontext, ddwaf_object *data,
ddwaf_allocator alloc, ddwaf_object *result, uint64_t timeout);

/**
* Performs the destruction of the subcontext, freeing the data passed to it through
* ddwaf_subcontext_eval using the used-defined allocator.
Expand Down
2 changes: 2 additions & 0 deletions libddwaf.def
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ EXPORTS
ddwaf_known_addresses
ddwaf_context_init
ddwaf_context_eval
ddwaf_context_multieval
ddwaf_context_destroy
ddwaf_subcontext_init
ddwaf_subcontext_eval
ddwaf_subcontext_multieval
ddwaf_subcontext_destroy
ddwaf_object_destroy
ddwaf_get_version
Expand Down
29 changes: 29 additions & 0 deletions smoketest/smoke.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,34 @@ int main() {
puts("result is valid");
ddwaf_object_destroy(&result, alloc);

// Exercise the multieval entrypoint. It takes an array of input batches
// (each a map of addresses); the actual data is irrelevant here, this just
// verifies the symbol is exported and the library loads correctly.
ddwaf_context multi_ctx = ddwaf_context_init(handle, alloc);
if (!multi_ctx) {
puts("multi_ctx is null");
return 1;
}

ddwaf_object multi_data;
ddwaf_object_set_array(&multi_data, 1, alloc);

ddwaf_object *batch = ddwaf_object_insert(&multi_data, alloc);
ddwaf_object_set_map(batch, 1, alloc);
ddwaf_object_set_string(
ddwaf_object_insert_key(batch, STRL("key"), alloc), STRL("Arachni"), alloc);

ddwaf_object multi_result = {0};
ddwaf_context_multieval(multi_ctx, &multi_data, alloc, &multi_result, (uint32_t)-1);

const ddwaf_object *multi_events =
ddwaf_object_find(&multi_result, "events", sizeof("events") - 1);
if (ddwaf_object_get_size(multi_events) == 0) {
puts("multieval result is empty");
return 1;
}
puts("multieval result is valid");
ddwaf_object_destroy(&multi_result, alloc);

return 0;
}
Loading
Loading