[syslog-ng]syslog-ng-1.4.17 crashes

Balazs Scheidler bazsi@balabit.hu
Tue, 19 Nov 2002 18:14:58 +0100


On Fri, Nov 15, 2002 at 10:24:24AM +0100, Balazs Scheidler wrote:
> On Thu, Nov 14, 2002 at 07:49:00PM +0100, Heinz Ekker wrote:
> > On Thu, Nov 14, 2002 at 06:07:02PM +0100, Balazs Scheidler wrote:
> 
> hmm.. as it seems the length c_format() wants to allocate is 0xcedfcc21
> bytes, cca 3.5GB, somehow the log entry to be written is completely bogus.
> 
> do_flush() calls c_format with a format "%s", string length 0xcedfcc12 and
> data pointer 0x3927911d, if the allocation would succeed, syslog-ng would
> crash anyway, when trying to dereference 0x3927911d.
> 
> The funny thing is that A_WRITE() is called with exactly these parameters,
> and it didn't crash, so something changed the data between A_WRITE() and
> c_format().
> 
> Can you send me your syslog-ng binary and the core file in private? Maybe I
> can do some more analyisis. (I hope core files don't depend on libc version,
> or if they do, it would still show some valid data)

I'm finished with my analysis.

First of all you have linked syslog-ng 1.4 against libol 0.3. This is _not_
recommended (and can only be done by patching syslog-ng configure script)

I've checked out why the whole thing might have crashed anyway, but there
were no obvious reasons. One of the local variables (move) in the do_flush()
function contains a bogus value. I've tried to reproduce it with syslog-ng
1.5 without success.

The disassembly of your do_flush function shows (at least to me and I was
watching it quite a lot) that you might have compiled libol with a buggy
compiler. I might be wrong, but the memory slot referenced when calling
c_format() is not initialized by the assembly function in any way (it
is but in a later part of the function), but it is initialized by the C
code.

Don't you happen to be using the buggy gcc 2.96 release from RedHat?

The relevant part is:

; if (item->packet->length != move)
0x80534e6 <do_flush+94>:	je     0x8053510 <do_flush+136>
;;  not equal
0x80534e8 <do_flush+96>:	push   %ecx
;; ecx := move, this slot is used for the local variable res as well!
0x80534e9 <do_flush+97>:	mov    0xffffefdc(%ebp),%ecx
;; offset into the string (s->data + move)
0x80534ef <do_flush+103>:	lea    0xc(%ecx,%esi,1),%eax
0x80534f3 <do_flush+107>:	push   %eax
;; calculate (s->length - move), $ecx is move, $edx is s->length
0x80534f4 <do_flush+108>:	sub    %ecx,%edx
0x80534f6 <do_flush+110>:	push   %edx
;; format string ("%s")
0x80534f7 <do_flush+111>:	push   $0x80540bd
0x80534fc <do_flush+116>:	call   0x8050670 <c_format>


as you can see the local variable $ebp+0xffffefdc is stored in $ecx as the
value of the local variable 'move', and $ebp+0xffffefdc gets its first value
outside the FOR_QUEUE loop. The funny thing is that this same slot is used
for the local variable res as well, as the return value of A_WRITE is
stored there.

Here's a full disassembly of the do_flush function, annotated with my comments:

(gdb) disassemble do_flush
Dump of assembler code for function do_flush:
0x8053488 <do_flush>:	push   %ebp
0x8053489 <do_flush+1>:	mov    %esp,%ebp
0x805348b <do_flush+3>:	push   %edi
0x805348c <do_flush+4>:	push   %esi
0x805348d <do_flush+5>:	push   %ebx
0x805348e <do_flush+6>:	sub    $0x1024,%esp
0x8053494 <do_flush+12>:	pushl  0x8(%ebp)
0x8053497 <do_flush+15>:	push   $0x8058e00
0x805349c <do_flush+20>:	call   0x8053250 <ol_object_check>
0x80534a1 <do_flush+25>:	mov    %eax,0xffffefe4(%ebp)
0x80534a7 <do_flush+31>:	movl   $0x0,0xffffefe0(%ebp)
0x80534b1 <do_flush+41>:	mov    0x28(%eax),%edi
0x80534b4 <do_flush+44>:	add    $0x10,%esp
; jump to check the condition
0x80534b7 <do_flush+47>:	jmp    0x805353c <do_flush+180>
; body of for loop starts here (FOR_QUEUE)
0x80534bc <do_flush+52>:	push   %esi
0x80534bd <do_flush+53>:	push   %ebx
0x80534be <do_flush+54>:	add    $0xc,%eax
0x80534c1 <do_flush+57>:	mov    0xffffefe0(%ebp),%ecx
0x80534c7 <do_flush+63>:	lea    0xffffefe8(%ecx,%ebp,1),%edx
0x80534ce <do_flush+70>:	push   %eax
0x80534cf <do_flush+71>:	push   %edx
0x80534d0 <do_flush+72>:	call   0x8049688 <memcpy>
0x80534d5 <do_flush+77>:	add    %ebx,0xffffefe0(%ebp)
0x80534db <do_flush+83>:	mov    0x8(%edi),%esi
0x80534de <do_flush+86>:	mov    0x8(%esi),%edx
0x80534e1 <do_flush+89>:	add    $0x10,%esp
0x80534e4 <do_flush+92>:	cmp    %ebx,%edx
; if (item->packet->length != move)
0x80534e6 <do_flush+94>:	je     0x8053510 <do_flush+136>
;;  not equal
0x80534e8 <do_flush+96>:	push   %ecx
;; ecx := move, this slot is used for the local variable res as well!
0x80534e9 <do_flush+97>:	mov    0xffffefdc(%ebp),%ecx
;; offset into the string (s->data + move)
0x80534ef <do_flush+103>:	lea    0xc(%ecx,%esi,1),%eax
0x80534f3 <do_flush+107>:	push   %eax
;; calculate (s->length - move), $ecx is move, $edx is s->length
0x80534f4 <do_flush+108>:	sub    %ecx,%edx
0x80534f6 <do_flush+110>:	push   %edx
;; format string ("%s")
0x80534f7 <do_flush+111>:	push   $0x80540bd
0x80534fc <do_flush+116>:	call   0x8050670 <c_format>
0x8053501 <do_flush+121>:	mov    %eax,0x8(%edi)
0x8053504 <do_flush+124>:	mov    %esi,(%esp,1)
0x8053507 <do_flush+127>:	call   0x805320c <ol_string_free>
0x805350c <do_flush+132>:	jmp    0x8053533 <do_flush+171>
0x805350e <do_flush+134>:	mov    %esi,%esi
;; equal (item->packet->length == move)
0x8053510 <do_flush+136>:	mov    0xffffefe4(%ebp),%eax
0x8053516 <do_flush+142>:	decl   0x38(%eax)
0x8053519 <do_flush+145>:	sub    $0xc,%esp
0x805351c <do_flush+148>:	push   %edi
0x805351d <do_flush+149>:	call   0x8052a74 <ol_queue_remove>
0x8053522 <do_flush+154>:	pop    %eax
0x8053523 <do_flush+155>:	pushl  0x8(%edi)
0x8053526 <do_flush+158>:	call   0x805320c <ol_string_free>
0x805352b <do_flush+163>:	mov    %edi,(%esp,1)
0x805352e <do_flush+166>:	call   0x805334c <ol_space_free>
0x8053533 <do_flush+171>:	add    $0x10,%esp
0x8053536 <do_flush+174>:	mov    0xffffefd8(%ebp),%edi
; check for condition (FOR_QUEUE)
0x805353c <do_flush+180>:	mov    (%edi),%eax
0x805353e <do_flush+182>:	test   %eax,%eax
0x8053540 <do_flush+184>:	mov    %eax,0xffffefd8(%ebp)
0x8053546 <do_flush+190>:	je     0x8053567 <do_flush+223>
; edx := 4096 (sizeof(buf))
0x8053548 <do_flush+192>:	mov    $0x1000,%edx
; eax := item->packet->length
0x805354d <do_flush+197>:	mov    0x8(%edi),%eax
; 
0x8053550 <do_flush+200>:	sub    0xffffefe0(%ebp),%edx
0x8053556 <do_flush+206>:	mov    0x8(%eax),%ebx
0x8053559 <do_flush+209>:	cmp    %edx,%ebx
0x805355b <do_flush+211>:	jbe    0x805355f <do_flush+215>
0x805355d <do_flush+213>:	mov    %edx,%ebx
0x805355f <do_flush+215>:	test   %edx,%edx
0x8053561 <do_flush+217>:	jne    0x80534bc <do_flush+52>
; end of FOR_QUEUE loop
0x8053567 <do_flush+223>:	push   %esi
0x8053568 <do_flush+224>:	lea    0xffffefe8(%ebp),%esi
0x805356e <do_flush+230>:	push   %esi
0x805356f <do_flush+231>:	pushl  0xffffefe0(%ebp)
0x8053575 <do_flush+237>:	pushl  0xc(%ebp)
0x8053578 <do_flush+240>:	mov    0xc(%ebp),%edx
; call to A_WRITE
0x805357b <do_flush+243>:	call   *0xc(%edx)
0x805357e <do_flush+246>:	add    $0x10,%esp
0x8053581 <do_flush+249>:	test   %eax,%eax
; move := eax
0x8053583 <do_flush+251>:	mov    %eax,0xffffefdc(%ebp)
0x8053589 <do_flush+257>:	js     0x8053628 <do_flush+416>
0x805358f <do_flush+263>:	cmp    %eax,0xffffefe0(%ebp)
0x8053595 <do_flush+269>:	jne    0x80535b4 <do_flush+300>
0x8053597 <do_flush+271>:	mov    0xffffefe4(%ebp),%ecx
0x805359d <do_flush+277>:	mov    0x14(%ecx),%eax
0x80535a0 <do_flush+280>:	test   %eax,%eax
0x80535a2 <do_flush+282>:	je     0x805363c <do_flush+436>
0x80535a8 <do_flush+288>:	movl   $0x1,(%eax)
0x80535ae <do_flush+294>:	jmp    0x805363c <do_flush+436>
0x80535b3 <do_flush+299>:	nop    
0x80535b4 <do_flush+300>:	mov    0xffffefdc(%ebp),%ebx
0x80535ba <do_flush+306>:	test   %ebx,%ebx
0x80535bc <do_flush+308>:	je     0x805363c <do_flush+436>
0x80535be <do_flush+310>:	sub    $0xc,%esp
0x80535c1 <do_flush+313>:	push   $0xc
0x80535c3 <do_flush+315>:	call   0x805332c <ol_space_alloc>
0x80535c8 <do_flush+320>:	mov    0xffffefdc(%ebp),%edx
0x80535ce <do_flush+326>:	add    $0xc,%esp
0x80535d1 <do_flush+329>:	mov    %eax,%ebx
0x80535d3 <do_flush+331>:	lea    (%edx,%esi,1),%eax
0x80535d6 <do_flush+334>:	push   %eax
0x80535d7 <do_flush+335>:	sub    %edx,0xffffefe0(%ebp)
0x80535dd <do_flush+341>:	pushl  0xffffefe0(%ebp)
0x80535e3 <do_flush+347>:	push   $0x80540bd
0x80535e8 <do_flush+352>:	call   0x8050670 <c_format>
0x80535ed <do_flush+357>:	mov    %eax,0x8(%ebx)
0x80535f0 <do_flush+360>:	pop    %edx
0x80535f1 <do_flush+361>:	pop    %ecx
0x80535f2 <do_flush+362>:	mov    0xffffefe4(%ebp),%eax
0x80535f8 <do_flush+368>:	add    $0x28,%eax
0x80535fb <do_flush+371>:	push   %ebx
0x80535fc <do_flush+372>:	push   %eax
0x80535fd <do_flush+373>:	call   0x8052a38 <ol_queue_add_head>
0x8053602 <do_flush+378>:	mov    0xffffefe4(%ebp),%ecx
0x8053608 <do_flush+384>:	mov    0x38(%ecx),%eax
0x805360b <do_flush+387>:	inc    %eax
0x805360c <do_flush+388>:	add    $0x10,%esp
0x805360f <do_flush+391>:	cmp    0x3c(%ecx),%eax
0x8053612 <do_flush+394>:	mov    %eax,0x38(%ecx)
0x8053615 <do_flush+397>:	jne    0x805363c <do_flush+436>
0x8053617 <do_flush+399>:	mov    0x14(%ecx),%eax
0x805361a <do_flush+402>:	test   %eax,%eax
0x805361c <do_flush+404>:	je     0x805363c <do_flush+436>
0x805361e <do_flush+406>:	movl   $0x0,(%eax)
0x8053624 <do_flush+412>:	jmp    0x805363c <do_flush+436>
0x8053626 <do_flush+414>:	mov    %esi,%esi
0x8053628 <do_flush+416>:	sub    $0xc,%esp
0x805362b <do_flush+419>:	push   $0x8057c20
0x8053630 <do_flush+424>:	call   0x805293c <werror>
0x8053635 <do_flush+429>:	mov    $0x4,%eax
0x805363a <do_flush+434>:	jmp    0x805363e <do_flush+438>
0x805363c <do_flush+436>:	xor    %eax,%eax
0x805363e <do_flush+438>:	lea    0xfffffff4(%ebp),%esp
0x8053641 <do_flush+441>:	pop    %ebx
0x8053642 <do_flush+442>:	pop    %esi
0x8053643 <do_flush+443>:	pop    %edi
0x8053644 <do_flush+444>:	pop    %ebp
0x8053645 <do_flush+445>:	ret    
0x8053646 <do_flush+446>:	mov    %esi,%esi
End of assembler dump.


-- 
Bazsi
PGP info: KeyID 9AF8D0A9 Fingerprint CD27 CFB0 802C 0944 9CFD 804E C82C 8EB1