Skip to content

Commit f43af93

Browse files
chore(asm): handle any object passed to the waf as str (#5422)
1. Remove error for unknown objects passed to the WAF and quietly transform them to str 2. Ensure the string limit is also enforced on bytes passed to the WAF Those are minor improvements after a code review due to #5415 ## Checklist - [x] Change(s) are motivated and described in the PR description. - [x] Testing strategy is described if automated tests are not included in the PR. - [x] Risk is outlined (performance impact, potential for breakage, maintainability, etc). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] [Library release note guidelines](https://ddtrace.readthedocs.io/en/stable/contributing.html#Release-Note-Guidelines) are followed. - [x] Documentation is included (in-code, generated user docs, [public corp docs](https://github.com/DataDog/documentation/)). - [x] Author is aware of the performance implications of this PR as reported in the benchmarks PR comment. ## Reviewer Checklist - [x] Title is accurate. - [x] No unnecessary changes are introduced. - [x] Description motivates each change. - [x] Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes unless absolutely necessary. - [x] Testing strategy adequately addresses listed risk(s). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] Release note makes sense to a user of the library. - [x] Reviewer is aware of, and discussed the performance implications of this PR as reported in the benchmarks PR comment. --------- Co-authored-by: Federico Mon <[email protected]>
1 parent 17ee10c commit f43af93

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

ddtrace/appsec/ddwaf/ddwaf_types.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def __init__(
125125
elif isinstance(struct, unicode):
126126
ddwaf_object_string(self, struct.encode("UTF-8", errors="ignore")[: max_string_length - 1])
127127
elif isinstance(struct, bytes):
128-
ddwaf_object_string(self, struct)
128+
ddwaf_object_string(self, struct[: max_string_length - 1])
129129
elif isinstance(struct, float):
130130
res = unicode(struct).encode("UTF-8", errors="ignore")[: max_string_length - 1]
131131
ddwaf_object_string(self, res)
@@ -159,10 +159,13 @@ def __init__(
159159
)
160160
if obj.type: # discards invalid objects
161161
ddwaf_object_map_add(map_o, res_key, obj)
162+
elif struct is not None:
163+
struct = str(struct)
164+
if isinstance(struct, bytes): # Python 2
165+
ddwaf_object_string(self, struct[: max_string_length - 1])
166+
else: # Python 3
167+
ddwaf_object_string(self, struct.encode("UTF-8", errors="ignore")[: max_string_length - 1])
162168
else:
163-
if struct is not None:
164-
log.debug("DDWAF object init called with unknown data structure: %s", repr(type(struct)))
165-
166169
ddwaf_object_invalid(self)
167170

168171
@classmethod

tests/appsec/test_ddwaf_fuzz.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from hypothesis import given
44
from hypothesis import strategies as st
5+
import pytest
56

67
from ddtrace.appsec.ddwaf.ddwaf_types import ddwaf_object
78

@@ -25,6 +26,53 @@ def test_ddwaf_objects_wrapper(obj, kwargs):
2526
del obj
2627

2728

29+
class _AnyObject:
30+
cst = "1048A9B04F0EDC"
31+
32+
def __str__(self):
33+
return self.cst
34+
35+
36+
@pytest.mark.parametrize(
37+
"obj, res",
38+
[
39+
(32, "32"),
40+
(True, True),
41+
("test", "test"),
42+
(b"test", "test"),
43+
(1.0, "1.0"),
44+
([1, 2], ["1", "2"]),
45+
({"test": "truc"}, {"test": "truc"}),
46+
(None, None),
47+
(_AnyObject(), _AnyObject.cst),
48+
],
49+
)
50+
def test_small_objects(obj, res):
51+
dd_obj = ddwaf_object(obj)
52+
assert dd_obj.struct == res
53+
54+
55+
@pytest.mark.parametrize(
56+
"obj, res",
57+
[
58+
(324, "324"), # integers are formatted into strings by libddwaf and are not truncated
59+
(True, True),
60+
("toast", "to"),
61+
(b"toast", "to"),
62+
(1.034, "1."),
63+
([1, 2], ["1"]),
64+
({"toast": "touch", "tomato": "tommy"}, {"to": "to"}),
65+
(None, None),
66+
(_AnyObject(), _AnyObject.cst[:2]),
67+
([[[1, 2], 3], 4], [[]]),
68+
],
69+
)
70+
def test_limits(obj, res):
71+
# truncation of max_string_length takes the last C null byte into account
72+
dd_obj = ddwaf_object(obj, max_objects=1, max_depth=1, max_string_length=3)
73+
assert dd_obj.struct == res
74+
75+
2876
if __name__ == "__main__":
2977
import atheris
3078

0 commit comments

Comments
 (0)