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.