Skip to content

Commit ba67c74

Browse files
Add runtime detection for case where new request_rec fields are back ported to older Apache version. Also pad out request_rec and set fields for case where mod_wsgi is compiled against older Apache, so doesn't crash when Apache upgraded but mod_wsgi not recompiled.
1 parent 808e966 commit ba67c74

2 files changed

Lines changed: 132 additions & 18 deletions

File tree

docs/release-notes/version-4.4.6.rst

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,35 @@ Bugs Fixed
1717
structure ``request_rec`` due to CVE-2013-5704. The addition of these
1818
fields will cause versions of mod_wsgi from 4.4.0-4.4.5 to crash when used
1919
in mod_wsgi daemon mode and mod_wsgi isn't initialising the new structure
20-
members. If updating to those Apache versions or newer, you must update
21-
to mod_wsgi version 4.4.6 or newer. The mod_wsgi source code must have also
22-
been compiled against the newer Apache version. You cannot compile mod_wsgi
23-
version 4.4.6 source code against an older Apache version and then upgrade
24-
Apache to the newer versions as initialising of the new structure members
25-
will not have been compiled in as whether it is done is dependent on the
26-
version of Apache being used at compile time.
20+
members.
21+
22+
If you are upgrading your Apache installation to those versions or later
23+
versions, you must also update to mod_wsgi version 4.4.6. The mod_wsgi
24+
4.4.6 source code must have also been compiled against the newer Apache
25+
version.
26+
27+
In recompiling mod_wsgi 4.4.6 source code against the newer Apache versions
28+
the source code is able to detect the new fields exist at compile time by
29+
checking a compile time version number.
30+
31+
One problem that can arise is that where a CVE is raised for a security
32+
issue, Linux distributions will back port the change to older Apache
33+
versions. When they do this though, the compile time version number isn't
34+
changed, so mod_wsgi cannot detect at compile time when built against
35+
Apache versions with the backport that the additional fields exist.
36+
37+
To combat this problem, mod_wsgi will do some runtime checks which look at
38+
the actual size of ``request_rec`` and calculate whether the additional
39+
fields have been added by way of a backported change. In this case mod_wsgi
40+
will then set the fields as necessary.
41+
42+
As a final fail safe for forward compatibility. If the current mod_wsgi
43+
source code is compiled against a version of Apache which doesn't have the
44+
CVE change applied, it will pad the ``request_rec`` and optimistically set
45+
the fields anyway. This is to deal with the situation where mod_wsgi is
46+
compiled against an older Apache and then that Apache is upgraded to one
47+
with the CVE change, but mod_wsgi is not recompiled so that the additional
48+
fields can be detected at compile time.
2749

2850
2. Override ``LC_ALL`` environment variable when ``locale`` option to the
2951
``WSGIDaemonProcess`` directive. It is not always sufficient to just call

src/server/mod_wsgi.c

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11372,6 +11372,27 @@ static apr_status_t wsgi_header_filter(ap_filter_t *f, apr_bucket_brigade *b)
1137211372
return ap_pass_brigade(f->next, b);
1137311373
}
1137411374

11375+
typedef struct cve_2013_5704_fields cve_2013_5704_fields;
11376+
typedef struct cve_2013_5704_apache22 cve_2013_5704_apache22;
11377+
typedef struct cve_2013_5704_apache24 cve_2013_5704_apache24;
11378+
11379+
struct cve_2013_5704_fields {
11380+
apr_table_t *trailers_in;
11381+
apr_table_t *trailers_out;
11382+
};
11383+
11384+
struct cve_2013_5704_apache22 {
11385+
struct ap_filter_t *proto_input_filters;
11386+
int eos_sent;
11387+
cve_2013_5704_fields fields;
11388+
};
11389+
11390+
struct cve_2013_5704_apache24 {
11391+
apr_sockaddr_t *useragent_addr;
11392+
char *useragent_ip;
11393+
cve_2013_5704_fields fields;
11394+
};
11395+
1137511396
static int wsgi_hook_daemon_handler(conn_rec *c)
1137611397
{
1137711398
apr_socket_t *csd;
@@ -11401,6 +11422,13 @@ static int wsgi_hook_daemon_handler(conn_rec *c)
1140111422

1140211423
int queue_timeout_occurred = 0;
1140311424

11425+
#if ! (AP_MODULE_MAGIC_AT_LEAST(20120211, 37) || \
11426+
(AP_SERVER_MAJORVERSION_NUMBER == 2 && \
11427+
AP_SERVER_MINORVERSION_NUMBER <= 2 && \
11428+
AP_MODULE_MAGIC_AT_LEAST(20051115, 36)))
11429+
apr_size_t size = 0;
11430+
#endif
11431+
1140411432
/* Don't do anything if not in daemon process. */
1140511433

1140611434
if (!wsgi_daemon_pool)
@@ -11454,10 +11482,22 @@ static int wsgi_hook_daemon_handler(conn_rec *c)
1145411482
next = current->next;
1145511483
}
1145611484

11457-
/* Create and populate our own request object. */
11485+
/*
11486+
* Create and populate our own request object. We allocate more
11487+
* memory than we require here for the request_rec in order to
11488+
* implement an opimistic hack for the case where mod_wsgi is built
11489+
* against an Apache version prior to CVE-2013-6704 being applied to
11490+
* it. If that Apache is upgraded but mod_wsgi not recompiled then
11491+
* it will crash in daemon mode. We therefore use the extra space to
11492+
* set the structure members which are added by CVE-2013-6704 to try
11493+
* and avoid that situation. Note that this is distinct from the
11494+
* hack down below to deal with where mod_wsgi was compiled against
11495+
* an Apache version which had CVE-2013-6704 backported.
11496+
*/
1145811497

1145911498
apr_pool_create(&p, c->pool);
11460-
r = apr_pcalloc(p, sizeof(request_rec));
11499+
11500+
r = apr_pcalloc(p, sizeof(request_rec)+sizeof(cve_2013_5704_fields));
1146111501

1146211502
r->pool = p;
1146311503
r->connection = c;
@@ -11481,24 +11521,76 @@ static int wsgi_hook_daemon_handler(conn_rec *c)
1148111521
r->proto_input_filters = c->input_filters;
1148211522
r->input_filters = r->proto_input_filters;
1148311523

11484-
#if (AP_SERVER_MINORVERSION_NUMBER <= 2 && \
11485-
AP_MODULE_MAGIC_AT_LEAST(20051115, 36)) || \
11486-
(AP_SERVER_MINORVERSION_NUMBER > 2 && \
11487-
AP_MODULE_MAGIC_AT_LEAST(20120211, 37))
11524+
#if AP_MODULE_MAGIC_AT_LEAST(20120211, 37) || \
11525+
(AP_SERVER_MAJORVERSION_NUMBER == 2 && \
11526+
AP_SERVER_MINORVERSION_NUMBER <= 2 && \
11527+
AP_MODULE_MAGIC_AT_LEAST(20051115, 36))
1148811528

1148911529
/*
1149011530
* New request_rec fields were added to Apache because of changes
1149111531
* related to CVE-2013-5704. The change means that mod_wsgi version
1149211532
* 4.4.0-4.4.5 will crash if run on the Apache versions with the
11493-
* addition fields if mod_wsgi daemon mode is used. If the change
11494-
* for the CVE was backported, even 4.4.6 onwards will crash as
11495-
* Apache with backported changes will not update the module magic
11496-
* number. In that case the cpp conditional here would have to be
11497-
* removed from around the code.
11533+
* addition fields if mod_wsgi daemon mode is used. If we are using
11534+
* Apache 2.2.29 or 2.4.11, we set the fields direct against the
11535+
* new structure members.
1149811536
*/
1149911537

1150011538
r->trailers_in = apr_table_make(r->pool, 5);
1150111539
r->trailers_out = apr_table_make(r->pool, 5);
11540+
#else
11541+
/*
11542+
* We use a huge hack here to try and identify when CVE-2013-5704
11543+
* has been back ported to older Apache version. This is necessary
11544+
* as when backported the Apache module magic number will not be
11545+
* updated and it isn't possible to determine from that at compile
11546+
* time if the new structure members exist and so that they should
11547+
* be set. We therefore try and work out whether the extra structure
11548+
* members exist through looking at the size of request_rec and
11549+
* whether memory has been allocated above what is known to be the
11550+
* last member in the structure before the new members were added.
11551+
*/
11552+
11553+
#if AP_SERVER_MINORVERSION_NUMBER <= 2
11554+
size = offsetof(request_rec, eos_sent);
11555+
size += sizeof(r->eos_sent);
11556+
#else
11557+
size = offsetof(request_rec, useragent_ip);
11558+
size += sizeof(r->useragent_ip);
11559+
#endif
11560+
11561+
/*
11562+
* Check whether request_rec is at least as large as minimal size
11563+
* plus the size of the extra fields. If it is, then we need to
11564+
* set the additional fields.
11565+
*/
11566+
11567+
if (sizeof(request_rec) >= size + sizeof(cve_2013_5704_fields)) {
11568+
#if AP_SERVER_MINORVERSION_NUMBER <= 2
11569+
cve_2013_5704_apache22 *rext;
11570+
rext = (cve_2013_5704_apache22 *)&r->proto_input_filters;
11571+
#else
11572+
cve_2013_5704_apache24 *rext;
11573+
rext = (cve_2013_5704_apache24 *)&r->useragent_addr;
11574+
#endif
11575+
11576+
rext->fields.trailers_in = apr_table_make(r->pool, 5);
11577+
rext->fields.trailers_out = apr_table_make(r->pool, 5);
11578+
}
11579+
else {
11580+
/*
11581+
* Finally, to allow forward portability of a compiled mod_wsgi
11582+
* binary from an Apache version without the CVE-2013-5704
11583+
* change to one where it is, without needing to recompile
11584+
* mod_wsgi, we set fields in the extra memory we added before
11585+
* the actual request_rec.
11586+
*/
11587+
11588+
cve_2013_5704_fields *rext;
11589+
rext = (cve_2013_5704_fields *)(r+1);
11590+
11591+
rext->trailers_in = apr_table_make(r->pool, 5);
11592+
rext->trailers_out = apr_table_make(r->pool, 5);
11593+
}
1150211594
#endif
1150311595

1150411596
r->per_dir_config = r->server->lookup_defaults;

0 commit comments

Comments
 (0)