Skip to content

Commit 86b5d2d

Browse files
Merge branch 'release/4.4.6'
2 parents 1be8b37 + ba67c74 commit 86b5d2d

18 files changed

+595
-18
lines changed

docs/release-notes/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Release Notes
55
.. toctree::
66
:maxdepth: 2
77

8+
version-4.4.6.rst
89
version-4.4.5.rst
910
version-4.4.4.rst
1011
version-4.4.3.rst

docs/release-notes/version-4.4.6.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
=============
2+
Version 4.4.6
3+
=============
4+
5+
Version 4.4.6 of mod_wsgi can be obtained from:
6+
7+
https://codeload.github.com/GrahamDumpleton/mod_wsgi/tar.gz/4.4.6
8+
9+
For details on the availability of Windows binaries see:
10+
11+
https://github.com/GrahamDumpleton/mod_wsgi/tree/master/win32
12+
13+
Bugs Fixed
14+
----------
15+
16+
1. Apache 2.2.29 and 2.4.11 introduce additional fields to the request
17+
structure ``request_rec`` due to CVE-2013-5704. The addition of these
18+
fields will cause versions of mod_wsgi from 4.4.0-4.4.5 to crash when used
19+
in mod_wsgi daemon mode and mod_wsgi isn't initialising the new structure
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.
49+
50+
2. Override ``LC_ALL`` environment variable when ``locale`` option to the
51+
``WSGIDaemonProcess`` directive. It is not always sufficient to just call
52+
``setlocale()`` as some Python code, including interpreter initialisation
53+
can still consult the original ``LC_ALL`` environment variable. In this
54+
case this can result in an undesired file system encoding still being
55+
selected.
56+
57+
New Features
58+
------------
59+
60+
1. Added ``--enable-gdb`` option to ``mod_wsgi-express`` for when running
61+
in debug mode. With this option set, Apache will be started up within
62+
``gdb`` allowing the debug of process crashes on startup or while handling
63+
requests. If the ``gdb`` program is not in ``PATH``, the ``--gdb-executable``
64+
option can be set to give its location.

src/server/__init__.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,10 @@ def generate_server_metrics_script(options):
13331333
13341334
# %(sys_argv)s
13351335
1336-
HTTPD="%(httpd_executable)s %(httpd_arguments)s"
1336+
HTTPD="%(httpd_executable)s"
1337+
HTTPD_ARGS="%(httpd_arguments)s"
1338+
1339+
HTTPD_COMMAND="$HTTPD $HTTPD_ARGS"
13371340
13381341
SHLIBPATH="%(shlibpath)s"
13391342
@@ -1382,20 +1385,28 @@ def generate_server_metrics_script(options):
13821385
ARGV="-h"
13831386
fi
13841387
1388+
GDB="%(gdb_executable)s"
1389+
ENABLE_GDB="%(enable_gdb)s"
1390+
13851391
PROCESS_NAME="%(process_name)s"
13861392
13871393
case $ACMD in
13881394
start|stop|restart|graceful|graceful-stop)
1389-
exec -a "$PROCESS_NAME" $HTTPD -k $ARGV
1395+
if [ "x$ENABLE_GDB" != "xTrue" ]; then
1396+
exec -a "$PROCESS_NAME" $HTTPD_COMMAND -k $ARGV
1397+
else
1398+
echo "run $HTTPD_ARGS -k $ARGV" > %(server_root)s/gdb.cmds
1399+
gdb -x %(server_root)s/gdb.cmds $HTTPD
1400+
fi
13901401
;;
13911402
configtest)
1392-
exec $HTTPD -t
1403+
exec $HTTPD_COMMAND -t
13931404
;;
13941405
status)
13951406
exec %(python_executable)s -m webbrowser -t $STATUSURL
13961407
;;
13971408
*)
1398-
exec $HTTPD $ARGV
1409+
exec $HTTPD_COMMAND $ARGV
13991410
esac
14001411
"""
14011412

@@ -1946,6 +1957,14 @@ def check_percentage(option, opt_str, value, parser):
19461957
'which recorder data will be written when enabled under debug '
19471958
'mode.'),
19481959

1960+
optparse.make_option('--enable-gdb', action='store_true',
1961+
default=False, help='Flag indicating whether Apache should '
1962+
'be run under \'gdb\' when running in debug mode. This '
1963+
'would be use to debug process crashes.'),
1964+
optparse.make_option('--gdb-executable', default='gdb',
1965+
metavar='FILE-PATH', help='Override the path to the gdb '
1966+
'executable.'),
1967+
19491968
optparse.make_option('--setup-only', action='store_true', default=False,
19501969
help='Flag indicating that after the configuration files have '
19511970
'been setup, that the command should then exit and not go on '
@@ -2416,6 +2435,7 @@ def _cmd_setup_server(command, args, options):
24162435
options['enable_coverage'] = False
24172436
options['enable_profiler'] = False
24182437
options['enable_recorder'] = False
2438+
options['enable_gdb'] = False
24192439

24202440
options['parent_domain'] = 'unspecified'
24212441

@@ -2536,10 +2556,27 @@ def _cmd_setup_server(command, args, options):
25362556
print('Environ Variables :', options['server_root'] + '/envvars')
25372557
print('Control Script :', options['server_root'] + '/apachectl')
25382558

2539-
print('Locale Setting :', options['locale'])
2559+
if options['processes'] == 1:
2560+
print('Request Capacity : %s (%s process * %s threads)' % (
2561+
options['processes']*options['threads'],
2562+
options['processes'], options['threads']))
2563+
else:
2564+
print('Request Capacity : %s (%s processes * %s threads)' % (
2565+
options['processes']*options['threads'],
2566+
options['processes'], options['threads']))
2567+
2568+
print('Request Timeout : %s (seconds)' % options['request_timeout'])
25402569

2541-
print('Daemon Processes :', options['processes'])
2542-
print('Daemon Threads :', options['threads'])
2570+
print('Queue Backlog : %s (connections)' % options['daemon_backlog'])
2571+
2572+
print('Queue Timeout : %s (seconds)' % options['queue_timeout'])
2573+
2574+
print('Server Capacity : %s (event/worker), %s (prefork)' % (
2575+
options['worker_max_clients'], options['prefork_max_clients']))
2576+
2577+
print('Server Backlog : %s (connections)' % options['server_backlog'])
2578+
2579+
print('Locale Setting :', options['locale'])
25432580

25442581
return options
25452582

src/server/mod_wsgi.c

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9206,13 +9206,17 @@ static int wsgi_start_process(apr_pool_t *p, WSGIDaemonProcess *daemon)
92069206
}
92079207

92089208
if (daemon->group->locale) {
9209+
char *envvar;
92099210
char *result;
92109211

92119212
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wsgi_server,
92129213
"mod_wsgi (pid=%d): Setting locale to %s for "
92139214
"daemon process group %s.", getpid(),
92149215
daemon->group->locale, daemon->group->name);
92159216

9217+
envvar = apr_pstrcat(p, "LC_ALL=", daemon->group->locale, NULL);
9218+
putenv(envvar);
9219+
92169220
result = setlocale(LC_ALL, daemon->group->locale);
92179221

92189222
if (!result) {
@@ -11368,6 +11372,27 @@ static apr_status_t wsgi_header_filter(ap_filter_t *f, apr_bucket_brigade *b)
1136811372
return ap_pass_brigade(f->next, b);
1136911373
}
1137011374

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+
1137111396
static int wsgi_hook_daemon_handler(conn_rec *c)
1137211397
{
1137311398
apr_socket_t *csd;
@@ -11397,6 +11422,13 @@ static int wsgi_hook_daemon_handler(conn_rec *c)
1139711422

1139811423
int queue_timeout_occurred = 0;
1139911424

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+
1140011432
/* Don't do anything if not in daemon process. */
1140111433

1140211434
if (!wsgi_daemon_pool)
@@ -11450,10 +11482,22 @@ static int wsgi_hook_daemon_handler(conn_rec *c)
1145011482
next = current->next;
1145111483
}
1145211484

11453-
/* 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+
*/
1145411497

1145511498
apr_pool_create(&p, c->pool);
11456-
r = apr_pcalloc(p, sizeof(request_rec));
11499+
11500+
r = apr_pcalloc(p, sizeof(request_rec)+sizeof(cve_2013_5704_fields));
1145711501

1145811502
r->pool = p;
1145911503
r->connection = c;
@@ -11477,6 +11521,78 @@ static int wsgi_hook_daemon_handler(conn_rec *c)
1147711521
r->proto_input_filters = c->input_filters;
1147811522
r->input_filters = r->proto_input_filters;
1147911523

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))
11528+
11529+
/*
11530+
* New request_rec fields were added to Apache because of changes
11531+
* related to CVE-2013-5704. The change means that mod_wsgi version
11532+
* 4.4.0-4.4.5 will crash if run on the Apache versions with the
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.
11536+
*/
11537+
11538+
r->trailers_in = apr_table_make(r->pool, 5);
11539+
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+
}
11594+
#endif
11595+
1148011596
r->per_dir_config = r->server->lookup_defaults;
1148111597

1148211598
r->sent_bodyct = 0;

src/server/wsgi_daemon.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@
4848
#include "http_connection.h"
4949
#include "apr_poll.h"
5050
#include "apr_signal.h"
51-
#include "apr_support.h"
5251
#include "http_vhost.h"
5352

53+
#if APR_MAJOR_VERSION < 2
54+
#include "apr_support.h"
55+
#endif
56+
5457
#if APR_MAJOR_VERSION < 1
5558
#define apr_atomic_cas32 apr_atomic_cas
5659
#endif

src/server/wsgi_version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
#define MOD_WSGI_MAJORVERSION_NUMBER 4
2727
#define MOD_WSGI_MINORVERSION_NUMBER 4
28-
#define MOD_WSGI_MICROVERSION_NUMBER 5
29-
#define MOD_WSGI_VERSION_STRING "4.4.5"
28+
#define MOD_WSGI_MICROVERSION_NUMBER 6
29+
#define MOD_WSGI_VERSION_STRING "4.4.6"
3030

3131
/* ------------------------------------------------------------------------- */
3232

tests/environ.wsgi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def application(environ, start_response):
7272
print('LC_ALL: %s' % os.environ.get('LC_ALL'), file=output)
7373
print('sys.getdefaultencoding(): %s' % sys.getdefaultencoding(),
7474
file=output)
75+
print('sys.getfilesystemencoding(): %s' % sys.getfilesystemencoding(),
76+
file=output)
7577
print('locale.getlocale(): %s' % (locale.getlocale(),),
7678
file=output)
7779
print('locale.getdefaultlocale(): %s' % (locale.getdefaultlocale(),),

0 commit comments

Comments
 (0)