[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
(ITS#5853) LDAP search crashes when chasing multiple referrals
Full_Name: Jan Safranek
Version: 2.4.13
OS: Linux. Fedora 9, x86_64
URL: http://people.redhat.com/jsafrane/openldap-referral-crash/
Submission from: (NULL) (89.102.11.105)
Following ldapsearch crashes when referral chasing is enabled in very unusual
environment with many AD servers referring to each other (I had to increase
refhoplimit to chase all the referrals).
$ ldapsearch -x -C -D
cn=uzivatelk,ou=Services,ou=BOUDA,ou=administrace,dc=broken,dc=net -w
'mojeheslo' -b "dc=broken,dc=net" -h f9 "(sAMAccountName=uzivatel)"
ldapsearch: sockbuf.c:88: ber_sockbuf_ctrl: Assertion `sb != ((void *)0)'
failed.
You can find the stack trace below and ldapsearch -d -1 output at
http://people.redhat.com/jsafrane/openldap-referral-crash/, together with LDAP
traffic in pcap format.
IMO, if there are more referrals involved (A refers to B, which refers to C),
wait4msg() and try_read1msg() functions are called recursively several times.
When referral to C is being resolved, the stack looks like this:
1: try_read1msg
2: wait4msg
3: ldap_result
...
4: ldap_chase_v3referrals
5: try_read1msg
6: wait4msg
7: ldap_result
...
8: ldap_chase_v3referrals
9: try_read1msg
10: ldap_result
11: wait4msg
12: do_search
13: main
Looking at the wait4msg(), result.c:393, it goes through all connections inside
LDAP structure:
for ( lc = ld->ld_conns;
rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; )
{
if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
ldap_is_read_ready( ld, lc->lconn_sb ) )
{
<...mutexes...>
rc = try_read1msg( ld, msgid, all, &lc, result );
<...mutexes...>
if ( lc == NULL ) {
/* if lc gets free()'d,
* there's no guarantee
* lc->lconn_next is still
* sane; better restart
* (ITS#4405) */
lc = ld->ld_conns;
/* don't get to next conn! */
break;
}
}
/* next conn */
lc = lc->lconn_next;
}
And try_read1msg() can release the connection and change the list of
connections, see result.c:944:
ldap_free_connection( ld, lc, 0, 1 );
<...mutexes...>
lc = *lcp = NULL;
The calling wait4msg() expects that called try_read1msg() may free a connection
and does not crash. But if more wait4msg() are called recursively, the "bottom
ones", #6 and #11 in my stack example above, do not know about the change which
try_read1msg() in #1 has made and can hold already freed 'lc' pointer -> crash.
IMHO there should be some other check, that ensures that wait4msg() restarts the
loop even if some inner try_read1msg() modifies the list. Or there could be some
ldap_use_connecion() in try_read1msg() when referrals are being chased, so the
connection does get freed only by the right try_read1msg() - #5 in my case and
not #1. However, my knowledge of OpenLDAP internals is somewhat limited and I am
not able to tell which way is the best.
It's quite hard to reproduce the bug, the packets must arrive in the right
order, so the connection to B is being freed when referral to C is being chased.
I am not able to reproduce it in more controlled environment, the log is quite
huge and it contains some other not so interesting referrals. The connection,
which is freed too early, is connection to 'sec.broken.net' - look for the last
'ldap_free_connection: actually freed' in the log.
I hope my explanation above is somewhat readable and I didn't confuse you too
much :). Do not hesitate to ask for specific details.
Here is the promised real stack trace. It asserts when the 'lc' in wait4msg()
has been freed by previous call to try_read1msg.
(gdb) bt full
#0 0x0000003b49632215 in raise () from /lib64/libc.so.6
No symbol table info available.
#1 0x0000003b49633d83 in abort () from /lib64/libc.so.6
No symbol table info available.
#2 0x0000003b4962b039 in __assert_fail () from /lib64/libc.so.6
No symbol table info available.
#3 0x000000000044d4b1 in ber_sockbuf_ctrl (sb=0x0, opt=8, arg=0x0) at
sockbuf.c:88
p = (Sockbuf_IO_Desc *) 0x452f65
ret = 0
__PRETTY_FUNCTION__ = "ber_sockbuf_ctrl"
#4 0x0000000000416222 in try_read1msg (ld=0x1b80fa0, msgid=18, all=1,
lcp=0x7fffe4f67ae8, result=0x7fffe4f67be8) at result.c:1190
ber = (BerElement *) 0x1b8c040
newmsg = (LDAPMessage *) 0x1b91ca0
l = (LDAPMessage *) 0x0
prev = (LDAPMessage *) 0x1b8d370
id = 2
idx = 0
tag = 115
len = 78
foundit = 0
lr = (LDAPRequest *) 0x0
tmplr = (LDAPRequest *) 0x1b8d220
dummy_lr = {lr_msgid = 0, lr_status = 0, lr_refcnt = 0, lr_outrefcnt = 0,
lr_abandoned = 0, lr_origid = 0, lr_parentcnt = 0,
lr_res_msgtype = 0, lr_res_errno = 0, lr_res_error = 0x0, lr_res_matched =
0x0, lr_ber = 0x0, lr_conn = 0x0, lr_dn = {bv_len = 0, bv_val = 0x0},
lr_parent = 0x0, lr_child = 0x0, lr_refnext = 0x0, lr_prev = 0x0, lr_next =
0x0}
lc = (LDAPConn *) 0x1b8e3e0
tmpber = {ber_opts = {lbo_valid = 2, lbo_options = 1, lbo_debug = -1}, ber_tag
= 0, ber_len = 87, ber_usertag = 0,
ber_buf = 0x1b8c0a0 "\002\001\005s\204", ber_ptr = 0x1b8c0f7 "", ber_end =
0x1b8c0f7 "", ber_sos = 0x0, ber_rwptr = 0x0, ber_memctx = 0x0}
rc = -2
refer_cnt = 1
hadref = 1
simple_request = 0
err = 5
lderr = 1
__PRETTY_FUNCTION__ = "try_read1msg"
bv_nod = {bv_len = 22, bv_val = 0x452b0b "1.3.6.1.4.1.1466.20036"}
#5 0x0000000000414c67 in wait4msg (ld=0x1b80fa0, msgid=18, all=1,
timeout=0x7fffe4f67bf0, result=0x7fffe4f67be8) at result.c:402
err = 0
lc_ready = 0
rc = -2
tv = {tv_sec = 0, tv_usec = 100000}
tv0 = {tv_sec = 0, tv_usec = 100000}
start_time_tv = {tv_sec = 1228828417, tv_usec = 878311}
tvp = (struct timeval *) 0x7fffe4f67b10
lc = (LDAPConn *) 0x1b8e3e0
__PRETTY_FUNCTION__ = "wait4msg"
#6 0x0000000000414433 in ldap_result (ld=0x1b80fa0, msgid=18, all=1,
timeout=0x7fffe4f67bf0, result=0x7fffe4f67be8) at result.c:127
lm = (LDAPMessage *) 0x0
rc = 18
__PRETTY_FUNCTION__ = "ldap_result"
#7 0x0000000000428313 in ldap_new_connection (ld=0x1b80fa0,
srvlist=0x7fffe4f67df0, use_ldsb=0, connect=1, bind=0x7fffe4f67dc0) at
request.c:560
tv = {tv_sec = 0, tv_usec = 100000}
res = (LDAPMessage *) 0x0
msgid = 18
rc = 0
passwd = {bv_len = 0, bv_val = 0x0}
err = 1
savedefconn = (LDAPConn *) 0x1b8a380
lc = (LDAPConn *) 0x1b8c690
async = 0
__PRETTY_FUNCTION__ = "ldap_new_connection"
---Type <return> to continue, or q <return> to quit---
#8 0x00000000004276b5 in ldap_send_server_request (ld=0x1b80fa0, ber=0x1b8d290,
msgid=17, parentreq=0x1b8a6e0, srvlist=0x7fffe4f67df0, lc=0x0,
bind=0x7fffe4f67dc0) at request.c:207
lr = (LDAPRequest *) 0x1b8d290
incparent = 1
rc = 389
#9 0x0000000000429be6 in ldap_chase_v3referrals (ld=0x1b80fa0, lr=0x1b8cb40,
refs=0x0, sref=1, errstrp=0x1b8cb70, hadrefp=0x7fffe4f67f2c)
at request.c:1209
unfollowed = 0x0
unfollowedcnt = 0
origreq = (LDAPRequest *) 0x1b8a6e0
srv = (LDAPURLDesc *) 0x1b8c7b0
ber = (BerElement *) 0x1b8d290
refarray = (char **) 0x1b8c670
lc = (LDAPConn *) 0x0
rc = 0
count = 0
i = 0
j = 0
id = 17
rinfo = {ri_msgid = 2, ri_request = 99, ri_url = 0x1b91c30
"ldap://DomainDnsZones.sec.broken.net/DC=DomainDnsZones,DC=sec,DC=broken,DC=net"}
#10 0x000000000041553d in try_read1msg (ld=0x1b80fa0, msgid=-1, all=0,
lcp=0x7fffe4f680e8, result=0x7fffe4f68228) at result.c:729
refs = (char **) 0x1b8c670
ber = (BerElement *) 0x1b8ae00
newmsg = (LDAPMessage *) 0x0
l = (LDAPMessage *) 0x1e4f68080
prev = (LDAPMessage *) 0x7fffe4f68080
id = 2
idx = 0
tag = 115
len = 80
foundit = 0
lr = (LDAPRequest *) 0x1b8cb40
tmplr = (LDAPRequest *) 0x1b8a550
dummy_lr = {lr_msgid = 0, lr_status = 0, lr_refcnt = 0, lr_outrefcnt = 0,
lr_abandoned = 0, lr_origid = 0, lr_parentcnt = 0,
lr_res_msgtype = 0, lr_res_errno = 0, lr_res_error = 0x0, lr_res_matched =
0x0, lr_ber = 0x0, lr_conn = 0x0, lr_dn = {bv_len = 0, bv_val = 0x0},
lr_parent = 0x0, lr_child = 0x0, lr_refnext = 0x0, lr_prev = 0x0, lr_next =
0x0}
lc = (LDAPConn *) 0x1b8beb0
tmpber = {ber_opts = {lbo_valid = 2, lbo_options = 1, lbo_debug = -1}, ber_tag
= 0, ber_len = 89, ber_usertag = 0,
ber_buf = 0x1b8c600 "\002\001\003s\204", ber_ptr = 0x1b8c659 "", ber_end =
0x1b8c659 "", ber_sos = 0x0, ber_rwptr = 0x0, ber_memctx = 0x0}
rc = -2
refer_cnt = 0
hadref = 0
simple_request = 0
err = 4
lderr = 1
__PRETTY_FUNCTION__ = "try_read1msg"
bv_nod = {bv_len = 22, bv_val = 0x452b0b "1.3.6.1.4.1.1466.20036"}
#11 0x0000000000414c67 in wait4msg (ld=0x1b80fa0, msgid=-1, all=0, timeout=0x0,
result=0x7fffe4f68228) at result.c:402
err = 0
lc_ready = 0
rc = -2
tv = {tv_sec = 0, tv_usec = 0}
tv0 = {tv_sec = 0, tv_usec = 0}
start_time_tv = {tv_sec = 0, tv_usec = 0}
tvp = (struct timeval *) 0x0
lc = (LDAPConn *) 0x1b8beb0
__PRETTY_FUNCTION__ = "wait4msg"
#12 0x0000000000414433 in ldap_result (ld=0x1b80fa0, msgid=-1, all=0,
timeout=0x0, result=0x7fffe4f68228) at result.c:127
lm = (LDAPMessage *) 0x0
rc = 100
__PRETTY_FUNCTION__ = "ldap_result"
---Type <return> to continue, or q <return> to quit---
#13 0x0000000000408dbf in dosearch (ld=0x1b80fa0, base=0x1b7f5e0
"dc=broken,dc=net", scope=2, filtpatt=0x0,
value=0x7fffe4f6b881 "(sAMAccountName=uzivatel)", attrs=0x0, attrsonly=0,
sctrls=0x0, cctrls=0x0, timeout=0x0, sizelimit=-1) at ldapsearch.c:1280
filter = 0x7fffe4f6b881 "(sAMAccountName=uzivatel)"
rc = 0
nresponses = 7
nentries = 1
nreferences = 6
nextended = 0
npartial = 0
res = (LDAPMessage *) 0x0
msg = (LDAPMessage *) 0x0
msgid = 2
retoid = 0x0
retdata = (struct berval *) 0x0
nresponses_psearch = -1
cancel_msgid = -1
#14 0x00000000004084cc in main (argc=14, argv=0x7fffe4f6a4f8) at
ldapsearch.c:1112
filtpattern = 0x7fffe4f6b881 "(sAMAccountName=uzivatel)"
attrs = (char **) 0x0
line = '\0' <repeats 1344 times>,
"\006\000\000\000\000\000\000\000\200\220öäÿ\177\000\000\220\220öäÿ\177\000\000\231C!J;\000\000\000\237C!J;\000\000\000\023pdI;",
'\0' <repeats 47 times>,
"º\005\000\000\004\000\000\000\000\000\000\000à\220öäÿ\177\000\000ð\220öäÿ\177\000\000ÔB!J;\000\000\000ØB!J;\000\000\000\023pdI;",
'\0' <repeats 47 times>, "º\005\000\000X\220öäÿ\177\000\000x\220öäÿ\177\000\000
\220öäÿ\177\000\000p\220öäÿ\177\000\000Ð\213öäÿ\177", '\0' <repeats 18 times>,
"\205ç Iøÿÿÿ\000\000\000\000\000\000\000\000èÔAI;\000\000\000"...
fp = (FILE *) 0x0
rc = 4213523
rc1 = 0
i = 0
first = 32767
ld = (LDAP *) 0x1b80fa0
seber = (BerElement *) 0x0
vrber = (BerElement *) 0x0
syncber = (BerElement *) 0x0
syncbvalp = (struct berval *) 0x0
err = 4216832
(gdb)