libddwaf 1.3.0.2.0-x86_64-darwin → 1.5.1.0.1-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: e0a596d9f94ee5aed556adfa96b6e005e5e49754c4bbcfb9b58becc61e97fd41
4
+ data.tar.gz: 7c4d3f254272fcca470bb6d6d57c4b08ee9a7af6dc0a3e8a691d73399ed2eab1
5
5
  SHA512:
6
- metadata.gz: 3418e4f2bfb0b9c73cce9c7bc6fa8594fbdec009e01d59b210480484306982e7ae798c3ffdc25984cc1fc8dea4a50fc771fa7c924eae2af37719b4e029ad1372
7
- data.tar.gz: 7fcb30f7a97d1c31abb2c26746eb8b60f637cdcbcfb05fe6fcfbe3fcc1fff73336c3d6c429e2f2c579cd4d12ce01e3b30b16f18c8287c31f8fc0b6454e357898
6
+ metadata.gz: c39d0828579f5d75ccdf6bd73e986fde409abdb0aa82d47fe8a667efa79e316c109fd65691471718fc0e2dc03ef6f6aea5b36b4518cdd9cd8149760372f86f60
7
+ data.tar.gz: '085b54fe799d706da464a5b4488d25c2b2e3529d1db235d1900a5b0e0567f0f92c12246d51350b1a6e97dfcc83a4a655794c2bfc498295535179483d54be6d65'
data/CHANGELOG.md ADDED
@@ -0,0 +1,79 @@
1
+ # 2023-02-01 v1.5.1.0.1
2
+
3
+ - Fix incorrect size in input string limit
4
+ - Fix object freeing on `update_rule_data` and `toggle_rules`
5
+
6
+ # 2022-10-04 v1.5.1.0.0
7
+
8
+ - Update to libddwaf 1.5.1
9
+ - Add live rule data update API
10
+ - Add live rule toggle API
11
+ - Add libddwaf boolean type support
12
+ - Add Ruby to libddwaf object conversion limits
13
+ - Add Ruby to libddwaf object converter optional coercion of scalars to string
14
+ - Add static type checking via RBS+Steep
15
+ - Change version to return a string
16
+ - Change free function to be passed as config instead of context init argument
17
+ - Change result to include action list
18
+ - Change return code from action to status
19
+ - Change handle and context freeing model from GC-based to explicit
20
+ - Fix double-free upon finalization of retained C objects
21
+ - Fix context crash by retaining necessary C objects
22
+
23
+ # 2022-05-20 v1.3.0.2.0
24
+
25
+ - Fix multibyte string handling
26
+ - Support JRuby
27
+
28
+ # 2022-04-29 v1.3.0.1.0
29
+
30
+ Promotion of v1.3.0.1.0.beta1 to stable
31
+
32
+ # 2022-04-25 v1.3.0.1.0.beta1
33
+
34
+ - Add obfuscator configuration
35
+ - Add nested object limit configuration
36
+ - Add report ruleset information
37
+
38
+ # 2022-04-29 v1.3.0.0.0
39
+
40
+ - Promote v1.3.0.0.0.beta1 to stable
41
+
42
+ # 2022-04-20 v1.3.0.0.0.beta1
43
+
44
+ - Update to libddwaf 1.3.0
45
+
46
+ # 2022-03-18 v1.2.1.0.0.beta1
47
+
48
+ - Update to libddwaf 1.2.1
49
+ - Fix incorrect types for a few binding functions
50
+
51
+ # 2022-03-04 v1.0.14.2.1.beta1
52
+
53
+ - Fix incorrect return code
54
+ - Fix passing nil in libddwaf object containers
55
+
56
+ # 2022-02-07 v1.0.14.2.0.beta1
57
+
58
+ - Change Datadog::Security to Datadog::AppSec
59
+
60
+ # 2022-02-01 v1.0.14.1.0.beta2
61
+
62
+ - Add support for Ruby 3.1
63
+
64
+ # 2021-12-14 v1.0.14.1.0.beta1
65
+
66
+ - Fix sequential runs on a single context by retaining C input data objects
67
+
68
+ # 2021-11-24 v1.0.14.0.0.beta1
69
+
70
+ - Update to libddwaf 1.0.14
71
+
72
+ # 2021-11-24 v1.0.13.0.0.beta1
73
+
74
+ - Add ruby platform fallback for unsupported platforms
75
+ - Update to libddwaf 1.0.13
76
+
77
+ # 2021-10-13 v1.0.12.0.0.beta1
78
+
79
+ - 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.1"
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,
@@ -190,12 +203,13 @@ module Datadog
190
203
  end
191
204
 
192
205
  class Obfuscator < ::FFI::Struct
193
- layout :key_regex, :pointer, # :charptr
194
- :value_regex, :pointer # :charptr
206
+ layout :key_regex, :pointer, # should be :charptr
207
+ :value_regex, :pointer # should be :charptr
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,108 @@ 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
+ data_obj = Datadog::AppSec::WAF.ruby_to_object(data, coerce: false)
543
+ res = Datadog::AppSec::WAF::LibDDWAF.ddwaf_update_rule_data(@handle_obj, data_obj)
544
+
545
+ RESULT_CODE[res]
546
+ ensure
547
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_object_free(data_obj) if data_obj
548
+ end
549
+
550
+ def toggle_rules(map)
551
+ map_obj = Datadog::AppSec::WAF.ruby_to_object(map, coerce: false)
552
+ res = Datadog::AppSec::WAF::LibDDWAF.ddwaf_toggle_rules(@handle_obj, map_obj)
553
+
554
+ RESULT_CODE[res]
555
+ ensure
556
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_object_free(map_obj) if map_obj
557
+ end
558
+
559
+ private
560
+
561
+ def validate!
562
+ @valid = true
563
+ end
564
+
565
+ def invalidate!
566
+ @valid = false
567
+ end
568
+
569
+ def valid?
570
+ @valid
571
+ end
572
+
573
+ def valid!
574
+ return if valid?
575
+
576
+ fail LibDDWAF::Error, "Attempt to use an invalid instance: #{inspect}"
577
+ end
578
+
579
+ def retained
580
+ @retained ||= []
581
+ end
582
+
583
+ def retain(object)
584
+ retained << object
585
+ end
586
+
587
+ def release(object)
588
+ retained.delete(object)
589
+ end
444
590
  end
445
591
 
446
- Result = Struct.new(:action, :data, :total_runtime, :timeout)
592
+ class Result
593
+ attr_reader :status, :data, :total_runtime, :timeout, :actions
594
+
595
+ def initialize(status, data, total_runtime, timeout, actions)
596
+ @status = status
597
+ @data = data
598
+ @total_runtime = total_runtime
599
+ @timeout = timeout
600
+ @actions = actions
601
+ end
602
+ end
447
603
 
448
604
  class Context
449
605
  attr_reader :context_obj
450
606
 
451
607
  def initialize(handle)
452
608
  handle_obj = handle.handle_obj
453
- free_func = Datadog::AppSec::WAF::LibDDWAF::ObjectNoFree
609
+ retain(handle)
454
610
 
455
- @context_obj = Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_init(handle_obj, free_func)
611
+ @context_obj = Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_init(handle_obj)
456
612
  if @context_obj.null?
457
613
  fail LibDDWAF::Error, 'Could not create context'
458
614
  end
459
615
 
460
- @input_objs = []
461
-
462
- ObjectSpace.define_finalizer(self, Context.finalizer(context_obj, @input_objs))
616
+ validate!
463
617
  end
464
618
 
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)
619
+ def finalize
620
+ invalidate!
621
+
622
+ retained.each do |retained_obj|
623
+ next unless retained_obj.is_a?(Datadog::AppSec::WAF::LibDDWAF::Object)
624
+
625
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_object_free(retained_obj)
471
626
  end
627
+
628
+ Datadog::AppSec::WAF::LibDDWAF.ddwaf_context_destroy(context_obj)
472
629
  end
473
630
 
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
- }
631
+ def run(input, timeout = LibDDWAF::DDWAF_RUN_TIMEOUT)
632
+ valid!
633
+
634
+ max_container_size = LibDDWAF::DDWAF_MAX_CONTAINER_SIZE
635
+ max_container_depth = LibDDWAF::DDWAF_MAX_CONTAINER_DEPTH
636
+ max_string_length = LibDDWAF::DDWAF_MAX_STRING_LENGTH
483
637
 
484
- def run(input, timeout = DEFAULT_TIMEOUT_US)
485
- input_obj = Datadog::AppSec::WAF.ruby_to_object(input)
638
+ input_obj = Datadog::AppSec::WAF.ruby_to_object(input,
639
+ max_container_size: max_container_size,
640
+ max_container_depth: max_container_depth,
641
+ max_string_length: max_string_length)
486
642
  if input_obj.null?
487
643
  fail LibDDWAF::Error, "Could not convert input: #{input.inspect}"
488
644
  end
@@ -493,21 +649,60 @@ module Datadog
493
649
  end
494
650
 
495
651
  # retain C objects in memory for subsequent calls to run
496
- @input_objs << input_obj
652
+ retain(input_obj)
497
653
 
498
654
  code = Datadog::AppSec::WAF::LibDDWAF.ddwaf_run(@context_obj, input_obj, result_obj, timeout)
499
655
 
656
+ actions = if result_obj[:actions][:size] > 0
657
+ result_obj[:actions][:array].get_array_of_string(0, result_obj[:actions][:size])
658
+ else
659
+ []
660
+ end
661
+
500
662
  result = Result.new(
501
- ACTION_MAP_OUT[code],
663
+ RESULT_CODE[code],
502
664
  (JSON.parse(result_obj[:data]) if result_obj[:data] != nil),
503
665
  result_obj[:total_runtime],
504
666
  result_obj[:timeout],
667
+ actions,
505
668
  )
506
669
 
507
- [ACTION_MAP_OUT[code], result]
670
+ [RESULT_CODE[code], result]
508
671
  ensure
509
672
  Datadog::AppSec::WAF::LibDDWAF.ddwaf_result_free(result_obj) if result_obj
510
673
  end
674
+
675
+ private
676
+
677
+ def validate!
678
+ @valid = true
679
+ end
680
+
681
+ def invalidate!
682
+ @valid = false
683
+ end
684
+
685
+ def valid?
686
+ @valid
687
+ end
688
+
689
+ def valid!
690
+ return if valid?
691
+
692
+ fail LibDDWAF::Error, "Attempt to use an invalid instance: #{inspect}"
693
+ end
694
+
695
+ def retained
696
+ @retained ||= []
697
+ end
698
+
699
+ def retain(object)
700
+ retained << object
701
+ end
702
+
703
+ def release(object)
704
+ retained.delete(object)
705
+ end
511
706
  end
512
707
  end
513
708
  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.1
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: 2023-02-01 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.4.4
66
67
  signing_key:
67
68
  specification_version: 4
68
69
  summary: Datadog WAF