Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/manual/mod/mod_mime_magic.xml
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,64 @@ using the specified magic file</description>
</usage>
</directivesynopsis>

<directivesynopsis>
<name>MimeMagicDecompression</name>
<description>Enable decompression of compressed files for MIME type detection</description>
<syntax>MimeMagicDecompression On|Off</syntax>
<default>MimeMagicDecompression Off</default>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>

<usage>
<p>The <directive>MimeMagicDecompression</directive> directive controls
whether <module>mod_mime_magic</module> will attempt to decompress files
that appear to be compressed (gzip, compress, etc.) in order to determine
the MIME type of the uncompressed content. This feature is <strong>disabled
by default</strong> and should only be enabled if you understand the
significant drawbacks. It exists to maintain backward compatibility with
previous releases of httpd, but its use is discouraged.</p>

<note type="warning"><title>Security and Compatibility Issues</title>
<p>This feature has several serious flaws and is disabled by default:</p>
<ol>
<li><strong>Not RFC-compliant:</strong> Standards documents consistently
recommend against setting Content-Encoding for files that are already
compressed (such as .zip or .gz files). See
<a href="https://www.rfc-editor.org/rfc/rfc9110.html#name-content-encoding">RFC 9110</a>.</li>

<li><strong>Breaks content integrity:</strong> When Content-Encoding is set,
most HTTP clients will decompress the file before writing it to disk. This
causes the downloaded file to have a different size and checksum than the
original, breaking signature verification and checksum validation. Software
distribution sites will find this particularly problematic.</li>

<li><strong>Unpredictable behavior:</strong> This feature only applies to
files that don't match a MIME type via file extension. This can lead to
inconsistent behavior where some files in a directory are affected and
others are not, making problems difficult to diagnose.</li>

<li><strong>Performance impact:</strong> Decompression requires forking and
executing an external <code>gzip</code> process for each compressed file,
which adds significant overhead.</li>

<li><strong>Security risk:</strong> Passing untrusted uploaded file data to
an external binary (<code>gzip</code>) could potentially expose the server to
compression bombs, resource exhaustion, or remote code execution
vulnerabilities in the decompression tool.</li>
</ol>
</note>

<example><title>Example (not recommended)</title>
<highlight language="config">
# Only enable if you fully understand the risks
MimeMagicDecompression On
</highlight>
</example>

<p>In most cases, it is better to ensure files have proper extensions
that can be mapped via <module>mod_mime</module> rather than relying on
this feature.</p>
</usage>
</directivesynopsis>

</modulesynopsis>
34 changes: 31 additions & 3 deletions modules/metadata/mod_mime_magic.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ typedef struct {
const char *magicfile; /* where magic be found */
struct magic *magic; /* head of magic config list */
struct magic *last;
int decompression_enabled; /* whether to decompress files for content detection */
} magic_server_config_rec;

/* per-request info */
Expand All @@ -472,8 +473,11 @@ module AP_MODULE_DECLARE_DATA mime_magic_module;

static void *create_magic_server_config(apr_pool_t *p, server_rec *d)
{
magic_server_config_rec *conf;
/* allocate the config - use pcalloc because it needs to be zeroed */
return apr_pcalloc(p, sizeof(magic_server_config_rec));
conf = apr_pcalloc(p, sizeof(magic_server_config_rec));
conf->decompression_enabled = 0; /* disabled by default */
return conf;
}

static void *merge_magic_server_config(apr_pool_t *p, void *basev, void *addv)
Expand All @@ -484,6 +488,7 @@ static void *merge_magic_server_config(apr_pool_t *p, void *basev, void *addv)
apr_palloc(p, sizeof(magic_server_config_rec));

new->magicfile = add->magicfile ? add->magicfile : base->magicfile;
new->decompression_enabled = add->decompression_enabled;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means the setting doesn't inherit properly across vhosts. The simplest way to do this properly is to have ->decomp_enabled default to an "UNSET" macro defined as -1, and then use a ternary operator to inherit in the merge = (add->decompress_enabled != UNSET) ? add->decompress_enabled : base->decompress_enabled. And also adjust the code that uses the field to special-case the UNSET value

new->magic = NULL;
new->last = NULL;
return new;
Expand All @@ -502,6 +507,19 @@ static const char *set_magicfile(cmd_parms *cmd, void *dummy, const char *arg)
return NULL;
}

static const char *set_decompression(cmd_parms *cmd, void *dummy, int arg)
{
magic_server_config_rec *conf = (magic_server_config_rec *)
ap_get_module_config(cmd->server->module_config,
&mime_magic_module);

if (!conf) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary, that can never return NULL (it's an array lookup).

return MODNAME ": server structure not allocated";
}
conf->decompression_enabled = arg;
return NULL;
}

/*
* configuration file commands - exported to Apache API
*/
Expand All @@ -510,6 +528,13 @@ static const command_rec mime_magic_cmds[] =
{
AP_INIT_TAKE1("MimeMagicFile", set_magicfile, NULL, RSRC_CONF,
"Path to MIME Magic file (in file(1) format)"),
AP_INIT_FLAG("MimeMagicDecompression", set_decompression, NULL, RSRC_CONF,
"Enable decompression of compressed files for content type detection "
"(Off by default). WARNING: This feature is NOT RFC-compliant, can be "
"unpredictable, breaks content integrity (clients will decompress files "
"causing checksum mismatches), impacts performance (fork/exec overhead), "
"and is unsafe (passes untrusted data to external gzip binary). "
"Use only if you understand these risks."),
{NULL}
};

Expand Down Expand Up @@ -878,10 +903,13 @@ static int magic_process(request_rec *r)
static int tryit(request_rec *r, unsigned char *buf, apr_size_t nb,
int checkzmagic)
{
magic_server_config_rec *conf = (magic_server_config_rec *)
ap_get_module_config(r->server->module_config, &mime_magic_module);

/*
* Try compression stuff
* Try compression stuff (only if decompression is enabled)
*/
if (checkzmagic == 1) {
if (checkzmagic == 1 && conf && conf->decompression_enabled) {
if (zmagic(r, buf, nb) == 1)
return OK;
}
Expand Down
Loading