Skip to content

Conversation

julianbrost
Copy link
Contributor

@julianbrost julianbrost commented Aug 1, 2025

In contrast to the regular kill binary, icinga2 internal signal drops permissions before sending the signal. This is important as the PID file can be written by the Icinga user, dropping the permissions prevents that user from using this to send signals to processes it is not supposed to signal.

SIGUSR1 wasn't among the list of signals supported by icinga2 internal signal, so it is added there.

Important

Mention in changelog:
The logrotate config is installed in /etc and may not be updated by a package update in case it was modified.

Tests

  • Installed from this branch, new CMake substitutions worked correctly.
  • systemctl reload icinga2 (and also calling /usr/lib/icinga2/safe-reload) still successfully reload Icinga 2.
  • Expanded command from the logrotate config worked when manually executing it (triggered the "Received USR1 signal, reopening application logs." log message).
  • icinga2 internal signal indeed drops privileges (more of a sanity check):
    # strace -e getuid,setuid,kill icinga2 internal signal --sig SIGHUP --pid 1
    --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2562755, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
    getuid()                                = 0
    setuid(961)                             = 0
    kill(1, SIGHUP)                         = -1 EPERM (Operation not permitted)
    +++ exited with 255 +++

fixes #10527

In contrast to the regular `kill` binary, `icinga2 internal signal` drops
permissions before sending the signal. This is important as the PID file can be
written by the Icinga user, dropping the permissions prevents that user from
using this to send signals to processes it is not supposed to signal.

SIGUSR1 wasn't among the list of signals supported by `icinga2 internal
signal`, so it is added there.
notifempty@LOGROTATE_CREATE@
postrotate
/bin/kill -USR1 $(cat @ICINGA2_INITRUNDIR@/icinga2.pid 2> /dev/null) 2> /dev/null || true
@CMAKE_INSTALL_FULL_SBINDIR@/icinga2 internal signal --sig SIGUSR1 --pid "$(cat @ICINGA2_INITRUNDIR@/icinga2.pid 2> /dev/null)" 2> /dev/null || true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be aware that this is a config file which we've currently told the package manager not to override by %config(noreplace).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunate, but not much we can do about it except mentioning it in the changelog. I've added a corresponding hint to the PR description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not true! We can at least consider %config, i.e w/o (noreplace).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the file was modified, there was probably a reason for doing so. Just overwriting it would likely break something.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And just keeping it leaves a security hole(?) for all who don't read the changelog, but modified stuff. Also, %config makes a backup of your modifications.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dgoetz:

  • This is a valid reason for %config
  • Needs proper upgrade log, though (breaking changes awareness)
  • Also %config must be kept long enough, as users may skip a version

@julianbrost
Copy link
Contributor Author

Feedback from the reporter:

I just had a look. I guess the interesting part now is what icinga2 internal signal --sig <signal> --pid <pid> does. Judging from the strace output it's a lot. Many threads are created, sockets are created, network interface information is retrieved via Netlink, file descriptors in /proc/self/fd are inspected, one thread sends SIGRT_1 to another thread.

Besides all that, all threads also seem to call setuid(), setgid() and setgroups(). icinga2 and icingacmd group ownership is retained. Only then the desired signal is sent to the target <pid>. So I guess it is okay. I couldn't see any dangerous file operations in the trace.

Copy link
Member

@Al2Klimov Al2Klimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discuss #10530 (comment) with Eric (in the next core status meeting).

RPM

performs its .rpmsave/.rpmnew dance only if both the package maintainer and the admin change a config file: https://serverfault.com/a/672640?utm_source=chatgpt.com

Given that the issue here is security-related, I consider a plain %config reasonable, especially as it will (backup and) replace the edited file (warning the user) only once.

Yes, only once. I mean, just look at the file's history: https://github.com/Icinga/icinga2/commits/master/etc/logrotate.d/icinga2.cmake

Spoiler:

We can also revert it in a year or similar.

Debian

always asks the user, offering a diff: https://raphaelhertzog.com/2010/09/21/debian-conffile-configuration-file-managed-by-dpkg/?utm_source=chatgpt.com

Just pressing Enter, for simply keep my changes, is tempting, though.

Both of them

provide post-scripts, so we could replace /bin/kill -USR1 with sed(1). A good workaround IMAO.

Eric also mentioned a(n Icinga 2) runtime check (that the file is sane).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

safe-reload script runs as root operating on potentially untrusted data found in icinga PID file
3 participants