[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#6076) slapo-collect: slapd repeatable segfaults caused by deletion of a single olcCollectInfo config value (when olcCollectInfo contains multiple configuration values)



Full_Name: Daniel Pluta
Version: OPENLDAP_STABLE
OS: Linux
URL: ftp://ftp.openldap.org/incoming/daniel-pluta-090424.patch
Submission from: (NULL) (2001:4ca0:0:f000:ecb9:edd3:5b88:63f0)


As already assumed in (ITS6072 FollowUp 5) there seems to be a bug regarding the
mapping of c->valx and the to-be-deleted value of the ci->ci_next list. The
origin seems to be the on-the-fly manipulation (sorting) of the ci-list that is
done by insert_ordered()) whenever a new config value is added...

To illustrate the problem in detail I've added some debugging output into
collect.c's LDAP_MOD_DELETE-section:

    case LDAP_MOD_DELETE:
        if ( c->valx == -1 ) {
        /* Delete entire attribute */
            collect_info *ci;
            while (( ci = on->on_bi.bi_private )) {
                on->on_bi.bi_private = ci->ci_next;
                ch_free( ci->ci_dn.bv_val );
                ch_free( ci );
            }
        } else {
        /* Delete just one value */
            collect_info **cip, *ci;
            int i;
            cip = (collect_info **)&on->on_bi.bi_private;

            Debug(LDAP_DEBUG_TRACE, "collect_cf: LDAP_MOD_DELETE:
c->valx=%d\n",
                c->valx, 0, 0);
            for ( i=0; i <= c->valx; i++, cip = &ci->ci_next ) {
                ci = *cip;
                Debug(LDAP_DEBUG_TRACE, "collect_cf: LDAP_MOD_DELETE: i=%d <-->
dn=%s\n",
                    i, ci->ci_dn.bv_val, 0);
            }
            *cip = ci->ci_next;
            Debug(LDAP_DEBUG_TRACE, "collect_cf: free: dn=%s\n",
                ci->ci_dn.bv_val, 0, 0);
            ch_free( ci->ci_dn.bv_val );
            ch_free( ci );
        }

The patch against OPENLDAP_STABLE could be downloaded from here:

ftp://ftp.openldap.org/incoming/daniel-pluta-090424.patch

This patch also includes the mini-enhancement proposed in ITS6072 and the
micro-bugfix provided in ITS6075. ITS6075 solves a small schema-specific bug
which wrongly denied deletion of single olcCollectInfo configuration values at
all.

Here are my 12 steps to reproduce the crash...


1.) edit collect's configuration setup in slapd.conf by adding the following
lines:
overlay collect
collectinfo ou=customer_A,dc=foo,dc=bar l,st
collectinfo ou=customer_B,dc=foo,dc=bar l,st
collectinfo ou=customer_C,dc=foo,dc=bar l,st
collectinfo ou=customer_D,dc=foo,dc=bar l,st
collectinfo ou=customer_E,dc=foo,dc=bar l,st
collectinfo ou=customer_F,dc=foo,dc=bar l,st
collectinfo ou=users,ou=customer_A,dc=foo,dc=bar l,st
collectinfo ou=users,ou=customer_B,dc=foo,dc=bar l,st
collectinfo ou=users,ou=customer_C,dc=foo,dc=bar l,st
collectinfo ou=users,ou=customer_D,dc=foo,dc=bar l,st
collectinfo ou=users,ou=customer_E,dc=foo,dc=bar l,st
collectinfo ou=users,ou=customer_F,dc=foo,dc=bar l,st

2.) convert ".conf" into "cn=config" format, by running: slaptest -f ... -F ...
The resulting collect cn=config ldif should be similar to:
dn: olcOverlay={0}collect
objectClass: olcOverlayConfig
objectClass: olcCollectConfig
olcOverlay: {0}collect
olcCollectInfo: "ou=users,ou=customer_f,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_e,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_d,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_c,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_b,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_a,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_f,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_e,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_d,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_c,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_b,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_a,dc=foo,dc=bar" l,st
structuralObjectClass: olcCollectConfig
entryUUID: 51c7d5fa-c50a-102d-9657-f3a43e5eeda2
creatorsName: cn=config
createTimestamp: 20090424105633Z
entryCSN: 20090424105633.913345Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20090424105633Z

3.) start slapd using the generated config (slapd -F ...)

4.) start browsing cn=config
everything is fine

5.) delete the follwing olcCollectInfo Value using this ldif:
dn: olcOverlay={0}collect,olcDatabase={2}bdb,cn=config
changetype: modify
delete: olcCollectInfo
olcCollectInfo: "ou=customer_a,dc=foo,dc=bar" l,st
-

6.) examine the log based on the above patch (which delivers the following
debugging output)
collect_cf: LDAP_MOD_DELETE: c->valx=11
collect_cf: LDAP_MOD_DELETE: i=0 <--> dn=ou=users,ou=customer_a,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=1 <--> dn=ou=users,ou=customer_b,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=2 <--> dn=ou=users,ou=customer_c,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=3 <--> dn=ou=users,ou=customer_d,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=4 <--> dn=ou=users,ou=customer_e,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=5 <--> dn=ou=users,ou=customer_f,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=6 <--> dn=ou=customer_a,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=7 <--> dn=ou=customer_b,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=8 <--> dn=ou=customer_c,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=9 <--> dn=ou=customer_d,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=10 <--> dn=ou=customer_e,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=11 <--> dn=ou=customer_f,dc=foo,dc=bar
collect_cf: free: dn=ou=customer_f,dc=foo,dc=bar

==> Holy sh..! ou=customer_f,dc=foo,dc=bar has been deleted, instead?!?!?!

7.) Though slapd still runs, lets ask about some more details using ldapsearch:
dn: olcoverlay={0}collect,olcdatabase={2}bdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcCollectConfig
olcCollectInfo: "ou=users,ou=customer_f,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_e,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_d,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_c,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_b,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=users,ou=customer_a,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_f,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_e,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_d,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_c,dc=foo,dc=bar" l,st
olcCollectInfo: "ou=customer_b,dc=foo,dc=bar" l,st
olcOverlay: {0}collect

==> Impressive! It seems to be that ou=customer_a,dc=foo,dc=bar has been
deleted(?!?!)


8.) ok, once again we try to delete a value:
dn: olcOverlay={0}collect,olcDatabase={2}bdb,cn=config
changetype: modify
delete: olcCollectInfo
olcCollectInfo: "ou=customer_e,dc=foo,dc=bar" l,st
-

9.) but the logging output tells us: "customer_b" gets deleted now...
collect_cf: LDAP_MOD_DELETE: c->valx=7
collect_cf: LDAP_MOD_DELETE: i=0 <--> dn=ou=users,ou=customer_a,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=1 <--> dn=ou=users,ou=customer_b,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=2 <--> dn=ou=users,ou=customer_c,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=3 <--> dn=ou=users,ou=customer_d,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=4 <--> dn=ou=users,ou=customer_e,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=5 <--> dn=ou=users,ou=customer_f,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=6 <--> dn=ou=customer_a,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: i=7 <--> dn=ou=customer_b,dc=foo,dc=bar
collect_cf: free: dn=ou=customer_b,dc=foo,dc=bar

10.) analog to point 7.) ldapsearch reports "customer_e" has been deleted...

11.) so far so good, now lets try to increase our level of fun and delete
another olcCollectInfo-value:
#!RESULT OK
#!CONNECTION ldap://10.111.1.1:3890
#!DATE 2009-04-24T11:36:18.343
dn: olcOverlay={0}collect,olcDatabase={2}bdb,cn=config
changetype: modify
delete: olcCollectInfo
olcCollectInfo: "ou=users,ou=customer_f,dc=foo,dc=bar" l,st
-

12.) slapd immediatly crashes, the logging output shows:
collect_cf: LDAP_MOD_DELETE: c->valx=0
collect_cf: LDAP_MOD_DELETE: i=0 <--> dn=ou=users,ou=customer_a,dc=foo,dc=bar
collect_cf: free: i=1 <--> dn=ou=users,ou=customer_a,dc=foo,dc=bar
collect_cf: LDAP_MOD_DELETE: c->valx=6
collect_cf: LDAP_MOD_DELETE: i=0 <--> dn=(null)

==> segfault, ZONK!


In my opinion it seems that the crash depends on the on-th-fly sorting of the
DN-list which directly depends on the timely order the DNs have been added
(processed by "insert_ordered()").

I'm not sure how to "fix" this bug providing an elegant solution because I don't
understand the direct/slapd-internal mapping of i to ci->cn_next in detail
(usually ldap results are unordered, perhabs something special regarding
back-config?). The problem seems to be located here:

              for ( i=0; i <= c->valx; i++, cip = &ci->ci_next )

These were my two first thoughts regarding a possible workaround:
- Always deleting and adding all values, in case one value gets modified?
- Using ordered-format "{n}" seems to result in "always delete / add all
values", too.

I would appreciate your advice!