[exim-dev] [Bug 2296] New: Crash when > 1 address redirectio…

Top Page
Delete this message
Reply to this message
Author: admin
Date:  
To: exim-dev
Subject: [exim-dev] [Bug 2296] New: Crash when > 1 address redirections used with cutthrough
https://bugs.exim.org/show_bug.cgi?id=2296

            Bug ID: 2296
           Summary: Crash when > 1 address redirections used with
                    cutthrough
           Product: Exim
           Version: 4.90
          Hardware: x86
                OS: Linux
            Status: NEW
          Severity: bug
          Priority: medium
         Component: Transports
          Assignee: nigel@???
          Reporter: tstewart@???
                CC: exim-dev@???


Created attachment 1095
--> https://bugs.exim.org/attachment.cgi?id=1095&action=edit
GDB command file

Exim will crash (or merely log bogus data, if lucky) when an message
follows 2 or more address redirections and cutthrough is enabled.

There is an automatic variable `struct address_item addr2' in
open_cutthrough_connection() whose address makes its way to
cutthrough.addr->parent->parent when more than one redirection is
used. There is code at verify.c:1099 that copies the first-level
address_item struct to newly-allocated memory, but the copied data has
its own parent pointer that points to addr2 within the stack.

Later, cutthrough_finaldot() calls delivery_log() to log the delivery.
delivery_log() calls string_log_address(), which traverses the parent
pointers and dereferences the address fields in each, the last of
which has long been overwritten by other stack frames. This will
either crash (like it did for us in production) or log bogus data
(like it did for me when creating the test case for this bug report).

If Exim survives, the bogus log entry looks like (imagine actual
binary data instead of the string RANDOM_MEMORY):

2018-08-08 17:15:50 1fnVo6-0001yw-F9 >> user3@??? <RANDOM_MEMORY>
R=next_hop T=smtp H=localhost [127.0.0.1] C="250 Ok"

I did a lot of investigation in GDB while finding the cause of the
crash, so I've collected my steps below into a gdb command file
(attached) to help pinpoint the bug. Also, I've worked around the bug
locally by only using one level of redirection in my /etc/aliases
file.


TO REPRODUCE
------------

The following was performed at commit
6a012214711def1133383366a0ddf7337eb0efa0, which was the HEAD of master
as of this writing.

Build the code, disabling optimizations and adding debug information:

make FULLECHO='' CFLAGS="-g -O0"
make install

Set up the following /etc/aliases file:

user1: user2
user2: user3

Set up the following acl and router entries:


begin acl

acl_check_rcpt:
  require
    control = cutthrough_delivery


accept

begin routers

system_aliases:
driver = redirect
allow_fail
allow_defer
data = ${lookup{$local_part}lsearch{/etc/aliases}}
#user = mailnull
group = mail
file_transport = address_file
pipe_transport = address_pipe

next_hop:
driver = manualroute
local_parts = user1 : user2 : user3
domains = +local_domains
transport = smtp
route_list = * localhost::2526 byname
self = send
hosts_randomize = true


Start newly-built exim in daemon mode:

exim -bd

I also ran Python's DebuggingServer to accept all messages sent by the
next_hop router:

python -msmtpd -n -c DebuggingServer 127.0.0.1:2526

Find the daemon's PID and attach GDB, loading the GDB command file
attached to this bug:

gdb -x path/to/exim.gdbcmd -p PID

This will set up some breakpoints and automatically continue. I used
msmtp locally to send through a message:


msmtp --host localhost --from user1@??? user1@??? <<EOF
Subject: Testing

Testing
EOF


As soon as msmtp sends GDB will stop and display some details. Use
`cont' to keep going. GDB will stop at the following places:

- verify.c:1209 :: Displays the address of addr2

- verify.c:1098 :: Displays the following before the shallow copy:
    cutthrough.addr->parent
    cutthrough.addr->parent->address
    cutthrough.addr->parent->parent
    cutthrough.addr->parent->parent->address


Note that cutthrough.addr->parent->parent is equal to &addr2 above.

- verify.c:1101 :: Same as above, but after the shallow copy.
cutthrough.addr->parent->parent is still the same as &addr2, though
cutthrough.addr->parent is now different due to the copy.

- cutthrough_finaldot() :: Same as above, to demonstrate that
cutthrough.addr->parent->parent is now corrupt.


There is also some commented code in exim.gdbcmd that lets you watch
cutthrough.addr->parent->parent get overwritten as the stack changes.

--
You are receiving this mail because:
You are on the CC list for the bug.