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!