Bug 239746 - net-mgmt/zabbix4-server: Unable to stop service since 4.0.11 update
Summary: net-mgmt/zabbix4-server: Unable to stop service since 4.0.11 update
Status: Open
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-ports-bugs mailing list
URL: https://support.zabbix.com/browse/ZBX...
Keywords: needs-patch, needs-qa
Depends on:
Blocks:
 
Reported: 2019-08-09 17:01 UTC by Christian Ullrich
Modified: 2019-08-10 19:39 UTC (History)
2 users (show)

See Also:
bugzilla: maintainer-feedback? (pg)


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Christian Ullrich 2019-08-09 17:01:19 UTC
Related bug report: https://support.zabbix.com/browse/ZBX-16460

A change in Zabbix 4.0.11 and 4.2.5 is causing trouble when stopping the agent, proxy, and server daemons. These versions changed the way the daemons are stopped, and the new implementation is affected by the security.bsd.conservative_signals sysctl under certain circumstances.

Everything below uses the agent as an example, but it applies to the other services as well.

The problem occurs when all of the below are true:

- zabbix_agentd_user is not set to "zabbix" (it is not set at all by default).
- The rc script provided by the port is used.

The net-mgmt/zabbix4{,2}-{agent,proxy,server} ports provide their own rc script. This script has its own implementation of $start_cmd that extends $PATH (at least for agent and server, the initialization is missing from the proxy ports) with the contents of $zabbix_*_paths.

This is a bug because it entirely ignores any potentially set $zabbix_agent_user variable. Even though _user variables are infrequently used, they should still be obeyed.

Because of this bug, the services are always started as the user executing the rc script, i.e. root, even if apparently overridden by setting the _user variable. They then setuid() to the user name their own configuration specifies, which is "zabbix" in the ports.

In this situation, stopping the services does not work if the security.bsd.conservative_signals sysctl is enabled, which it has been by default for the entire 14 years of its existence.

The Zabbix services each run multiple copies of themselves, with the parent process managing them. To stop the service, this parent process receives a SIGTERM and reacts by sending first SIGUSR2 to its children, followed by SIGABRT. _If_ it setuid()d itself, however, sending SIGABRT to its children fails with EPERM due to the sysctl.

A simple workaround for this issue is to set $zabbix_agentd_user to "zabbix" so the service process does not setuid() itself, except that this is impossible because the rc script ignores the variable.

I'm honestly not sure whether the underlying cause isn't a bug in FreeBSD. The kill(2) man page says that the sysctl prevents signals not on the whitelist from being sent to a setuid process. In this case, the receiving processes apparently inherit the setuid status from their parent through the fork(), and that may not be entirely correct.

On the other hand, it might also be a bug in Zabbix, in that it uses a signal not on the whitelist in a situation with setuid processes.


Suggested fix:

- Remove the $zabbix_agentd_paths rc variable and use $zabbix_agentd_env instead.
- Remove the zabbix_agentd_cmd() function from the port-provided rc script.
- Default the $zabbix_agentd_user rc variable to "zabbix" (the same user as in the sample configuration files).
Comment 1 Danilo G. Baio freebsd_committer 2019-08-10 19:39:57 UTC
Hi.

Unfortunately I can confirm this issue with Zabbix 4.2.5 and 4.0.11.

Thank you for the report here and with Zabbix, your information is very clear and helpful.

I added a "steps to reproduce" on the bug you have opened.

Is common to execute the daemon as root and then set-uid to other unprivileged user, like nginx/php-fpm, but there are others daemons that don't do that, like mysql server and in this case, we can deal with that through daemon(8).

But first, let's see their thoughts there.

Regards.