Icinga / Icinga/icinga2

Conversion of Function to Number possible on certain platforms

Open
#10,459 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
C++
Stars
2.2k
Forks
616
Avg merge
5d 6h
Merged PRs (30d)
10

Description

Describe the bug

It is possible to convert an Icinga function to a Number on certain platforms.

  • ✅ Linux built with glibc:
    Icinga 2 (version: v2.14.0-566-g8d607d2ef)
    Type $help to view available commands.
    <1> => Number({{ }})
           ^^^^^^^^^^^^^
    Error while evaluating expression: Can't convert 'Object of type 'Function'' to a floating point number.
    
  • ✅ Linux built with musl:
    Icinga 2 (version: r2.14.0-1)
    Type $help to view available commands.
    <1> => Number({{ }})
           ^^^^^^^^^^^^^
    Error while evaluating expression: Can't convert 'Object of type 'Function'' to a floating point number.
    
  • ❌ OpenBSD 7.7:
    Icinga 2 (version: r2.14.5-1)
    Type $help to view available commands.
    <1> => Number({{ }})
    14088953728896.000000
    
  • ❌ macOS (24.5.0 Darwin Kernel Version 24.5.0: Tue Apr 22 19:54:29 PDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6030 arm64)
    Icinga 2 (version: v2.14.0-661-gae06649e8)
    Type $help to view available commands.
    <1> => Number({{ }})
    5317598160.000000
    

While working with an Icinga a few days back, I realized that I was able to put a lambda as the Service.check_interval value. On this system, this resulted in this function being interpreted as a huge double, effectively killing Icinga DB.

To Reproduce

The easiest way to check is typing Number({{ }}) into the icinga2 console as shown above. In the following, my original finding was reported.

[!NOTE]
I am able to reproduce this issue on the originally affected system, running the latest Icinga 2 release version r2.14.5 on a current OpenBSD. However, I was not able to reproduce this on a Linux based on our Icinga 2 Docker containers. More about this below.

Starting with a generic Service object assigned with an apply for rule based on custom variables. This Service object has a faulty check_interval value of a lambda instead of a double value.

apply Service for (key => config in host.vars.passive_checks) {
  name = key

  check_command = "dummy"
  check_interval = {{ config.contains("check_interval") ? config.check_interval : 7d }}

  vars.dummy_state = 3
  vars.dummy_text = {{
    var service = get_service(macro("$host.name$"), macro("$service.name$"))
    var lastCheck = DateTime(service.last_check).to_string()

    return "No check results received. Last result time: " + lastCheck
  }}
}

(I am aware that the correct config would be check_interval = config.contains("check_interval") ? config.check_interval : 7d. This has nothing to do with the reported issue.)

For demonstration sake, one Host resulting in two such Service objects was created.

object Host "passive-test" {
  import "not-a-host"

  vars += {
    "passive_checks" = {
      "backup" = { check_interval = 14d }
      "foo" = { }
    }
  }
}

Let's verify the config.

$ icinga2 daemon -C --dump-objects
[2025-05-27 12:08:36 +0200] information/cli: Icinga application loader (version: r2.14.5-1)
[2025-05-27 12:08:36 +0200] information/cli: Loading configuration file(s).
[2025-05-27 12:08:36 +0200] information/ConfigItem: Committing config item(s).
[2025-05-27 12:08:37 +0200] information/ApiListener: My API identity: REDACTED
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 CheckerComponent.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 8 Hosts.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 Endpoint.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 FileLogger.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 NotificationComponent.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 3 TimePeriods.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 UserGroup.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 3 Zones.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 Downtime.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 IcingaDB.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 2 HostGroups.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 IcingaApplication.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 2 NotificationCommands.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 108 Services.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 231 CheckCommands.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 19 Dependencies.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 116 Notifications.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 7 ServiceGroups.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 2 ApiUsers.
[2025-05-27 12:08:37 +0200] information/ConfigItem: Instantiated 1 ApiListener.
[2025-05-27 12:08:38 +0200] information/ConfigItem: Instantiated 1 ScheduledDowntime.
[2025-05-27 12:08:38 +0200] information/ConfigItem: Instantiated 1 User.
[2025-05-27 12:08:38 +0200] information/ScriptGlobal: Dumping variables to file '/var/cache/icinga2/icinga2.vars'
[2025-05-27 12:08:38 +0200] information/cli: Finished validating the configuration file(s).

After reloading Icinga 2, the Service objects can be queried.

$ icinga2 object list -t Service -n 'passive-test!backup' | grep check_interval
  * check_interval = 13949418929536
$ icinga2 object list -t Service -n 'passive-test!foo' | grep check_interval
  * check_interval = 13949418927872

And after another reload, again.

$ icinga2 object list -t Service -n 'passive-test!backup' | grep check_interval
  * check_interval = 3945424160768
$ icinga2 object list -t Service -n 'passive-test!foo' | grep check_interval
  * check_interval = 3945132634240

While these values are ridiculously large and most likely derived from some pointer value, Icinga 2 is happy.

However, Icinga DB is not.

2025-05-27T12:10:13.039+0200    WARN    database        Can't execute query. Retrying   {[...], "errorVerbose": "pq: value for domain uint violates check constraint \"between_0_and_4294967295\"\ncan't perform \"INSERT INTO \\\"service\\\" [...]}

Since this faulty check_interval value will never be "between_0_and_4294967295", this will eventually lead into an Icinga DB crash.

As stated in the info box above, while I am able to reproduce this on the OpenBSD system, this fails with an expected error on a Linux. Since the type within the .ti file is a double, I am receiving an expected error.

icinga2  | [2025-05-27 10:01:21 +0000] critical/config: Error: Error while evaluating expression: Can't convert 'Object of type 'Function'' to a floating point number.
icinga2  | Location: in /etc/icinga2/zones.d/master/04-dummys-services.conf: 60:3-60:95
icinga2  | /etc/icinga2/zones.d/master/04-dummys-services.conf(58):
icinga2  | /etc/icinga2/zones.d/master/04-dummys-services.conf(59):   check_command = "dummy"
icinga2  | /etc/icinga2/zones.d/master/04-dummys-services.conf(60):   check_interval = {{ config.contains("check_interval") ? config.get("check_interval") : 24h }}
icinga2  |                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
icinga2  | /etc/icinga2/zones.d/master/04-dummys-services.conf(61):
icinga2  | /etc/icinga2/zones.d/master/04-dummys-services.conf(62):   vars.dummy_state = 3

Now, I am puzzled how this can work on one OS while failing on another.

Expected behavior

I would expect a convert error on every operating system.

Your Environment

Include as many relevant details about the environment you experienced the problem in

  • Version used (icinga2 --version): r2.14.5-1
  • Operating System and version: OpenBSD 7.7 GENERIC#630 amd64
  • Enabled features (icinga2 feature list): api checker icingadb mainlog notification
  • Icinga Web 2 version and modules (System - About): -
  • Config validation (icinga2 daemon -C): ✅

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing Number({{ }}) in the icinga2 console on OpenBSD and Linux, then compare the platform-dependent conversion behavior. Trace the expression evaluation and configuration validation path for the Function-to-Number conversion; done means the conversion raises an error consistently on every supported operating system.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.