libddwaf 1.3.0.2.0-x86_64-darwin → 1.5.1.0.0-x86_64-darwin

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd64af8282e39c80685231bc47387ed3c685dce9a927e05ce8dfadc995dcc7a0
4
- data.tar.gz: f3db575f44ce5bb8ecebf1732b77aa4ea5ae0350f053402f03f833a00280e869
3
+ metadata.gz: a35c1c6b48d5a2f652a9e726e8651ac2dcd82d91e875f859c511d7a096b1ef05
4
+ data.tar.gz: 7cbec901402fb39d79a84dcd01bf6b5739c5f11f8e6c3ae9d43ffc9c6d7310cd
5
5
  SHA512:
6
- metadata.gz: 3418e4f2bfb0b9c73cce9c7bc6fa8594fbdec009e01d59b210480484306982e7ae798c3ffdc25984cc1fc8dea4a50fc771fa7c924eae2af37719b4e029ad1372
7
- data.tar.gz: 7fcb30f7a97d1c31abb2c26746eb8b60f637cdcbcfb05fe6fcfbe3fcc1fff73336c3d6c429e2f2c579cd4d12ce01e3b30b16f18c8287c31f8fc0b6454e357898
6
+ metadata.gz: 4a3f7f7b47d3fd5de075d22cc749998611f79b688012494a979ef5435a6785bfd5dfc198e970f33224ae0ad8669b4f76b76c56fd3cdff1fc0f861c4e037b245c
7
+ data.tar.gz: 5f81bd74f5f95f74fcab502d38de48de621a45fe7f1da4c1854f61c6f9a57171288ede0ff61490963c692f3929de1c610b613d3dd4fe71882f12ae62d1950af9
data/CHANGELOG.md ADDED
@@ -0,0 +1,74 @@
1
+ # 2022-10-04 v1.5.1.0.0
2
+
3
+ - Update to libddwaf 1.5.1
4
+ - Add live rule data update API
5
+ - Add live rule toggle API
6
+ - Add libddwaf boolean type support
7
+ - Add Ruby to libddwaf object conversion limits
8
+ - Add Ruby to libddwaf object converter optional coercion of scalars to string
9
+ - Add static type checking via RBS+Steep
10
+ - Change version to return a string
11
+ - Change free function to be passed as config instead of context init argument
12
+ - Change result to include action list
13
+ - Change return code from action to status
14
+ - Change handle and context freeing model from GC-based to explicit
15
+ - Fix double-free upon finalization of retained C objects
16
+ - Fix context crash by retaining necessary C objects
17
+
18
+ # 2022-05-20 v1.3.0.2.0
19
+
20
+ - Fix multibyte string handling
21
+ - Support JRuby
22
+
23
+ # 2022-04-29 v1.3.0.1.0
24
+
25
+ Promotion of v1.3.0.1.0.beta1 to stable
26
+
27
+ # 2022-04-25 v1.3.0.1.0.beta1
28
+
29
+ - Add obfuscator configuration
30
+ - Add nested object limit configuration
31
+ - Add report ruleset information
32
+
33
+ # 2022-04-29 v1.3.0.0.0
34
+
35
+ - Promote v1.3.0.0.0.beta1 to stable
36
+
37
+ # 2022-04-20 v1.3.0.0.0.beta1
38
+
39
+ - Update to libddwaf 1.3.0
40
+
41
+ # 2022-03-18 v1.2.1.0.0.beta1
42
+
43
+ - Update to libddwaf 1.2.1
44
+ - Fix incorrect types for a few binding functions
45
+
46
+ # 2022-03-04 v1.0.14.2.1.beta1
47
+
48
+ - Fix incorrect return code
49
+ - Fix passing nil in libddwaf object containers
50
+
51
+ # 2022-02-07 v1.0.14.2.0.beta1
52
+
53
+ - Change Datadog::Security to Datadog::AppSec
54
+
55
+ # 2022-02-01 v1.0.14.1.0.beta2
56
+
57
+ - Add support for Ruby 3.1
58
+
59
+ # 2021-12-14 v1.0.14.1.0.beta1
60
+
61
+ - Fix sequential runs on a single context by retaining C input data objects
62
+
63
+ # 2021-11-24 v1.0.14.0.0.beta1
64
+
65
+ - Update to libddwaf 1.0.14
66
+
67
+ # 2021-11-24 v1.0.13.0.0.beta1
68
+
69
+ - Add ruby platform fallback for unsupported platforms
70
+ - Update to libddwaf 1.0.13
71
+
72
+ # 2021-10-13 v1.0.12.0.0.beta1
73
+
74
+ - Initial release
@@ -2,8 +2,8 @@ module Datadog
2
2
  module AppSec
3
3
  module WAF
4
4
  module VERSION
5
- BASE_STRING = '1.3.0'
6
- STRING = "#{BASE_STRING}.2.0"
5
+ BASE_STRING = '1.5.1'
6
+ STRING = "#{BASE_STRING}.0.0"
7
7
  MINIMUM_RUBY_VERSION = '2.1'
8
8
  end
9
9
  end
@@ -57,20 +57,35 @@ module Datadog
57
57
  Gem::Platform.local.cpu
58
58
  end
59
59
 
60
+ def self.source_dir
61
+ __dir__ || raise('__dir__ is nil: eval?')
62
+ end
63
+
60
64
  def self.vendor_dir
61
- File.join(__dir__, '../../../vendor')
65
+ File.join(source_dir, '../../../vendor')
62
66
  end
63
67
 
64
68
  def self.libddwaf_vendor_dir
65
69
  File.join(vendor_dir, 'libddwaf')
66
70
  end
67
71
 
68
- def self.shared_lib_triplet
69
- local_version ? "#{local_os}-#{local_version}-#{local_cpu}" : "#{local_os}-#{local_cpu}"
72
+ def self.shared_lib_triplet(version: local_version)
73
+ version ? "#{local_os}-#{version}-#{local_cpu}" : "#{local_os}-#{local_cpu}"
70
74
  end
71
75
 
72
76
  def self.libddwaf_dir
73
- File.join(libddwaf_vendor_dir, "libddwaf-#{Datadog::AppSec::WAF::VERSION::BASE_STRING}-#{shared_lib_triplet}")
77
+ default = File.join(libddwaf_vendor_dir,
78
+ "libddwaf-#{Datadog::AppSec::WAF::VERSION::BASE_STRING}-#{shared_lib_triplet}")
79
+ candidates = [
80
+ default
81
+ ]
82
+
83
+ if local_os == 'linux'
84
+ candidates << File.join(libddwaf_vendor_dir,
85
+ "libddwaf-#{Datadog::AppSec::WAF::VERSION::BASE_STRING}-#{shared_lib_triplet(version: nil)}")
86
+ end
87
+
88
+ candidates.find { |d| Dir.exist?(d) } || default
74
89
  end
75
90
 
76
91
  def self.shared_lib_extname
@@ -85,15 +100,7 @@ module Datadog
85
100
 
86
101
  # version
87
102
 
88
- class Version < ::FFI::Struct
89
- layout :major, :uint16,
90
- :minor, :uint16,
91
- :patch, :uint16
92
- end
93
-
94
- typedef Version.by_ref, :ddwaf_version
95
-
96
- attach_function :ddwaf_get_version, [:ddwaf_version], :void
103
+ attach_function :ddwaf_get_version, [], :string
97
104
 
98
105
  # ddwaf::object data structure
99
106
 
@@ -102,7 +109,9 @@ module Datadog
102
109
  :ddwaf_obj_unsigned, 1 << 1,
103
110
  :ddwaf_obj_string, 1 << 2,
104
111
  :ddwaf_obj_array, 1 << 3,
105
- :ddwaf_obj_map, 1 << 4
112
+ :ddwaf_obj_map, 1 << 4,
113
+ :ddwaf_obj_bool, 1 << 5
114
+ typedef DDWAF_OBJ_TYPE, :ddwaf_obj_type
106
115
 
107
116
  typedef :pointer, :charptr
108
117
  typedef :pointer, :charptrptr
@@ -129,7 +138,8 @@ module Datadog
129
138
  layout :stringValue, :charptr,
130
139
  :uintValue, :uint64,
131
140
  :intValue, :int64,
132
- :array, :pointer
141
+ :array, :pointer,
142
+ :boolean, :bool
133
143
  end
134
144
 
135
145
  class Object < ::FFI::Struct
@@ -137,7 +147,7 @@ module Datadog
137
147
  :parameterNameLength, :uint64,
138
148
  :valueUnion, ObjectValueUnion,
139
149
  :nbEntries, :uint64,
140
- :type, DDWAF_OBJ_TYPE
150
+ :type, :ddwaf_obj_type
141
151
  end
142
152
 
143
153
  typedef Object.by_ref, :ddwaf_object
@@ -152,6 +162,7 @@ module Datadog
152
162
  attach_function :ddwaf_object_signed, [:ddwaf_object, :int64], :ddwaf_object
153
163
  attach_function :ddwaf_object_unsigned_force, [:ddwaf_object, :uint64], :ddwaf_object
154
164
  attach_function :ddwaf_object_signed_force, [:ddwaf_object, :int64], :ddwaf_object
165
+ attach_function :ddwaf_object_bool, [:ddwaf_object, :bool], :ddwaf_object
155
166
 
156
167
  attach_function :ddwaf_object_array, [:ddwaf_object], :ddwaf_object
157
168
  attach_function :ddwaf_object_array_add, [:ddwaf_object, :ddwaf_object], :bool
@@ -182,6 +193,8 @@ module Datadog
182
193
  typedef :pointer, :ddwaf_handle
183
194
  typedef Object.by_ref, :ddwaf_rule
184
195
 
196
+ callback :ddwaf_object_free_fn, [:ddwaf_object], :void
197
+
185
198
  class Config < ::FFI::Struct
186
199
  class Limits < ::FFI::Struct
187
200
  layout :max_container_size, :uint32,
@@ -195,7 +208,8 @@ module Datadog
195
208
  end
196
209
 
197
210
  layout :limits, Limits,
198
- :obfuscator, Obfuscator
211
+ :obfuscator, Obfuscator,
212
+ :free_fn, :pointer #:ddwaf_object_free_fn
199
213
  end
200
214
 
201
215
  typedef Config.by_ref, :ddwaf_config
@@ -216,33 +230,43 @@ module Datadog
216
230
  attach_function :ddwaf_destroy, [:ddwaf_handle], :void
217
231
 
218
232
  attach_function :ddwaf_required_addresses, [:ddwaf_handle, UInt32Ptr], :charptrptr
233
+ attach_function :ddwaf_required_rule_data_ids, [:ddwaf_handle, UInt32Ptr], :charptrptr
234
+
235
+ # updating
236
+
237
+ DDWAF_RET_CODE = enum :ddwaf_err_internal, -3,
238
+ :ddwaf_err_invalid_object, -2,
239
+ :ddwaf_err_invalid_argument, -1,
240
+ :ddwaf_ok, 0,
241
+ :ddwaf_match, 1
242
+ typedef DDWAF_RET_CODE, :ddwaf_ret_code
243
+
244
+ attach_function :ddwaf_update_rule_data, [:ddwaf_handle, :ddwaf_object], :ddwaf_ret_code
245
+ attach_function :ddwaf_toggle_rules, [:ddwaf_handle, :ddwaf_object], :ddwaf_ret_code
219
246
 
220
247
  # running
221
248
 
222
249
  typedef :pointer, :ddwaf_context
223
250
 
224
- callback :ddwaf_object_free_fn, [:ddwaf_object], :void
225
-
226
- attach_function :ddwaf_context_init, [:ddwaf_handle, :ddwaf_object_free_fn], :ddwaf_context
251
+ attach_function :ddwaf_context_init, [:ddwaf_handle], :ddwaf_context
227
252
  attach_function :ddwaf_context_destroy, [:ddwaf_context], :void
228
253
 
229
- DDWAF_RET_CODE = enum :ddwaf_err_internal, -3,
230
- :ddwaf_err_invalid_object, -2,
231
- :ddwaf_err_invalid_argument, -1,
232
- :ddwaf_good, 0,
233
- :ddwaf_monitor, 1,
234
- :ddwaf_block, 2
254
+ class ResultActions < ::FFI::Struct
255
+ layout :array, :charptrptr,
256
+ :size, :uint32
257
+ end
235
258
 
236
259
  class Result < ::FFI::Struct
237
260
  layout :timeout, :bool,
238
261
  :data, :string,
262
+ :actions, ResultActions,
239
263
  :total_runtime, :uint64
240
264
  end
241
265
 
242
266
  typedef Result.by_ref, :ddwaf_result
243
267
  typedef :uint64, :timeout_us
244
268
 
245
- attach_function :ddwaf_run, [:ddwaf_context, :ddwaf_object, :ddwaf_result, :timeout_us], DDWAF_RET_CODE, blocking: true
269
+ attach_function :ddwaf_run, [:ddwaf_context, :ddwaf_object, :ddwaf_result, :timeout_us], :ddwaf_ret_code, blocking: true
246
270
  attach_function :ddwaf_result_free, [:ddwaf_result], :void
247
271
 
248
272
  # logging
@@ -253,20 +277,28 @@ module Datadog
253
277
  :ddwaf_log_warn,
254
278
  :ddwaf_log_error,
255
279
  :ddwaf_log_off
280
+ typedef DDWAF_LOG_LEVEL, :ddwaf_log_level
281
+
282
+ callback :ddwaf_log_cb, [:ddwaf_log_level, :string, :string, :uint, :charptr, :uint64], :void
283
+
284
+ attach_function :ddwaf_set_log_cb, [:ddwaf_log_cb, :ddwaf_log_level], :bool
285
+
286
+ DEFAULT_MAX_CONTAINER_SIZE = 0
287
+ DEFAULT_MAX_CONTAINER_DEPTH = 0
288
+ DEFAULT_MAX_STRING_LENGTH = 0
256
289
 
257
- callback :ddwaf_log_cb, [DDWAF_LOG_LEVEL, :string, :string, :uint, :charptr, :uint64], :void
290
+ DDWAF_MAX_CONTAINER_SIZE = 256
291
+ DDWAF_MAX_CONTAINER_DEPTH = 20
292
+ DDWAF_MAX_STRING_LENGTH = 4096
258
293
 
259
- attach_function :ddwaf_set_log_cb, [:ddwaf_log_cb, DDWAF_LOG_LEVEL], :bool
294
+ DDWAF_RUN_TIMEOUT = 5000
260
295
  end
261
296
 
262
297
  def self.version
263
- version = LibDDWAF::Version.new
264
- LibDDWAF.ddwaf_get_version(version.pointer)
265
-
266
- [version[:major], version[:minor], version[:patch]]
298
+ LibDDWAF.ddwaf_get_version
267
299
  end
268
300
 
269
- def self.ruby_to_object(val)
301
+ def self.ruby_to_object(val, max_container_size: nil, max_container_depth: nil, max_string_length: nil, coerce: true)
270
302
  case val
271
303
  when Array
272
304
  obj = LibDDWAF::Object.new
@@ -275,12 +307,20 @@ module Datadog
275
307
  fail LibDDWAF::Error, "Could not convert into object: #{val}"
276
308
  end
277
309
 
278
- val.each do |e|
279
- res = LibDDWAF.ddwaf_object_array_add(obj, ruby_to_object(e))
280
- unless res
281
- fail LibDDWAF::Error, "Could not add to map object: #{k.inspect} => #{v.inspect}"
310
+ max_index = max_container_size - 1 if max_container_size
311
+ val.each.with_index do |e, i|
312
+ member = ruby_to_object(e,
313
+ max_container_size: max_container_size,
314
+ max_container_depth: (max_container_depth - 1 if max_container_depth),
315
+ max_string_length: max_string_length,
316
+ coerce: coerce)
317
+ e_res = LibDDWAF.ddwaf_object_array_add(obj, member)
318
+ unless e_res
319
+ fail LibDDWAF::Error, "Could not add to array object: #{e.inspect}"
282
320
  end
283
- end
321
+
322
+ break val if max_index && i >= max_index
323
+ end unless max_container_depth == 0
284
324
 
285
325
  obj
286
326
  when Hash
@@ -290,36 +330,56 @@ module Datadog
290
330
  fail LibDDWAF::Error, "Could not convert into object: #{val}"
291
331
  end
292
332
 
293
- val.each do |k, v|
294
- res = LibDDWAF.ddwaf_object_map_addl(obj, k.to_s, k.to_s.bytesize, ruby_to_object(v))
295
- unless res
333
+ max_index = max_container_size - 1 if max_container_size
334
+ val.each.with_index do |e, i|
335
+ k, v = e[0], e[1] # for Steep, which doesn't handle |(k, v), i|
336
+
337
+ k = k.to_s[0, max_string_length] if max_string_length
338
+ member = ruby_to_object(v,
339
+ max_container_size: max_container_size,
340
+ max_container_depth: (max_container_depth - 1 if max_container_depth),
341
+ max_string_length: max_string_length,
342
+ coerce: coerce)
343
+ kv_res = LibDDWAF.ddwaf_object_map_addl(obj, k.to_s, k.to_s.bytesize, member)
344
+ unless kv_res
296
345
  fail LibDDWAF::Error, "Could not add to map object: #{k.inspect} => #{v.inspect}"
297
346
  end
298
- end
347
+
348
+ break val if max_index && i >= max_index
349
+ end unless max_container_depth == 0
299
350
 
300
351
  obj
301
352
  when String
302
353
  obj = LibDDWAF::Object.new
303
- res = LibDDWAF.ddwaf_object_stringl(obj, val, val.bytesize)
354
+ val = val.to_s[0, max_string_length] if max_string_length
355
+ str = val.to_s
356
+ res = LibDDWAF.ddwaf_object_stringl(obj, str, str.bytesize)
304
357
  if res.null?
305
- fail LibDDWAF::Error, "Could not convert into object: #{val}"
358
+ fail LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
306
359
  end
307
360
 
308
361
  obj
309
362
  when Symbol
310
363
  obj = LibDDWAF::Object.new
364
+ val = val.to_s[0, max_string_length] if max_string_length
311
365
  str = val.to_s
312
366
  res = LibDDWAF.ddwaf_object_stringl(obj, str, str.bytesize)
313
367
  if res.null?
314
- fail LibDDWAF::Error, "Could not convert into object: #{val}"
368
+ fail LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
315
369
  end
316
370
 
317
371
  obj
318
372
  when Integer
319
373
  obj = LibDDWAF::Object.new
320
- res = LibDDWAF.ddwaf_object_string(obj, val.to_s)
374
+ res = if coerce
375
+ LibDDWAF.ddwaf_object_string(obj, val.to_s)
376
+ elsif val < 0
377
+ LibDDWAF.ddwaf_object_signed_force(obj, val)
378
+ else
379
+ LibDDWAF.ddwaf_object_unsigned_force(obj, val)
380
+ end
321
381
  if res.null?
322
- fail LibDDWAF::Error, "Could not convert into object: #{val}"
382
+ fail LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
323
383
  end
324
384
 
325
385
  obj
@@ -327,15 +387,19 @@ module Datadog
327
387
  obj = LibDDWAF::Object.new
328
388
  res = LibDDWAF.ddwaf_object_string(obj, val.to_s)
329
389
  if res.null?
330
- fail LibDDWAF::Error, "Could not convert into object: #{val}"
390
+ fail LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
331
391
  end
332
392
 
333
393
  obj
334
394
  when TrueClass, FalseClass
335
395
  obj = LibDDWAF::Object.new
336
- res = LibDDWAF.ddwaf_object_string(obj, val.to_s)
396
+ res = if coerce
397
+ LibDDWAF.ddwaf_object_string(obj, val.to_s)
398
+ else
399
+ LibDDWAF.ddwaf_object_bool(obj, val)
400
+ end
337
401
  if res.null?
338
- fail LibDDWAF::Error, "Could not convert into object: #{val}"
402
+ fail LibDDWAF::Error, "Could not convert into object: #{val.inspect}"
339
403
  end
340
404
 
341
405
  obj
@@ -348,6 +412,8 @@ module Datadog
348
412
  case obj[:type]
349
413
  when :ddwaf_obj_invalid
350
414
  nil
415
+ when :ddwaf_obj_bool
416
+ obj[:valueUnion][:boolean]
351
417
  when :ddwaf_obj_string
352
418
  obj[:valueUnion][:stringValue].read_bytes(obj[:nbEntries])
353
419
  when :ddwaf_obj_signed
@@ -372,21 +438,47 @@ module Datadog
372
438
  end
373
439
  end
374
440
 
441
+ def self.log_callback(level, func, file, line, message, len)
442
+ return if logger.nil?
443
+
444
+ logger.debug do
445
+ {
446
+ level: level,
447
+ func: func,
448
+ file: file,
449
+ line: line,
450
+ message: message.read_bytes(len)
451
+ }.inspect
452
+ end
453
+ end
454
+
455
+ def self.logger
456
+ @logger
457
+ end
458
+
375
459
  def self.logger=(logger)
376
- @log_cb = proc do |level, func, file, line, message, len|
377
- logger.debug { { level: level, func: func, file: file, line: line, message: message.read_bytes(len) }.inspect }
460
+ unless @log_callback
461
+ log_callback = method(:log_callback)
462
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_set_log_cb(log_callback, :ddwaf_log_trace)
463
+
464
+ # retain logging proc if set properly
465
+ @log_callback = log_callback
378
466
  end
379
467
 
380
- Datadog::AppSec::WAF::LibDDWAF.ddwaf_set_log_cb(@log_cb, :ddwaf_log_trace)
468
+ @logger = logger
381
469
  end
382
470
 
471
+ RESULT_CODE = {
472
+ ddwaf_err_internal: :err_internal,
473
+ ddwaf_err_invalid_object: :err_invalid_object,
474
+ ddwaf_err_invalid_argument: :err_invalid_argument,
475
+ ddwaf_ok: :ok,
476
+ ddwaf_match: :match,
477
+ }
478
+
383
479
  class Handle
384
480
  attr_reader :handle_obj
385
481
 
386
- DEFAULT_MAX_CONTAINER_SIZE = 0
387
- DEFAULT_MAX_CONTAINER_DEPTH = 0
388
- DEFAULT_MAX_STRING_LENGTH = 0
389
-
390
482
  attr_reader :ruleset_info
391
483
 
392
484
  def initialize(rule, limits: {}, obfuscator: {})
@@ -399,12 +491,14 @@ module Datadog
399
491
  if config_obj.null?
400
492
  fail LibDDWAF::Error, 'Could not create config struct'
401
493
  end
494
+ retain(config_obj)
402
495
 
403
- config_obj[:limits][:max_container_size] = limits[:max_container_size] || DEFAULT_MAX_CONTAINER_SIZE
404
- config_obj[:limits][:max_container_depth] = limits[:max_container_depth] || DEFAULT_MAX_CONTAINER_DEPTH
405
- config_obj[:limits][:max_string_length] = limits[:max_string_length] || DEFAULT_MAX_STRING_LENGTH
496
+ config_obj[:limits][:max_container_size] = limits[:max_container_size] || LibDDWAF::DEFAULT_MAX_CONTAINER_SIZE
497
+ config_obj[:limits][:max_container_depth] = limits[:max_container_depth] || LibDDWAF::DEFAULT_MAX_CONTAINER_DEPTH
498
+ config_obj[:limits][:max_string_length] = limits[:max_string_length] || LibDDWAF::DEFAULT_MAX_STRING_LENGTH
406
499
  config_obj[:obfuscator][:key_regex] = FFI::MemoryPointer.from_string(obfuscator[:key_regex]) if obfuscator[:key_regex]
407
500
  config_obj[:obfuscator][:value_regex] = FFI::MemoryPointer.from_string(obfuscator[:value_regex]) if obfuscator[:value_regex]
501
+ config_obj[:free_fn] = Datadog::AppSec::WAF::LibDDWAF::ObjectNoFree
408
502
 
409
503
  ruleset_info = LibDDWAF::RuleSetInfo.new
410
504
 
@@ -421,19 +515,21 @@ module Datadog
421
515
  fail LibDDWAF::Error.new('Could not create handle', ruleset_info: @ruleset_info)
422
516
  end
423
517
 
424
- ObjectSpace.define_finalizer(self, Handle.finalizer(handle_obj))
518
+ validate!
425
519
  ensure
426
520
  Datadog::AppSec::WAF::LibDDWAF.ddwaf_ruleset_info_free(ruleset_info) if ruleset_info
427
521
  Datadog::AppSec::WAF::LibDDWAF.ddwaf_object_free(rule_obj) if rule_obj
428
522
  end
429
523
 
430
- def self.finalizer(handle_obj)
431
- proc do |object_id|
432
- Datadog::AppSec::WAF::LibDDWAF.ddwaf_destroy(handle_obj)
433
- end
524
+ def finalize
525
+ invalidate!
526
+
527
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_destroy(handle_obj)
434
528
  end
435
529
 
436
530
  def required_addresses
531
+ valid!
532
+
437
533
  count = Datadog::AppSec::WAF::LibDDWAF::UInt32Ptr.new
438
534
  list = Datadog::AppSec::WAF::LibDDWAF.ddwaf_required_addresses(handle_obj, count)
439
535
 
@@ -441,48 +537,102 @@ module Datadog
441
537
 
442
538
  list.get_array_of_string(0, count[:value])
443
539
  end
540
+
541
+ def update_rule_data(data)
542
+ res = Datadog::AppSec::WAF::LibDDWAF.ddwaf_update_rule_data(@handle_obj, Datadog::AppSec::WAF.ruby_to_object(data, coerce: false))
543
+
544
+ RESULT_CODE[res]
545
+ end
546
+
547
+ def toggle_rules(map)
548
+ res = Datadog::AppSec::WAF::LibDDWAF.ddwaf_toggle_rules(@handle_obj, Datadog::AppSec::WAF.ruby_to_object(map, coerce: false))
549
+
550
+ RESULT_CODE[res]
551
+ end
552
+
553
+ private
554
+
555
+ def validate!
556
+ @valid = true
557
+ end
558
+
559
+ def invalidate!
560
+ @valid = false
561
+ end
562
+
563
+ def valid?
564
+ @valid
565
+ end
566
+
567
+ def valid!
568
+ return if valid?
569
+
570
+ fail LibDDWAF::Error, "Attempt to use an invalid instance: #{inspect}"
571
+ end
572
+
573
+ def retained
574
+ @retained ||= []
575
+ end
576
+
577
+ def retain(object)
578
+ retained << object
579
+ end
580
+
581
+ def release(object)
582
+ retained.delete(object)
583
+ end
444
584
  end
445
585
 
446
- Result = Struct.new(:action, :data, :total_runtime, :timeout)
586
+ class Result
587
+ attr_reader :status, :data, :total_runtime, :timeout, :actions
588
+
589
+ def initialize(status, data, total_runtime, timeout, actions)
590
+ @status = status
591
+ @data = data
592
+ @total_runtime = total_runtime
593
+ @timeout = timeout
594
+ @actions = actions
595
+ end
596
+ end
447
597
 
448
598
  class Context
449
599
  attr_reader :context_obj
450
600
 
451
601
  def initialize(handle)
452
602
  handle_obj = handle.handle_obj
453
- free_func = Datadog::AppSec::WAF::LibDDWAF::ObjectNoFree
603
+ retain(handle)
454
604
 
455
- @context_obj = Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_init(handle_obj, free_func)
605
+ @context_obj = Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_init(handle_obj)
456
606
  if @context_obj.null?
457
607
  fail LibDDWAF::Error, 'Could not create context'
458
608
  end
459
609
 
460
- @input_objs = []
461
-
462
- ObjectSpace.define_finalizer(self, Context.finalizer(context_obj, @input_objs))
610
+ validate!
463
611
  end
464
612
 
465
- def self.finalizer(context_obj, input_objs)
466
- proc do |object_id|
467
- input_objs.each do |input_obj|
468
- Datadog::AppSec::WAF::LibDDWAF.ddwaf_object_free(input_obj)
469
- end
470
- Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_destroy(context_obj)
613
+ def finalize
614
+ invalidate!
615
+
616
+ retained.each do |retained_obj|
617
+ next unless retained_obj.is_a?(Datadog::AppSec::WAF::LibDDWAF::Object)
618
+
619
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_object_free(retained_obj)
471
620
  end
621
+
622
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_destroy(context_obj)
472
623
  end
473
624
 
474
- DEFAULT_TIMEOUT_US = 10_0000
475
- ACTION_MAP_OUT = {
476
- ddwaf_err_internal: :err_internal,
477
- ddwaf_err_invalid_object: :err_invalid_object,
478
- ddwaf_err_invalid_argument: :err_invalid_argument,
479
- ddwaf_good: :good,
480
- ddwaf_monitor: :monitor,
481
- ddwaf_block: :block,
482
- }
625
+ def run(input, timeout = LibDDWAF::DDWAF_RUN_TIMEOUT)
626
+ valid!
627
+
628
+ max_container_size = LibDDWAF::DDWAF_MAX_CONTAINER_SIZE
629
+ max_container_depth = LibDDWAF::DDWAF_MAX_CONTAINER_DEPTH
630
+ max_string_length = LibDDWAF::DDWAF_MAX_CONTAINER_SIZE
483
631
 
484
- def run(input, timeout = DEFAULT_TIMEOUT_US)
485
- input_obj = Datadog::AppSec::WAF.ruby_to_object(input)
632
+ input_obj = Datadog::AppSec::WAF.ruby_to_object(input,
633
+ max_container_size: max_container_size,
634
+ max_container_depth: max_container_depth,
635
+ max_string_length: max_string_length)
486
636
  if input_obj.null?
487
637
  fail LibDDWAF::Error, "Could not convert input: #{input.inspect}"
488
638
  end
@@ -493,21 +643,60 @@ module Datadog
493
643
  end
494
644
 
495
645
  # retain C objects in memory for subsequent calls to run
496
- @input_objs << input_obj
646
+ retain(input_obj)
497
647
 
498
648
  code = Datadog::AppSec::WAF::LibDDWAF.ddwaf_run(@context_obj, input_obj, result_obj, timeout)
499
649
 
650
+ actions = if result_obj[:actions][:size] > 0
651
+ result_obj[:actions][:array].get_array_of_string(0, result_obj[:actions][:size])
652
+ else
653
+ []
654
+ end
655
+
500
656
  result = Result.new(
501
- ACTION_MAP_OUT[code],
657
+ RESULT_CODE[code],
502
658
  (JSON.parse(result_obj[:data]) if result_obj[:data] != nil),
503
659
  result_obj[:total_runtime],
504
660
  result_obj[:timeout],
661
+ actions,
505
662
  )
506
663
 
507
- [ACTION_MAP_OUT[code], result]
664
+ [RESULT_CODE[code], result]
508
665
  ensure
509
666
  Datadog::AppSec::WAF::LibDDWAF.ddwaf_result_free(result_obj) if result_obj
510
667
  end
668
+
669
+ private
670
+
671
+ def validate!
672
+ @valid = true
673
+ end
674
+
675
+ def invalidate!
676
+ @valid = false
677
+ end
678
+
679
+ def valid?
680
+ @valid
681
+ end
682
+
683
+ def valid!
684
+ return if valid?
685
+
686
+ fail LibDDWAF::Error, "Attempt to use an invalid instance: #{inspect}"
687
+ end
688
+
689
+ def retained
690
+ @retained ||= []
691
+ end
692
+
693
+ def retain(object)
694
+ retained << object
695
+ end
696
+
697
+ def release(object)
698
+ retained.delete(object)
699
+ end
511
700
  end
512
701
  end
513
702
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libddwaf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0.2.0
4
+ version: 1.5.1.0.0
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 1980-01-01 00:00:00.000000000 Z
11
+ date: 2022-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -33,6 +33,7 @@ executables: []
33
33
  extensions: []
34
34
  extra_rdoc_files: []
35
35
  files:
36
+ - CHANGELOG.md
36
37
  - LICENSE
37
38
  - LICENSE-3rdparty.csv
38
39
  - LICENSE.Apache
@@ -41,8 +42,8 @@ files:
41
42
  - lib/datadog/appsec/waf.rb
42
43
  - lib/datadog/appsec/waf/version.rb
43
44
  - lib/libddwaf.rb
44
- - vendor/libddwaf/libddwaf-1.3.0-darwin-x86_64/lib/libddwaf.dylib
45
- homepage: https://github.com/DataDog/libddwaf
45
+ - vendor/libddwaf/libddwaf-1.5.1-darwin-x86_64/lib/libddwaf.dylib
46
+ homepage: https://github.com/DataDog/libddwaf-rb
46
47
  licenses:
47
48
  - BSD-3-Clause
48
49
  metadata:
@@ -62,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
63
  - !ruby/object:Gem::Version
63
64
  version: 2.0.0
64
65
  requirements: []
65
- rubygems_version: 3.2.26
66
+ rubygems_version: 3.3.22
66
67
  signing_key:
67
68
  specification_version: 4
68
69
  summary: Datadog WAF