Alex W created SERF-195:
---------------------------
Summary: [PATCH] time-consuming operations in auth_ module leads
to memory corruption
Key: SERF-195
URL: https://issues.apache.org/jira/browse/SERF-195
Project: serf
Issue Type: Bug
Affects Versions: serf-1.4.0, serf-trunk
Reporter: Alex W
Attachments: linked-list-fix.patch
In serf trunk and 1.4.x, doing time-consuming operations in an auth module's
"setup" function can lead to memory corruption and crashes. I strongly suspect
this can be triggered in other ways as well, if they can lead to delayed
requests, timeouts or errors on the server, etc. You can easily reproduce this
(pretty reliably) by making a change such as:
{noformat}
diff a/auth/auth_basic.c b/auth/auth_basic.c
--- a/auth/auth_basic.c
+++ b/auth/auth_basic.c
@@ -169,6 +169,7 @@ serf__setup_request_basic_auth(const serf__authn_scheme_t
*scheme,
basic_info = authn_info->baton;
if (basic_info && basic_info->header && basic_info->value) {
+ usleep(75000);
serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
basic_info->value);
return APR_SUCCESS;
{noformat}
And then using serf via e.g. {{svn co}} of a large repository.
The crash which occurs results from the {{written_reqs}} and {{unwritten_reqs}}
lists on the {{serf_connection_t}} containing invalid pointers. Generally,
since the memory is pooled, we don't notice the corruption until teardown time.
If you run with pool debugging and valgrind you can eventually narrow down the
cause to the linked lists.
Several places which manipulate the linked lists are suspicious, e.g. this
section in {{outgoing.c}}:
{noformat}
serf__link_requests(&conn->written_reqs, &conn->written_reqs_tail,
request);
conn->nr_of_written_reqs++;
conn->unwritten_reqs = conn->unwritten_reqs->next;
conn->nr_of_unwritten_reqs--;
request->next = NULL;
{noformat}
This assumes (but never checks) that the request in question is at the front of
the {{unwritten_reqs}} list, which can be violated in both error cases and in
cases of aborted requests. The ordering of operations here (link the request
onto the new list, then unlink it from the old one) should also make a reader
pretty suspicious, though in this particular case it shouldn't be a problem
(since {{serf__link_requests}} doesn't actually change the {{next}} pointer).
There are also other sections of linked list code too which are a little
questionable.
I'm attaching a patch which reorganises the {{written_reqs}} and
{{unwritten_reqs}} lists into their own structs and provides higher-level
functions for manipulating them. These also add assertions to make sure that
the correct list is being used. I also check conditions in places such as this
section of {{outgoing.c}} for other error cases. After these changes I can no
longer reproduce the incorrect free() or other crashes with a slow auth plugin.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)