[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
Re: (ITS#3388) Seg11 when used with pam_ldap under dtlogin
Will dig into the realloc call and try to figure that out. the
ber->ber_ptr==0x6 makes a lot more sense now...
Thanks.
- joel
On Nov 10, 2004, at 4:21 PM, Howard Chu wrote:
> Joel Boutros wrote:
>
>> Hi, Howard,
>>
>> I've tried to put this together to make it more clear what the
>> problem I'm seeing is... This is the call tree which results in the
>> bug. As things are pushed onto the stack, I indent. When it's done,
>> I un-indent. if something allocates, i mark it with a -->. I've
>> removed anything that isn't relevant to the problem at hand (ie,
>> assert()s, error checks, unrelated assignments, etc).
>>
>> If you've got alternatives or can explain why this isn't the cause of
>> the crash, please!, i'm very interested. I'd really like to get this
>> problem solved, so a refutal would tell me where i should look
>> instead. As it stands, this "feels" like an OpenLDAP issue.
>
> The fact is that ldap_build_search_req is always called by
> ldap_search, and if it was broken, every ldap search request would be
> crashing. Since ldapsearch works, and the entire OpenLDAP test suite
> works in any given release, the problem must be elsewhere.
>
>>
>> pam_ldap code
>> ldap_search_s
>> ldap_search
>> ldap_build_search_req
>> ldap_alloc_ber_with_options
>> ber_alloc_t
>> LBER_CALLOC --> ber
>> ber->valid = LBER_VALID_BERELEMENT;
>> ber->ber_tag = LBER_DEFAULT;
>> ber->ber_options = options;
>> ber->ber_debug = ber_int_debug;
>> LDAP_NEXT_MSGID
>> ber_printf(ld, "{it{seeiib", ...)
>> ber_start_seq
>> ber_start_seqorset
>> ber_mamcalloc_x --> new
>> 1 new->sos_first = ber->ber_ptr;
>> 1 new->sos_ptr = new->sos_first +
>> ber_calc_taglen(tag) + FOUR_BYTE_LEN;
>> ber->ber_sos = new
>> ber_put_int
>> ber_put_int_or_enum
>> ber_put_tag
>> ber_write
>> if ( nosos || ber->ber_sos ==
>> NULL ) { ber->ber_sos same as new above, so !NULL
>> 2 if ( ber->ber_ptr + len >
>> ber->ber_end ) { } ber->ber_ptr == 0, ber->ber_end == 0
>> 3 ber_realloc( ber, len )
>> }
>> AC_MEMCPY( ber->ber_ptr, buf,
>> (size_t)len );
>> ber->ber_ptr += len;
>>
>>
>>
>> The two lines marked (1) lines are the problem, as far as i can tell.
>> ber->ber_ptr is NULL. Nothing ever set it to non-NULL after the
>> calloc in ber_alloc_t. So new->sos_first is 0, ber_calc_taglen(tag)
>> == 1, and FOUR_BYTE_LEN == 5. new->sos_ptr becomes 0x6, and then we
>> dereference it in ber_write()'s memcpy (much later).
>>
>> It isn't clear what the results of (2) are, but it seems likely to
>> evaluate true, as ber->ber_ptr is 6, len is at least something, and
>> ber->ber_end is probably (never got set to anything else).
>
> 2 will always be TRUE since ber->ber_end is zero/NULL. ber_realloc
> will be called, which will realloc the ber->ber_buf. Since
> ber->ber_buf is still NULL at that point, this is semantically the
> same as a malloc.
>
>> ber->berber_realloc (3) is the only place that ber->ber_ptr can
>> possibly move. It getting moved depends on ber_memrealloc_x()
>> returning moved memory. It isn't clear how it really behaves here,
>> though -- if it moves at all, ber->ber_ptr = (ber->ber_buf +
>> (ber->ber_ptr - oldbuf)); when ber->ber_ptr is 0x6, and we're
>> subtracting oldbuf. We'll end up with total trash on ber->ber_ptr.
>> That's if it moves. If it doesn't, ber->ber_ptr continues to be 0x6,
>> which is what i've seen in the AC_MEMCPY() call.
>
>> Maybe this problem only comes up when ber_memrealloc_x() returns a
>> moved region. This would explain why i see it under dtlogin, but
>> don't usually see it otherwise. I have verified that ber->ber_ptr is
>> 0x6 at the point ber_printf() is called when debugging under a
>> working case, but haven't had a lot of luck identifying why it then
>> continues to work (my "working" test case involves time limits
>> because it's under login(1), and i just can't get to the call quickly
>> enough).
>
> Since the oldbuf was NULL, if ber_memrealloc_x succeeds then any
> returned memory counts as a moved region. At that point the ber_sos
> pointers are adjusted, and they are completely valid when ber_realloc
> returns. If ber_memrealloc_x fails then it will return a NULL pointer
> which will cause ber_realloc to return a failure code. That failure
> gets propagated back to the original caller.
>
>> Again, thanks for your time, I realize i'm being more irritating at
>> following this up than most people are. I'm just firmly convinced
>> i'm right, that this really is an OpenLDAP issue, as, so far, there's
>> something to suggest there's a different issue at-fault.
>
> I suggest you single-step through ber_realloc and see what is really
> happening.
>
> --
> -- Howard Chu
> Chief Architect, Symas Corp. Director, Highland Sun
> http://www.symas.com http://highlandsun.com/hyc
> Symas: Premier OpenSource Development and Support
>