wget: check chunk length for overflowing off_t
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 8 Apr 2018 16:06:24 +0000 (18:06 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 8 Apr 2018 16:06:24 +0000 (18:06 +0200)
function                                             old     new   delta
retrieve_file_data                                   428     465     +37
wget_main                                           2386    2389      +3
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 40/0)               Total: 40 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/wget.c

index c9e576e697ba0df2cf26b0d24bac0214ced179e2..2650b5384a441ec138548335e6f4a5b7439a73a2 100644 (file)
@@ -801,7 +801,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
        if (ftpcmd("SIZE ", target->path, sfp) == 213) {
                G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
                if (G.content_len < 0 || errno) {
-                       bb_error_msg_and_die("SIZE value is garbage");
+                       bb_error_msg_and_die("bad SIZE value '%s'", G.wget_buf + 4);
                }
                G.got_clen = 1;
        }
@@ -965,11 +965,19 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
                if (!G.chunked)
                        break;
 
-               fgets_trim_sanitize(dfp, NULL); /* Eat empty line */
+               /* Each chunk ends with "\r\n" - eat it */
+               fgets_trim_sanitize(dfp, NULL);
  get_clen:
+               /* chunk size format is "HEXNUM[;name[=val]]\r\n" */
                fgets_trim_sanitize(dfp, NULL);
+               errno = 0;
                G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
-               /* FIXME: error check? */
+               /*
+                * Had a bug with inputs like "ffffffff0001f400"
+                * smashing the heap later. Ensure >= 0.
+                */
+               if (G.content_len < 0 || errno)
+                       bb_error_msg_and_die("bad chunk length '%s'", G.wget_buf);
                if (G.content_len == 0)
                        break; /* all done! */
                G.got_clen = 1;