From 51a803f2b68f70da7b2eb9d49c8173501cb3d59d Mon Sep 17 00:00:00 2001 From: Yury Lebedev Date: Wed, 2 Oct 2024 16:49:26 +0200 Subject: [PATCH 1/3] Add a force disable of appsec when using Ruby >= 3.3 with old ffi Ruby 3.3 and newer has a memory leak when using libddwaf with `ffi` gem older than 1.16.0. We want to avoid forcing our customers to update `ffi` gem, by setting the minimum version in `libddwaf-rb`, since prebuilt `ffi` extension is incompatible with rubygems version supplied with ruby 2.7 and below. --- lib/datadog/appsec/component.rb | 18 +++++++++++++++++- spec/datadog/appsec/component_spec.rb | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/datadog/appsec/component.rb b/lib/datadog/appsec/component.rb index 2663f594b06..f8fd00358ca 100644 --- a/lib/datadog/appsec/component.rb +++ b/lib/datadog/appsec/component.rb @@ -11,7 +11,8 @@ module AppSec class Component class << self def build_appsec_component(settings, telemetry:) - return unless settings.respond_to?(:appsec) && settings.appsec.enabled + return if !settings.respond_to?(:appsec) || !settings.appsec.enabled + return if incompatible_ffi_version? processor = create_processor(settings, telemetry) @@ -28,6 +29,21 @@ def build_appsec_component(settings, telemetry:) private + def incompatible_ffi_version? + ffi_version = Gem.loaded_specs['ffi'] && Gem.loaded_specs['ffi'].version + if RUBY_VERSION >= '3.3.0' && ffi_version < '1.16.0' + Datadog.logger.warn( + 'AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, ' \ + 'and will be forcibly disabled due to a memory leak in `ffi`. ' \ + 'Please upgrade your `ffi` version to 1.16.0 or higher.' + ) + + true + else + false + end + end + def create_processor(settings, telemetry) rules = AppSec::Processor::RuleLoader.load_rules( telemetry: telemetry, diff --git a/spec/datadog/appsec/component_spec.rb b/spec/datadog/appsec/component_spec.rb index 75e0c9fe1cb..3581038d5d4 100644 --- a/spec/datadog/appsec/component_spec.rb +++ b/spec/datadog/appsec/component_spec.rb @@ -19,6 +19,20 @@ expect(component).to be_a(described_class) end + context 'when using old ffi version with Ruby 3.3.x' do + before do + stub_const('RUBY_VERSION', '3.3.0') + allow(Gem).to receive(:loaded_specs).and_return('ffi' => double(version: Gem::Version.new('1.15.4'))) + end + + it 'returns a Datadog::AppSec::Component instance with a nil processor' do + expect(Datadog.logger).to receive(:warn) + + component = described_class.build_appsec_component(settings, telemetry: telemetry) + expect(component).to be_nil + end + end + context 'when processor is ready' do it 'returns a Datadog::AppSec::Component with a processor instance' do expect_any_instance_of(Datadog::AppSec::Processor).to receive(:ready?).and_return(true) From b4f66416f834d5251c3059c1fb09af5d2260aed2 Mon Sep 17 00:00:00 2001 From: Yury Lebedev Date: Wed, 2 Oct 2024 18:15:49 +0200 Subject: [PATCH 2/3] Add guard clause to AppSec::Component#incompatible_ffi_version? --- lib/datadog/appsec/component.rb | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/datadog/appsec/component.rb b/lib/datadog/appsec/component.rb index f8fd00358ca..72e33a2267f 100644 --- a/lib/datadog/appsec/component.rb +++ b/lib/datadog/appsec/component.rb @@ -31,17 +31,15 @@ def build_appsec_component(settings, telemetry:) def incompatible_ffi_version? ffi_version = Gem.loaded_specs['ffi'] && Gem.loaded_specs['ffi'].version - if RUBY_VERSION >= '3.3.0' && ffi_version < '1.16.0' - Datadog.logger.warn( - 'AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, ' \ - 'and will be forcibly disabled due to a memory leak in `ffi`. ' \ - 'Please upgrade your `ffi` version to 1.16.0 or higher.' - ) - - true - else - false - end + return false unless RUBY_VERSION >= '3.3.0' && ffi_version < '1.16.0' + + Datadog.logger.warn( + 'AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, ' \ + 'and will be forcibly disabled due to a memory leak in `ffi`. ' \ + 'Please upgrade your `ffi` version to 1.16.0 or higher.' + ) + + true end def create_processor(settings, telemetry) From 03f3bc90a34dcc748370d295a0635157526f58a9 Mon Sep 17 00:00:00 2001 From: Yury Lebedev Date: Mon, 7 Oct 2024 11:07:19 +0200 Subject: [PATCH 3/3] Use Gem::Version for comparing Ruby and ffi versions --- lib/datadog/appsec/component.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/datadog/appsec/component.rb b/lib/datadog/appsec/component.rb index 72e33a2267f..a4a1db9ab3b 100644 --- a/lib/datadog/appsec/component.rb +++ b/lib/datadog/appsec/component.rb @@ -31,7 +31,8 @@ def build_appsec_component(settings, telemetry:) def incompatible_ffi_version? ffi_version = Gem.loaded_specs['ffi'] && Gem.loaded_specs['ffi'].version - return false unless RUBY_VERSION >= '3.3.0' && ffi_version < '1.16.0' + return false unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3') && + ffi_version < Gem::Version.new('1.16.0') Datadog.logger.warn( 'AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, ' \