bug-wget
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-wget] [PATCH 22/27] Bugfix: Detect malformed base64 Metalink/HTTP D


From: Matthew White
Subject: [Bug-wget] [PATCH 22/27] Bugfix: Detect malformed base64 Metalink/HTTP Digest header
Date: Thu, 29 Sep 2016 06:03:02 +0200

* src/http.c (metalink_from_http): Fix hash_bin_len type. Use ssize_t
  instead than size_t. Reject -1 as base64_decode() return value
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-http-baddigest.py: New file. Metalink/HTTP
  malformed base64 Digest header tests

On malformed base64 input, ssize_t base64_decode() returns -1. Such
value is too big for a size_t variable, and used as xmalloc() value
will exaust all the memory.
---
 src/http.c                              | 14 +++--
 testenv/Makefile.am                     |  1 +
 testenv/Test-metalink-http-baddigest.py | 93 +++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 3 deletions(-)
 create mode 100755 testenv/Test-metalink-http-baddigest.py

diff --git a/src/http.c b/src/http.c
index e6af7c1..4466b31 100644
--- a/src/http.c
+++ b/src/http.c
@@ -2894,10 +2894,18 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
              Therefore we convert: base64 -> binary -> hex.  */
           const size_t dig_hash_str_len = strlen (dig_hash);
           char *bin_hash = alloca (dig_hash_str_len * 3 / 4 + 1);
-          size_t hash_bin_len;
+          ssize_t hash_bin_len;
 
           hash_bin_len = base64_decode (dig_hash, bin_hash);
 
+          /* Detect malformed base64 input.  */
+          if (hash_bin_len < 0)
+            {
+              xfree (dig_type);
+              xfree (dig_hash);
+              continue;
+            }
+
           /* One slot for me, one for zero-termination.  */
           mfile->checksums =
                   xrealloc (mfile->checksums,
@@ -2905,8 +2913,8 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
           mfile->checksums[hash_count] = xnew (metalink_checksum_t);
           mfile->checksums[hash_count]->type = dig_type;
 
-          mfile->checksums[hash_count]->hash = xmalloc (hash_bin_len * 2 + 1);
-          wg_hex_to_string (mfile->checksums[hash_count]->hash, bin_hash, 
hash_bin_len);
+          mfile->checksums[hash_count]->hash = xmalloc ((size_t)hash_bin_len * 
2 + 1);
+          wg_hex_to_string (mfile->checksums[hash_count]->hash, bin_hash, 
(size_t)hash_bin_len);
 
           xfree (dig_hash);
 
diff --git a/testenv/Makefile.am b/testenv/Makefile.am
index daba609..ff9fe05 100644
--- a/testenv/Makefile.am
+++ b/testenv/Makefile.am
@@ -29,6 +29,7 @@
 if METALINK_IS_ENABLED
   METALINK_TESTS = Test-metalink-http.py            \
     Test-metalink-http-quoted.py                    \
+    Test-metalink-http-baddigest.py                 \
     Test-metalink-http-xml.py                       \
     Test-metalink-http-xml-trust.py                 \
     Test-metalink-xml.py                            \
diff --git a/testenv/Test-metalink-http-baddigest.py 
b/testenv/Test-metalink-http-baddigest.py
new file mode 100755
index 0000000..2496da7
--- /dev/null
+++ b/testenv/Test-metalink-http-baddigest.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+    This is to test Metalink/HTTP with a malformed base64 Digest header.
+
+    With --trust-server-names, trust the metalink:file names.
+
+    Without --trust-server-names, don't trust the metalink:file names:
+    use the basename of --input-metalink, and add a sequential number
+    (e.g. .#1, .#2, etc.).
+
+    Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+bad_sha256 = b64encode (hashlib.sha256 (bad.encode ('UTF-8')).digest 
()).decode ('ascii')
+
+LinkHeaders = ["<http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file>; rel=duplicate; 
pri=1"]
+DigestHeader = "SHA-256=bad_base64,SHA-256={{BAD_HASH}}"
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+
+wrong_file = WgetFile ("wrong_file", bad)
+wrong_file_down = WgetFile ("main.metalink", bad)
+
+WGET_OPTIONS = "--metalink-over-http"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+    "HEAD /main.metalink",
+    "GET /wrong_file"
+]]
+
+Files = [[
+    MetaHTTP,
+    wrong_file
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [wrong_file_down]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+    "ServerFiles"       : Files,
+    "LocalFiles"        : Existing_Files
+}
+test_options = {
+    "WgetCommands"      : WGET_OPTIONS,
+    "Urls"              : WGET_URLS
+}
+post_test = {
+    "ExpectedFiles"     : ExpectedDownloadedFiles,
+    "ExpectedRetcode"   : ExpectedReturnCode,
+    "FilesCrawled"      : RequestList
+}
+
+http_test = HTTPTest (
+                pre_hook=pre_test,
+                test_params=test_options,
+                post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+DigestHeader = DigestHeader.replace('{{BAD_HASH}}', bad_sha256)
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port):
+    text = text.replace('{{SRV_HOST}}', host)
+    text = text.replace('{{SRV_PORT}}', str (port))
+    return text
+
+MetaHTTPRules["SendHeader"] = {
+        'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
+                    for LinkHeader in LinkHeaders ],
+        'Digest': DigestHeader
+}
+
+err = http_test.begin ()
+
+exit (err)
-- 
2.7.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]