Skip to content

Commit

Permalink
fix(tracer): do not try to load asm if libddwaf unavailable (#8226)
Browse files Browse the repository at this point in the history
PR to hot fix CI on gitlab involving jobs with lambda.

- move filename of libddwaf to asm config. Check here if the file exists
and disable asm and api security if it doesn't.
- add a failsafe in the tracer. Even if asm or apisec is enabled later,
do not activate them if libddwaf is unavailable.

## 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] Risks are described (performance impact, potential for breakage,
maintainability)
- [x] Change is maintainable (easy to change, telemetry, documentation)
- [x] [Library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
are followed or label `changelog/no-changelog` is set
- [x] Documentation is included (in-code, generated user docs, [public
corp docs](https://github.com/DataDog/documentation/))
- [x] Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))
- [x] If this PR changes the public interface, I've notified
`@DataDog/apm-tees`.
- [x] If change touches code that signs or publishes builds or packages,
or handles credentials of any kind, I've requested a review from
`@DataDog/security-design-and-guidance`.

## Reviewer Checklist

- [x] Title is accurate
- [x] All changes are related to the pull request's stated goal
- [x] Description motivates each change
- [x] Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes
- [x] Testing strategy adequately addresses listed risks
- [x] Change is maintainable (easy to change, telemetry, documentation)
- [x] Release note makes sense to a user of the library
- [x] Author has acknowledged and discussed the performance implications
of this PR as reported in the benchmarks PR comment
- [x] Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
  • Loading branch information
christophe-papazian authored Jan 30, 2024
1 parent 0cc5742 commit 4722a8b
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 44 deletions.
40 changes: 22 additions & 18 deletions ddtrace/appsec/_ddwaf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,33 @@

from ddtrace.appsec._constants import DEFAULT
from ddtrace.internal.logger import get_logger
from ddtrace.settings.asm import config as asm_config


LOGGER = get_logger(__name__)

try:
from .ddwaf_types import DDWafRulesType
from .ddwaf_types import _observator
from .ddwaf_types import ddwaf_config
from .ddwaf_types import ddwaf_context_capsule
from .ddwaf_types import ddwaf_get_version
from .ddwaf_types import ddwaf_object
from .ddwaf_types import ddwaf_object_free
from .ddwaf_types import ddwaf_result
from .ddwaf_types import ddwaf_run
from .ddwaf_types import py_ddwaf_context_init
from .ddwaf_types import py_ddwaf_init
from .ddwaf_types import py_ddwaf_known_addresses
from .ddwaf_types import py_ddwaf_update

_DDWAF_LOADED = True
except BaseException:
if asm_config._asm_libddwaf_available:
try:
from .ddwaf_types import DDWafRulesType
from .ddwaf_types import _observator
from .ddwaf_types import ddwaf_config
from .ddwaf_types import ddwaf_context_capsule
from .ddwaf_types import ddwaf_get_version
from .ddwaf_types import ddwaf_object
from .ddwaf_types import ddwaf_object_free
from .ddwaf_types import ddwaf_result
from .ddwaf_types import ddwaf_run
from .ddwaf_types import py_ddwaf_context_init
from .ddwaf_types import py_ddwaf_init
from .ddwaf_types import py_ddwaf_known_addresses
from .ddwaf_types import py_ddwaf_update

_DDWAF_LOADED = True
except BaseException:
_DDWAF_LOADED = False
LOGGER.warning("DDWaf features disabled. WARNING: Dynamic Library not loaded", exc_info=True)
else:
_DDWAF_LOADED = False
LOGGER.warning("DDWaf features disabled. WARNING: Dynamic Library not loaded", exc_info=True)


class DDWaf_result(object):
Expand Down
17 changes: 2 additions & 15 deletions ddtrace/appsec/_ddwaf/ddwaf_types.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import ctypes
import ctypes.util
from enum import IntEnum
import os
from platform import machine
from platform import system
from typing import Any
Expand All @@ -10,15 +9,11 @@
from typing import Union

from ddtrace.internal.logger import get_logger
from ddtrace.settings.asm import config as asm_config


DDWafRulesType = Union[None, int, str, List[Any], Dict[str, Any]]

_DIRNAME = os.path.dirname(__file__)

FILE_EXTENSION = {"Linux": "so", "Darwin": "dylib", "Windows": "dll"}[system()]


log = get_logger(__name__)

#
Expand All @@ -34,16 +29,8 @@
ARCHI = machine().lower()

# 32-bit-Python on 64-bit-Windows
if system() == "Windows" and ARCHI == "amd64":
from sys import maxsize

if maxsize <= (1 << 32):
ARCHI = "x86"

TRANSLATE_ARCH = {"amd64": "x64", "i686": "x86_64", "x86": "win32"}
ARCHITECTURE = TRANSLATE_ARCH.get(ARCHI, ARCHI)

ddwaf = ctypes.CDLL(os.path.join(_DIRNAME, "libddwaf", ARCHITECTURE, "lib", "libddwaf." + FILE_EXTENSION))
ddwaf = ctypes.CDLL(asm_config._asm_libddwaf)
#
# Constants
#
Expand Down
29 changes: 29 additions & 0 deletions ddtrace/settings/asm.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import os.path
from platform import machine
from platform import system

from envier import Env

from ddtrace.appsec._constants import API_SECURITY
Expand All @@ -13,6 +17,24 @@ def _validate_sample_rate(r: float) -> None:
raise ValueError("sample rate value must be between 0.0 and 1.0")


def build_libddwaf_filename() -> str:
"""
Build the filename of the libddwaf library to load.
"""
_DIRNAME = os.path.dirname(os.path.dirname(__file__))
FILE_EXTENSION = {"Linux": "so", "Darwin": "dylib", "Windows": "dll"}[system()]
ARCHI = machine().lower()
# 32-bit-Python on 64-bit-Windows
if system() == "Windows" and ARCHI == "amd64":
from sys import maxsize

if maxsize <= (1 << 32):
ARCHI = "x86"
TRANSLATE_ARCH = {"amd64": "x64", "i686": "x86_64", "x86": "win32"}
ARCHITECTURE = TRANSLATE_ARCH.get(ARCHI, ARCHI)
return os.path.join(_DIRNAME, "appsec", "_ddwaf", "libddwaf", ARCHITECTURE, "lib", "libddwaf." + FILE_EXTENSION)


class ASMConfig(Env):
_asm_enabled = Env.var(bool, APPSEC_ENV, default=False)
_iast_enabled = Env.var(bool, IAST_ENV, default=False)
Expand All @@ -24,6 +46,9 @@ class ASMConfig(Env):
_api_security_enabled = Env.var(bool, API_SECURITY.ENV_VAR_ENABLED, default=True)
_api_security_sample_rate = Env.var(float, API_SECURITY.SAMPLE_RATE, validator=_validate_sample_rate, default=0.1)
_api_security_parse_response_body = Env.var(bool, API_SECURITY.PARSE_RESPONSE_BODY, default=True)
_asm_libddwaf = build_libddwaf_filename()
_asm_libddwaf_available = os.path.exists(_asm_libddwaf)

_waf_timeout = Env.var(
float,
"DD_APPSEC_WAF_TIMEOUT",
Expand Down Expand Up @@ -70,3 +95,7 @@ class ASMConfig(Env):


config = ASMConfig()

if not config._asm_libddwaf_available:
config._asm_enabled = False
config._iast_enabled = False
25 changes: 14 additions & 11 deletions ddtrace/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,24 @@ def _default_span_processors_factory(
span_processors: List[SpanProcessor] = []
span_processors += [TopLevelSpanProcessor()]

if appsec_enabled:
if asm_config._api_security_enabled:
from ddtrace.appsec._api_security.api_manager import APIManager
if asm_config._asm_libddwaf_available:
if appsec_enabled:
if asm_config._api_security_enabled:
from ddtrace.appsec._api_security.api_manager import APIManager

APIManager.enable()
APIManager.enable()

appsec_processor = _start_appsec_processor()
if appsec_processor:
span_processors.append(appsec_processor)
else:
if asm_config._api_security_enabled:
from ddtrace.appsec._api_security.api_manager import APIManager
appsec_processor = _start_appsec_processor()
if appsec_processor:
span_processors.append(appsec_processor)
else:
if asm_config._api_security_enabled:
from ddtrace.appsec._api_security.api_manager import APIManager

APIManager.disable()
APIManager.disable()

appsec_processor = None
else:
appsec_processor = None

if iast_enabled:
Expand Down

0 comments on commit 4722a8b

Please sign in to comment.