Avoiding infinite loops (that can cause dhcpd to segfault or crash)
  • 27 Sep 2018
  • 5 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

Avoiding infinite loops (that can cause dhcpd to segfault or crash)

  • Dark
    Light
  • PDF

Article Summary

"With great power comes great responsibility"

Infinite Loops

The configuration language used for ISC DHCP is quite complex and provides the administrator with a great deal of power to affect the processing of the server and, to a lesser degree, the client. Unfortunately with this power it is also possible to cause yourself significant problems. These problems can manifest in many different ways depending on what the configuration does, the initial article will start with two examples of infinite loops, we plan to extend this as we find more issues.

If you encounter odd or incorrect behavior it is best to try and reduce your configuration to determine if the problem is simply a bug in the code or may be an issue in the way you are using the configuration language. You will probably find it best to avoid overly complex configurations in any case as they tend to make it harder to maintain the configuration files over time.

In the following examples the configuration describes a loop. The server will simply follow the loop recursively and eventually crash. One potential difficulty in diagnosing them is that they may not occur frequently. The code at issue will only be executed by the server when called for elsewhere in the configuration. The first will only be executed when a client requests the vendor information and should receive it from the cisco-lwap option space. The second would occur when a client made a request as the offending statement was global. If the statement had been in a specific subnet or host it could take some time before it would occur.

While these provide two specific ways to create loops there are numerous other possibilities, though most of them are unlikely in normal use. In all cases some care should be taken to avoid creating circular dependencies when setting options.

Bad Encapsulation

The following example tries to set up a vendor option space for use with the server. Unfortunately the third line, while attempting to cause the option space to be encapsulated within the DHCP space, is actually going to cause the space to be encapsulated within itself. When the server attempts to use this option space it will create an internal infinite loop and will probably crash. 

option space cisco-lwap ;
option cisco-lwap.controllers code 241 = array of ip-address ;
option cisco-lwap.encap       code  43 = encapsulate cisco-lwap ;
option cisco-lwap.controllers 172.16.132.1 ;

DDNS Naming

In 4.3.2, 4.2.8 and 4.1-ESV-R11 we fixed some long-standing bugs with how the server determined the name to use for a client when updating the DNS via DDNS updates. As part of this patch we changed the default method of picking the hostname. Previously it was this:

option server.ddns-hostname = pick (option fqdn.hostname, option host-name);

After our changes it became:

option server.ddns-hostname = pick (option fqdn.hostname, option host-name, config-option host-name);

Note particularly the new (final) element in the pick list.

While this declaration for server.ddns-hostname is a part of the code, because it is the default value, it will behave exactly as if the string were included in the configuration file explicitly. It attempts to choose the hostname that the DDNS code should use for a client by looking at the hostname first from the incoming FQDN, then from the incoming host-name option and finally at the host-name option being set up by the server.

The difference between 'config-option' and 'option' in dhcpd.conf
In the example above, you see 'host-name' appearing twice in the pick list.  When it is prefixed with 'option' - this means 'use the value that is in the packet that we are handling' - in this case the host-name option as requested by the client. When it is prefixed with 'config-option', it means 'use the current value as defined right this moment on the server'. This might be the value from an option statement in the configuration file, or a new value that has been set during conditional processing prior to reaching this point in the handling of the client packet.

A reference to an option prefixed with 'config-option' may have to be evaluated before it can be used at the time it is encountered. If nothing else had altered it in the interim, then looking at the example immediately above, a dynamic evaluation would have to take place if dhcpd encountered 'config-option server.ddns-hostname' on the RHS (Right Hand Side) of another option statement.

In summary, when the dhcpd processing encounters 'config-option' <option> on the RHS of another option or processing statement, it substitutes whatever is the current option value at the time - including evaluating it first if necessary.

With the new default active for picking the name for the client, an administrator who had included the following line in their DHCP server configuration file, would experience a crash soon after restarting their upgraded dhcpd :

option host-name = config-option server.ddns-hostname;

This has the effect of creating a loop between the ddns-hostname and the config-option instance of the host-name (the config-option host-name on the right hand side of the equation is the same as option host-name on the left hand side of the equation.)  When the server attempts to evaluate this code it falls into a recursive loop and eventually dies with a segfault.

A segfault will usually be logged in the system logs, and will look something like this:

dhcpd[1234]: segfault at 7fffcd793ff8 ip 00007f418e1a8456 sp 00007fffcd794000 error 6 in dhcpd[7f418e128000+a9000]

(Note that the process ID and all of the stack and code offset values will vary by build and environment - don't expect to see the same numbers in your segfault, even if the cause is the same.)

The administrator has several options to fix this. The simplest is to remove the last line trying to set the host-name. This is likely to be what they really want most of the time, especially if they enable the use-host-decl-names option.

If the administrator does want to set the host-name more specifically, they can either set it directly (without reference to config-option server.ddns-hostname) or they can reset the default back to the way it was prior to the upgrade by overriding option server.ddns-hostname explicitly in dhcpd.conf with:

option server.ddns-hostname = pick (option fqdn.hostname, option host-name);