libddwaf 1.22.0.0.2-aarch64-linux → 1.24.1.0.3-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -2
- data/README.md +124 -0
- data/lib/datadog/appsec/waf/context.rb +24 -38
- data/lib/datadog/appsec/waf/converter.rb +62 -69
- data/lib/datadog/appsec/waf/errors.rb +19 -0
- data/lib/datadog/appsec/waf/handle.rb +29 -77
- data/lib/datadog/appsec/waf/handle_builder.rb +91 -0
- data/lib/datadog/appsec/waf/lib_ddwaf.rb +90 -123
- data/lib/datadog/appsec/waf/version.rb +3 -3
- data/lib/datadog/appsec/waf.rb +9 -7
- data/lib/libddwaf.rb +1 -1
- data/libddwaf.gemspec +43 -0
- data/sig/datadog/appsec/waf/context.rbs +29 -0
- data/sig/datadog/appsec/waf/converter.rbs +11 -0
- data/sig/datadog/appsec/waf/errors.rbs +20 -0
- data/sig/datadog/appsec/waf/handle.rbs +21 -0
- data/sig/datadog/appsec/waf/handle_builder.rbs +23 -0
- data/sig/datadog/appsec/waf/lib_ddwaf.rbs +158 -0
- data/sig/datadog/appsec/waf/result.rbs +33 -0
- data/sig/datadog/appsec/waf/version.rbs +13 -0
- data/sig/datadog/appsec/waf.rbs +16 -0
- data/sig/libddwaf.rbs +0 -0
- data/vendor/libddwaf/{libddwaf-1.22.0-linux-aarch64 → libddwaf-1.24.1-linux-aarch64}/lib/libddwaf.so +0 -0
- data/vendor/rbs/gem/0/gem.rbs +7 -0
- data/vendor/rbs/jruby/0/jruby.rbs +3 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94f0f27a08d18b3e1d41ad75c96edd62c01d1d22c2d69e5d6c8f2f4f98bd8172
|
4
|
+
data.tar.gz: 732d929052278441c9b5d95cd7f9ad1a52917d4af267b5803d7e90e7760d5532
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43139856cbb68e3be10d6d35aa412783a9396f2038f48f39ec297f2db13046e0185fd2a24e581bf2cb2b0294d9e461a4d9416023208f4468fe58b7778d4c875e
|
7
|
+
data.tar.gz: d1f5f32f20ad0abbb544e66dec7e81f655fd1892eca8a3d89f0be771abbab85eacecc50c08fa590e754cbf2b3b48089798c6e28edf84b2b400d84b4c67879284
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
# Unreleased v1.23.0.0.0
|
2
|
+
|
3
|
+
## Added
|
4
|
+
|
5
|
+
- Add `HandleBuilder` class for managing libddwaf configuration and building WAF handles
|
6
|
+
- Add Error classes:
|
7
|
+
- `LibDDWAFError` for libddwaf errors
|
8
|
+
- `ConversionError` for conversion errors
|
9
|
+
- `InstanceFinalizedError` that is raised when attempting to run methods on finalized instances
|
10
|
+
|
11
|
+
## Changed
|
12
|
+
|
13
|
+
- Change `Handle` instantiation - now it should be done using `HandleBuilder#build_handle` method
|
14
|
+
- Change `Context` instantiation - now is should be done using `Handle#build_context` method
|
15
|
+
- Change configuration of Limits and obfuscation - it is now done when initializing `HandleBuilder`
|
16
|
+
- Change `Context#run` to return a `Result` object instead of an tuple with code and result
|
17
|
+
|
18
|
+
## Removed
|
19
|
+
|
20
|
+
- Remove `WAF::Handle#merge` method - the configuration is now handled by `HandleBuilder`
|
21
|
+
|
1
22
|
# 2025-02-20 v.1.18.0.0.1
|
2
23
|
|
3
24
|
- Fixed memory-leak in `Datadog::AppSec::WAF::Context#run` when non-empty ephemeral data passed
|
@@ -12,7 +33,6 @@
|
|
12
33
|
- Update to libddwaf 1.14.0
|
13
34
|
- Add support for `Float` and `Nil` scalar values when converting from ruby to WAF Object and vice versa.
|
14
35
|
|
15
|
-
|
16
36
|
# 2023-08-29 v.1.11.0.0.0
|
17
37
|
|
18
38
|
- Update to libddwaf 1.11.0
|
@@ -21,7 +41,6 @@
|
|
21
41
|
- Changed `Datadog::AppSec::WAF::Result#data` to `Datadog::AppSec::WAF::Result#events`. (Breaking change)
|
22
42
|
The schema of the events variable can be found [here](https://github.com/DataDog/libddwaf/blob/master/schema/events.json)
|
23
43
|
|
24
|
-
|
25
44
|
# 2023-08-28 v.1.10.0.0.0
|
26
45
|
|
27
46
|
- Update to libddwaf 1.10.0
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# libddwaf Ruby bindings
|
2
|
+
|
3
|
+
``libddwaf-rb`` is library exposing the libddwaf C++ library to Ruby, packaging it in a multiplatform gem.
|
4
|
+
|
5
|
+
For the libddwaf implementation, see this repository:
|
6
|
+
- [``libddwaf``: libddwaf](https://github.com/DataDog/libddwaf.git)
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
## Rake tasks
|
11
|
+
|
12
|
+
### Outline
|
13
|
+
|
14
|
+
A typical workflow is as follows:
|
15
|
+
|
16
|
+
```
|
17
|
+
rake fetch # fetch prebuilt libddwaf binaries tarball in vendor/libddwaf
|
18
|
+
rake extract # extract downloaded tarball in vendor/libddwaf
|
19
|
+
rake spec # run rspec
|
20
|
+
rake binary # build the gem
|
21
|
+
```
|
22
|
+
|
23
|
+
Note that each depends on the previous one, but `fetch` and `extract` are lazy, which proves useful to produce manual builds.
|
24
|
+
|
25
|
+
### Platform selection
|
26
|
+
|
27
|
+
By default the above will automatically use the local Ruby platform.
|
28
|
+
|
29
|
+
Since libddwaf binary builds are available upstream, it's possible to build gems for any platform on any other platform. To that end `fetch`, `extract`, and `binary` can take an argument to specify the Ruby platform for which these operations should apply:
|
30
|
+
|
31
|
+
```
|
32
|
+
rake fetch[x86_64-linux-musl]
|
33
|
+
rake extract[x86_64-linux-musl]
|
34
|
+
rake binary[x86_64-linux-musl]
|
35
|
+
```
|
36
|
+
|
37
|
+
Of course you can't force the platform for `rspec` since that requires running code; see the Docker section below for ways to achieve that.
|
38
|
+
|
39
|
+
Note that zsh gives special meaning to brackets, therefore you may need to quote the argument:
|
40
|
+
|
41
|
+
```
|
42
|
+
rake 'fetch[x86_64-linux-musl]'
|
43
|
+
```
|
44
|
+
|
45
|
+
Available platforms are:
|
46
|
+
|
47
|
+
```
|
48
|
+
x86_64-linux-musl # Alpine build: targets musl-based Linux
|
49
|
+
x86_64-linux-gnu # Debian build: targets glibc-based Linux
|
50
|
+
x86_64-linux # Portable build: targets multiple linux libc
|
51
|
+
x86_64-darwin # Darwin build: targets macOS
|
52
|
+
aarch64-linux-musl # Same as above, for ARMv8
|
53
|
+
aarch64-linux-gnu # Same as above, for ARMv8
|
54
|
+
aarch64-linux # Same as above, for ARMv8
|
55
|
+
arm64-darwin # Same as above, for Apple Silicon
|
56
|
+
java # JRuby build, universal
|
57
|
+
```
|
58
|
+
|
59
|
+
Note: since it is not (yet) possible to package gems for the `java` Ruby platform any other way than `java`, it has to package all the native architectures.
|
60
|
+
|
61
|
+
In addition, options can be specified for the portable build:
|
62
|
+
|
63
|
+
```
|
64
|
+
rake binary[x86_64-linux:gnu+musl] # Combined build: combine musl and glibc builds, selecting one at runtime
|
65
|
+
rake binary[x86_64-linux:llvm] # Hybrid build: linked to llvm static libs and built against a musl sysroot
|
66
|
+
```
|
67
|
+
|
68
|
+
See upstream libddwaf for details about the [hybrid portable build](https://github.com/DataDog/libddwaf/blob/master/docker/libddwaf/README.md).
|
69
|
+
|
70
|
+
## Testing with Docker
|
71
|
+
|
72
|
+
Unless using Docker for Mac, remember to enable foreign CPU emulation via QEMU:
|
73
|
+
|
74
|
+
```
|
75
|
+
# aarch64 on x86_64 hardware
|
76
|
+
docker run --privileged --rm tonistiigi/binfmt --install arm64
|
77
|
+
# x86_64 on aarch64 hardware
|
78
|
+
docker run --privileged --rm tonistiigi/binfmt --install amd64
|
79
|
+
```
|
80
|
+
|
81
|
+
Then you can substitute e.g `--platform linux/x86_64` with `--platform linux/aarch64` below.
|
82
|
+
|
83
|
+
### GNU (Debian)
|
84
|
+
|
85
|
+
```
|
86
|
+
# this is too old for aarch64
|
87
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.1 sh -c 'rm -fv Gemfile.lock && gem install bundler -v "~> 1.17" && bundle install && bundle exec rake spec'
|
88
|
+
# these are fine for aarch64
|
89
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.2 sh -c 'rm -fv Gemfile.lock && gem install bundler -v "~> 1.17" && bundle install && bundle exec rake spec'
|
90
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.3 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
91
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.4 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
92
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.5 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
93
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.6 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
94
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.7 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
95
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:3.0 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
96
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:3.1 sh -c 'rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
97
|
+
```
|
98
|
+
|
99
|
+
### musl (Alpine)
|
100
|
+
|
101
|
+
```
|
102
|
+
# these are too old for aarch64
|
103
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.1-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler -v "~> 1.17" && bundle install && bundle exec rake spec'
|
104
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.2-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler -v "~> 1.17" && bundle install && bundle exec rake spec'
|
105
|
+
# these are fine for aarch64
|
106
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.3-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
107
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.4-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
108
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.5-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
109
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.6-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
110
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:2.7-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
111
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:3.0-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
112
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:3.1-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
113
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" ruby:3.1-alpine sh -c 'apk update && apk add build-base git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
114
|
+
```
|
115
|
+
|
116
|
+
### JRuby
|
117
|
+
|
118
|
+
```
|
119
|
+
# these are too old for aarch64
|
120
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" jruby:9.2.8.0 sh -c 'apt-get update && apt-get install -y build-essential git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
121
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" jruby:9.3.0.0 sh -c 'apt-get update && apt-get install -y build-essential git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
122
|
+
# this is fine for aarch64
|
123
|
+
docker run --rm -it --platform linux/x86_64 -v "${PWD}":"${PWD}" -w "${PWD}" jruby:9.3.4.0 sh -c 'apt-get update && apt-get install -y build-essential git && rm -fv Gemfile.lock && gem install bundler:2.2.22 && bundle install && bundle exec rake spec'
|
124
|
+
```
|
@@ -14,20 +14,16 @@ module Datadog
|
|
14
14
|
ddwaf_err_invalid_argument: :err_invalid_argument
|
15
15
|
}.freeze
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
def initialize(handle)
|
20
|
-
handle_obj = handle.handle_obj
|
21
|
-
retain(handle)
|
22
|
-
|
23
|
-
@context_obj = LibDDWAF.ddwaf_context_init(handle_obj)
|
24
|
-
raise LibDDWAF::Error, 'Could not create context' if @context_obj.null?
|
25
|
-
|
26
|
-
validate!
|
17
|
+
def initialize(context_ptr)
|
18
|
+
@context_ptr = context_ptr
|
27
19
|
end
|
28
20
|
|
29
|
-
|
30
|
-
|
21
|
+
# Destroys the WAF context and sets the pointer to nil.
|
22
|
+
#
|
23
|
+
# The instance becomes unusable after this method is called.
|
24
|
+
def finalize!
|
25
|
+
context_ptr_to_destroy = @context_ptr
|
26
|
+
@context_ptr = nil
|
31
27
|
|
32
28
|
retained.each do |retained_obj|
|
33
29
|
next unless retained_obj.is_a?(LibDDWAF::Object)
|
@@ -36,11 +32,17 @@ module Datadog
|
|
36
32
|
end
|
37
33
|
|
38
34
|
retained.clear
|
39
|
-
LibDDWAF.ddwaf_context_destroy(
|
35
|
+
LibDDWAF.ddwaf_context_destroy(context_ptr_to_destroy)
|
40
36
|
end
|
41
37
|
|
38
|
+
# Runs the WAF context with the given persistent and ephemeral data.
|
39
|
+
#
|
40
|
+
# @raise [ConversionError] if the conversion of persistent or ephemeral data fails
|
41
|
+
# @raise [LibDDWAFError] if libddwaf could not create the result object
|
42
|
+
#
|
43
|
+
# @return [Result] the result of the WAF run
|
42
44
|
def run(persistent_data, ephemeral_data, timeout = LibDDWAF::DDWAF_RUN_TIMEOUT)
|
43
|
-
|
45
|
+
ensure_pointer_presence!
|
44
46
|
|
45
47
|
persistent_data_obj = Converter.ruby_to_object(
|
46
48
|
persistent_data,
|
@@ -50,7 +52,7 @@ module Datadog
|
|
50
52
|
coerce: false
|
51
53
|
)
|
52
54
|
if persistent_data_obj.null?
|
53
|
-
raise
|
55
|
+
raise ConversionError, "Could not convert persistent data: #{persistent_data.inspect}"
|
54
56
|
end
|
55
57
|
|
56
58
|
# retain C objects in memory for subsequent calls to run
|
@@ -64,15 +66,15 @@ module Datadog
|
|
64
66
|
coerce: false
|
65
67
|
)
|
66
68
|
if ephemeral_data_obj.null?
|
67
|
-
raise
|
69
|
+
raise ConversionError, "Could not convert ephemeral data: #{ephemeral_data.inspect}"
|
68
70
|
end
|
69
71
|
|
70
72
|
result_obj = LibDDWAF::Result.new
|
71
|
-
raise
|
73
|
+
raise LibDDWAFError, "Could not create result object" if result_obj.null?
|
72
74
|
|
73
|
-
code = LibDDWAF.ddwaf_run(@
|
75
|
+
code = LibDDWAF.ddwaf_run(@context_ptr, persistent_data_obj, ephemeral_data_obj, result_obj, timeout)
|
74
76
|
|
75
|
-
|
77
|
+
Result.new(
|
76
78
|
RESULT_CODE[code],
|
77
79
|
Converter.object_to_ruby(result_obj[:events]),
|
78
80
|
result_obj[:total_runtime],
|
@@ -80,8 +82,6 @@ module Datadog
|
|
80
82
|
Converter.object_to_ruby(result_obj[:actions]),
|
81
83
|
Converter.object_to_ruby(result_obj[:derivatives])
|
82
84
|
)
|
83
|
-
|
84
|
-
[RESULT_CODE[code], result]
|
85
85
|
ensure
|
86
86
|
LibDDWAF.ddwaf_result_free(result_obj) if result_obj
|
87
87
|
LibDDWAF.ddwaf_object_free(ephemeral_data_obj) if ephemeral_data_obj
|
@@ -89,24 +89,10 @@ module Datadog
|
|
89
89
|
|
90
90
|
private
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
def validate!
|
95
|
-
@valid = true
|
96
|
-
end
|
97
|
-
|
98
|
-
def invalidate!
|
99
|
-
@valid = false
|
100
|
-
end
|
101
|
-
|
102
|
-
def valid?
|
103
|
-
@valid
|
104
|
-
end
|
105
|
-
|
106
|
-
def valid!
|
107
|
-
return if valid?
|
92
|
+
def ensure_pointer_presence!
|
93
|
+
return if @context_ptr
|
108
94
|
|
109
|
-
raise
|
95
|
+
raise InstanceFinalizedError, "Cannot use WAF context after it has been finalized"
|
110
96
|
end
|
111
97
|
|
112
98
|
def retained
|
@@ -7,66 +7,67 @@ module Datadog
|
|
7
7
|
module Converter
|
8
8
|
module_function
|
9
9
|
|
10
|
-
#
|
10
|
+
# standard:disable Metrics/MethodLength,Metrics/CyclomaticComplexity
|
11
11
|
def ruby_to_object(val, max_container_size: nil, max_container_depth: nil, max_string_length: nil, coerce: true)
|
12
12
|
case val
|
13
13
|
when Array
|
14
14
|
obj = LibDDWAF::Object.new
|
15
15
|
res = LibDDWAF.ddwaf_object_array(obj)
|
16
|
-
if res.null?
|
17
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val}"
|
18
|
-
end
|
16
|
+
raise ConversionError, "Could not convert into object: #{val}" if res.null?
|
19
17
|
|
20
18
|
max_index = max_container_size - 1 if max_container_size
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
19
|
+
unless max_container_depth == 0
|
20
|
+
val.each.with_index do |e, i|
|
21
|
+
member = Converter.ruby_to_object(
|
22
|
+
e,
|
23
|
+
max_container_size: max_container_size,
|
24
|
+
max_container_depth: (max_container_depth - 1 if max_container_depth),
|
25
|
+
max_string_length: max_string_length,
|
26
|
+
coerce: coerce
|
27
|
+
)
|
28
|
+
e_res = LibDDWAF.ddwaf_object_array_add(obj, member)
|
29
|
+
raise ConversionError, "Could not add to array object: #{e.inspect}" unless e_res
|
30
|
+
|
31
|
+
break val if max_index && i >= max_index
|
32
|
+
end
|
33
|
+
end
|
32
34
|
|
33
35
|
obj
|
34
36
|
when Hash
|
35
37
|
obj = LibDDWAF::Object.new
|
36
38
|
res = LibDDWAF.ddwaf_object_map(obj)
|
37
|
-
if res.null?
|
38
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val}"
|
39
|
-
end
|
39
|
+
raise ConversionError, "Could not convert into object: #{val}" if res.null?
|
40
40
|
|
41
41
|
max_index = max_container_size - 1 if max_container_size
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
unless max_container_depth == 0
|
43
|
+
val.each.with_index do |e, i|
|
44
|
+
# for Steep, which doesn't handle |(k, v), i|
|
45
|
+
k = e[0]
|
46
|
+
v = e[1]
|
47
|
+
|
48
|
+
k = k.to_s[0, max_string_length] if max_string_length
|
49
|
+
member = Converter.ruby_to_object(
|
50
|
+
v,
|
51
|
+
max_container_size: max_container_size,
|
52
|
+
max_container_depth: (max_container_depth - 1 if max_container_depth),
|
53
|
+
max_string_length: max_string_length,
|
54
|
+
coerce: coerce
|
55
|
+
)
|
56
|
+
kv_res = LibDDWAF.ddwaf_object_map_addl(obj, k.to_s, k.to_s.bytesize, member)
|
57
|
+
raise ConversionError, "Could not add to map object: #{k.inspect} => #{v.inspect}" unless kv_res
|
58
|
+
|
59
|
+
break val if max_index && i >= max_index
|
55
60
|
end
|
56
|
-
|
57
|
-
break val if max_index && i >= max_index
|
58
|
-
end unless max_container_depth == 0
|
61
|
+
end
|
59
62
|
|
60
63
|
obj
|
61
64
|
when String
|
62
65
|
obj = LibDDWAF::Object.new
|
63
|
-
encoded_val = val.to_s.encode(
|
66
|
+
encoded_val = val.to_s.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
64
67
|
val = encoded_val[0, max_string_length] if max_string_length
|
65
68
|
str = val.to_s
|
66
69
|
res = LibDDWAF.ddwaf_object_stringl(obj, str, str.bytesize)
|
67
|
-
if res.null?
|
68
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
|
69
|
-
end
|
70
|
+
raise ConversionError, "Could not convert into object: #{val.inspect}" if res.null?
|
70
71
|
|
71
72
|
obj
|
72
73
|
when Symbol
|
@@ -74,67 +75,58 @@ module Datadog
|
|
74
75
|
val = val.to_s[0, max_string_length] if max_string_length
|
75
76
|
str = val.to_s
|
76
77
|
res = LibDDWAF.ddwaf_object_stringl(obj, str, str.bytesize)
|
77
|
-
if res.null?
|
78
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
|
79
|
-
end
|
78
|
+
raise ConversionError, "Could not convert into object: #{val.inspect}" if res.null?
|
80
79
|
|
81
80
|
obj
|
82
81
|
when Integer
|
83
82
|
obj = LibDDWAF::Object.new
|
84
83
|
res = if coerce
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
if res.null?
|
92
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
|
84
|
+
LibDDWAF.ddwaf_object_string(obj, val.to_s)
|
85
|
+
elsif val < 0
|
86
|
+
LibDDWAF.ddwaf_object_signed(obj, val)
|
87
|
+
else
|
88
|
+
LibDDWAF.ddwaf_object_unsigned(obj, val)
|
93
89
|
end
|
90
|
+
raise ConversionError, "Could not convert into object: #{val.inspect}" if res.null?
|
94
91
|
|
95
92
|
obj
|
96
93
|
when Float
|
97
94
|
obj = LibDDWAF::Object.new
|
98
95
|
res = if coerce
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
103
|
-
if res.null?
|
104
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
|
96
|
+
LibDDWAF.ddwaf_object_string(obj, val.to_s)
|
97
|
+
else
|
98
|
+
LibDDWAF.ddwaf_object_float(obj, val)
|
105
99
|
end
|
100
|
+
raise ConversionError, "Could not convert into object: #{val.inspect}" if res.null?
|
106
101
|
|
107
102
|
obj
|
108
103
|
when TrueClass, FalseClass
|
109
104
|
obj = LibDDWAF::Object.new
|
110
105
|
res = if coerce
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
if res.null?
|
116
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
|
106
|
+
LibDDWAF.ddwaf_object_string(obj, val.to_s)
|
107
|
+
else
|
108
|
+
LibDDWAF.ddwaf_object_bool(obj, val)
|
117
109
|
end
|
110
|
+
raise ConversionError, "Could not convert into object: #{val.inspect}" if res.null?
|
118
111
|
|
119
112
|
obj
|
120
113
|
when NilClass
|
121
114
|
obj = LibDDWAF::Object.new
|
122
115
|
res = if coerce
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
127
|
-
if res.null?
|
128
|
-
raise LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
|
116
|
+
LibDDWAF.ddwaf_object_string(obj, "")
|
117
|
+
else
|
118
|
+
LibDDWAF.ddwaf_object_null(obj)
|
129
119
|
end
|
120
|
+
raise ConversionError, "Could not convert into object: #{val.inspect}" if res.null?
|
130
121
|
|
131
122
|
obj
|
132
123
|
else
|
133
|
-
Converter.ruby_to_object(
|
124
|
+
Converter.ruby_to_object("")
|
134
125
|
end
|
135
126
|
end
|
136
|
-
#
|
127
|
+
# standard:enable Metrics/MethodLength,Metrics/CyclomaticComplexity
|
137
128
|
|
129
|
+
# standard:disable Metrics/MethodLength,Metrics/CyclomaticComplexity
|
138
130
|
def object_to_ruby(obj)
|
139
131
|
case obj[:type]
|
140
132
|
when :ddwaf_obj_invalid, :ddwaf_obj_null
|
@@ -170,6 +162,7 @@ module Datadog
|
|
170
162
|
end
|
171
163
|
end
|
172
164
|
end
|
165
|
+
# standard:enable Metrics/MethodLength,Metrics/CyclomaticComplexity
|
173
166
|
end
|
174
167
|
end
|
175
168
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Datadog
|
2
|
+
module AppSec
|
3
|
+
module WAF
|
4
|
+
Error = Class.new(StandardError)
|
5
|
+
InstanceFinalizedError = Class.new(Error)
|
6
|
+
ConversionError = Class.new(Error)
|
7
|
+
|
8
|
+
class LibDDWAFError < Error
|
9
|
+
attr_reader :diagnostics
|
10
|
+
|
11
|
+
def initialize(msg, diagnostics: nil)
|
12
|
+
@diagnostics = diagnostics
|
13
|
+
|
14
|
+
super(msg)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -6,101 +6,53 @@ module Datadog
|
|
6
6
|
# Ruby representation of the ddwaf_handle in libddwaf
|
7
7
|
# See https://github.com/DataDog/libddwaf/blob/10e3a1dfc7bc9bb8ab11a09a9f8b6b339eaf3271/BINDING_IMPL_NOTES.md?plain=1#L4-L19
|
8
8
|
class Handle
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
rule_obj = Converter.ruby_to_object(rule)
|
13
|
-
if rule_obj.null? || rule_obj[:type] == :ddwaf_object_invalid
|
14
|
-
raise LibDDWAF::Error, "Could not convert object #{rule.inspect}"
|
15
|
-
end
|
16
|
-
|
17
|
-
config_obj = Datadog::AppSec::WAF::LibDDWAF::Config.new
|
18
|
-
if config_obj.null?
|
19
|
-
raise LibDDWAF::Error, 'Could not create config struct'
|
20
|
-
end
|
21
|
-
|
22
|
-
config_obj[:limits][:max_container_size] = limits[:max_container_size] || LibDDWAF::DEFAULT_MAX_CONTAINER_SIZE
|
23
|
-
config_obj[:limits][:max_container_depth] = limits[:max_container_depth] || LibDDWAF::DEFAULT_MAX_CONTAINER_DEPTH
|
24
|
-
config_obj[:limits][:max_string_length] = limits[:max_string_length] || LibDDWAF::DEFAULT_MAX_STRING_LENGTH
|
25
|
-
config_obj[:obfuscator][:key_regex] = FFI::MemoryPointer.from_string(obfuscator[:key_regex]) if obfuscator[:key_regex]
|
26
|
-
config_obj[:obfuscator][:value_regex] = FFI::MemoryPointer.from_string(obfuscator[:value_regex]) if obfuscator[:value_regex]
|
27
|
-
config_obj[:free_fn] = LibDDWAF::ObjectNoFree
|
28
|
-
|
29
|
-
@config = config_obj
|
30
|
-
|
31
|
-
diagnostics_obj = LibDDWAF::Object.new
|
32
|
-
|
33
|
-
@handle_obj = LibDDWAF.ddwaf_init(rule_obj, config_obj, diagnostics_obj)
|
34
|
-
|
35
|
-
@diagnostics = Converter.object_to_ruby(diagnostics_obj)
|
9
|
+
def initialize(handle_ptr)
|
10
|
+
@handle_ptr = handle_ptr
|
11
|
+
end
|
36
12
|
|
37
|
-
|
38
|
-
|
39
|
-
|
13
|
+
# Destroys the WAF handle and sets the pointer to nil.
|
14
|
+
#
|
15
|
+
# The instance becomes unusable after this method is called.
|
16
|
+
def finalize!
|
17
|
+
handle_ptr_to_destroy = @handle_ptr
|
18
|
+
@handle_ptr = nil
|
40
19
|
|
41
|
-
|
42
|
-
ensure
|
43
|
-
LibDDWAF.ddwaf_object_free(diagnostics_obj) if diagnostics_obj
|
44
|
-
LibDDWAF.ddwaf_object_free(rule_obj) if rule_obj
|
20
|
+
LibDDWAF.ddwaf_destroy(handle_ptr_to_destroy)
|
45
21
|
end
|
46
22
|
|
47
|
-
|
48
|
-
|
23
|
+
# Builds a WAF context.
|
24
|
+
#
|
25
|
+
# @raise [LibDDWAFError] if libddwaf could not create the context.
|
26
|
+
# @return [Handle] the WAF handle
|
27
|
+
def build_context
|
28
|
+
ensure_pointer_presence!
|
29
|
+
|
30
|
+
context_obj = LibDDWAF.ddwaf_context_init(@handle_ptr)
|
31
|
+
raise LibDDWAFError, "Could not create context" if context_obj.null?
|
49
32
|
|
50
|
-
|
33
|
+
Context.new(context_obj)
|
51
34
|
end
|
52
35
|
|
53
|
-
|
54
|
-
|
36
|
+
# Returns the list of known addresses in the WAF handle.
|
37
|
+
#
|
38
|
+
# @return [Array<String>] the list of known addresses
|
39
|
+
def known_addresses
|
40
|
+
ensure_pointer_presence!
|
55
41
|
|
56
42
|
count = LibDDWAF::UInt32Ptr.new
|
57
|
-
list = LibDDWAF.ddwaf_known_addresses(
|
43
|
+
list = LibDDWAF.ddwaf_known_addresses(@handle_ptr, count)
|
58
44
|
|
59
45
|
return [] if count == 0 # list is null
|
60
46
|
|
61
47
|
list.get_array_of_string(0, count[:value])
|
62
48
|
end
|
63
49
|
|
64
|
-
def merge(data)
|
65
|
-
data_obj = Converter.ruby_to_object(data, coerce: false)
|
66
|
-
diagnostics_obj = LibDDWAF::Object.new
|
67
|
-
new_handle = LibDDWAF.ddwaf_update(handle_obj, data_obj, diagnostics_obj)
|
68
|
-
|
69
|
-
return if new_handle.null?
|
70
|
-
|
71
|
-
diagnostics = Converter.object_to_ruby(diagnostics_obj)
|
72
|
-
new_from_handle(new_handle, diagnostics, config)
|
73
|
-
ensure
|
74
|
-
LibDDWAF.ddwaf_object_free(data_obj) if data_obj
|
75
|
-
LibDDWAF.ddwaf_object_free(diagnostics_obj) if diagnostics_obj
|
76
|
-
end
|
77
|
-
|
78
50
|
private
|
79
51
|
|
80
|
-
def
|
81
|
-
|
82
|
-
obj.instance_variable_set(:@handle_obj, handle_object)
|
83
|
-
obj.instance_variable_set(:@diagnostics, diagnostics)
|
84
|
-
obj.instance_variable_set(:@config, config)
|
85
|
-
obj
|
86
|
-
end
|
87
|
-
|
88
|
-
def validate!
|
89
|
-
@valid = true
|
90
|
-
end
|
91
|
-
|
92
|
-
def invalidate!
|
93
|
-
@valid = false
|
94
|
-
end
|
95
|
-
|
96
|
-
def valid?
|
97
|
-
@valid
|
98
|
-
end
|
99
|
-
|
100
|
-
def valid!
|
101
|
-
return if valid?
|
52
|
+
def ensure_pointer_presence!
|
53
|
+
return if @handle_ptr
|
102
54
|
|
103
|
-
raise
|
55
|
+
raise InstanceFinalizedError, "Cannot use WAF handle after it has been finalized"
|
104
56
|
end
|
105
57
|
end
|
106
58
|
end
|