Dear Maintainer,

the bug is still exists in 4.4.1 when lease limits are used as described before.

gdb:
Breakpoint 1, ack_lease (packet=packet@entry=0x555556c24780, lease=0x555556224630, offer=offer@entry=2, when=1554726300, msg=msg@entry=0x7fffffffcc90 "DHCPDISCOVER from 90:6e:bb:4d:77:e7 via 10.96.160.1",
    ms_nulltp=ms_nulltp@entry=0, hp=0x0) at dhcp.c:2570
2570    in dhcp.c

Somewhere in 4.3.x this function is changed to:
                /* If we don't have an active billing, see if we need
                   one, and if we do, try to do so. */
                if (lease->billing_class == NULL) {
                        char *cname = "";
                        int bill = 0;

                        for (i = 0; i < packet->class_count; i++) {
                                struct class *billclass, *subclass;

                                billclass = packet->classes[i];
                                if (billclass->lease_limit) {
                                        bill++;
                                        if (bill_class(lease, billclass))
                                                break;

                                        subclass = billclass->superclass;
                                        if (subclass == NULL)
                                                cname = subclass->name;
                                        else
                                                cname = billclass->name;
                                }
                        }

where gdb points:

                                                cname = subclass->name;

As you see, the if statement is TRUE, when sublass is NULL, then it tries to use NULL value on subclaass->name.

The old working code was:
                if (lease->billing_class == NULL) {
                        int bill = 0;
                        for (i = 0; i < packet->class_count; i++) {
                                if (packet->classes[i]->lease_limit) {
                                        bill++;
                                        if (bill_class(lease,
                                                       packet->classes[i]))
                                                break;
                                }
                        }

I've patched 4.4.1 with the old one.

Patch:
--- isc-dhcp-4.4.1.orig/server/dhcp.c
+++ isc-dhcp-4.4.1/server/dhcp.c
@@ -2554,24 +2554,16 @@ void ack_lease (packet, lease, offer, wh
                   one, and if we do, try to do so. */
                if (lease->billing_class == NULL) {
                        char *cname = "";
-                       int bill = 0;
+                        int bill = 0;
+                        for (i = 0; i < packet->class_count; i++) {
+                                if (packet->classes[i]->lease_limit) {
+                                        bill++;
+                                        if (bill_class(lease,
+                                                       packet->classes[i]))
+                                                break;
+                                }
+                        }

-                       for (i = 0; i < packet->class_count; i++) {
-                               struct class *billclass, *subclass;
-
-                               billclass = packet->classes[i];
-                               if (billclass->lease_limit) {
-                                       bill++;
-                                       if (bill_class(lease, billclass))
-                                               break;
-
-                                       subclass = billclass->superclass;
-                                       if (subclass == NULL)


I've started to test it on production environments (IPv4, IPv6). I'll report what happens after a few days.

Peter Nagy

On Sun, 12 Apr 2015 10:14:36 +0200 Jose Miguel Sanchez Ales <[email protected]> wrote:
Package: isc-dhcp-server
Version: 4.3.1-6
Severity: important

Dear Maintainer,

The dhcpd server dies with segmentation fault when exceeds the lease
limit in a class. For example:

#v+
class "foo" {
   match if 1 = 1;
   lease limit 1;
}
#v-

At first time, a client obtains ip and exhausts the limit:

#v+
Apr 12 09:32:06 zipi dhcpd: DHCPREQUEST for 192.168.255.106 from 
00:11:22:33:44:55 via eth1
Apr 12 09:32:06 zipi dhcpd: DHCPACK on 192.168.255.106 to 00:11:22:33:44:55 
(qos2) via eth1
#v-

However if a second client makes a request, the DHCP server dies:

#v+
Apr 12 09:32:33 zipi dhcpd: DHCPREQUEST for 192.168.255.106 from 
00:11:22:33:44:56 via eth1: lease 192.168.255.106 unavailable.
Apr 12 09:32:33 zipi dhcpd: DHCPNAK on 192.168.255.106 to 00:11:22:33:44:56 via 
eth1
Apr 12 09:32:33 zipi kernel: [  607.009131] dhcpd[9787]: segfault at 30 ip 
00007f31ee2d3333 sp 00007ffc6a94f300 error 4 in dhcpd[7f31ee2bc000+b3000]
#v-

On wheezy the behavior is correct:

#v+
DHCPDISCOVER from 00:11:22:33:44:70 via eth1: no available billing: lease limit 
reached in all matching classes
#v-

-- System Information:
Debian Release: 8.0
  APT prefers testing-updates
  APT policy: (500, 'testing-updates'), (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 3.16.0-4-amd64 (SMP w/1 CPU core)
Locale: LANG=es_ES.UTF-8, LC_CTYPE=es_ES.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages isc-dhcp-server depends on:
ii  debconf [debconf-2.0]  1.5.56
ii  debianutils            4.4+b1
ii  isc-dhcp-common        4.3.1-6
ii  libc6                  2.19-17
ii  libdns-export100       1:9.9.5.dfsg-9
ii  libirs-export91        1:9.9.5.dfsg-9
ii  libisc-export95        1:9.9.5.dfsg-9
ii  lsb-base               4.1+Debian13+nmu1

isc-dhcp-server recommends no packages.


Reply via email to