Browse Source

Fix endless loop in apt-get update that can cause disk fillup

The apt http code parses Content-Length and Content-Range. For
both requests the variable "Size" is used and the semantic for
this Size is the total file size. However Content-Length is not
the entire file size for partital file requests. For servers that
send the Content-Range header first and then the Content-Length
header this can lead to globbing of Size so that its less than
the real file size. This may lead to a subsequent passing of a
negative number into the CircleBuf which leads to a endless
loop that writes data.

Thanks to Anton Blanchard for the analysis and initial patch.

LP: #1445239
tags/debian/1.0.9.10
Michael Vogt 6 years ago
parent
commit
ceafe8a6ed
4 changed files with 21 additions and 10 deletions
  1. +1
    -1
      methods/http.cc
  2. +15
    -5
      methods/server.cc
  3. +2
    -1
      methods/server.h
  4. +3
    -3
      test/interactive-helper/aptwebserver.cc

+ 1
- 1
methods/http.cc View File

@@ -443,7 +443,7 @@ bool HttpServerState::RunData(FileFd * const File)
else if (JunkSize != 0)
In.Limit(JunkSize);
else
In.Limit(Size - StartPos);
In.Limit(DownloadSize);
// Just transfer the whole block.
do


+ 15
- 5
methods/server.cc View File

@@ -164,15 +164,22 @@ bool ServerState::HeaderLine(string Line)
Encoding = Stream;
HaveContent = true;

unsigned long long * SizePtr = &Size;
unsigned long long * DownloadSizePtr = &DownloadSize;
if (Result == 416)
SizePtr = &JunkSize;
DownloadSizePtr = &JunkSize;

*SizePtr = strtoull(Val.c_str(), NULL, 10);
if (*SizePtr >= std::numeric_limits<unsigned long long>::max())
*DownloadSizePtr = strtoull(Val.c_str(), NULL, 10);
if (*DownloadSizePtr >= std::numeric_limits<unsigned long long>::max())
return _error->Errno("HeaderLine", _("The HTTP server sent an invalid Content-Length header"));
else if (*SizePtr == 0)
else if (*DownloadSizePtr == 0)
HaveContent = false;

// On partial content (206) the Content-Length less than the real
// size, so do not set it here but leave that to the Content-Range
// header instead
if(Result != 206 && Size == 0)
Size = DownloadSize;

return true;
}

@@ -193,6 +200,9 @@ bool ServerState::HeaderLine(string Line)
return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
if ((unsigned long long)StartPos > Size)
return _error->Error(_("This HTTP server has broken range support"));

// figure out what we will download
DownloadSize = Size - StartPos;
return true;
}



+ 2
- 1
methods/server.h View File

@@ -34,7 +34,8 @@ struct ServerState
char Code[360];

// These are some statistics from the last parsed header lines
unsigned long long Size; // size of the usable content (aka: the file)
unsigned long long Size; // total size of the usable content (aka: the file)
unsigned long long DownloadSize; // size we actually download (can be smaller than Size if we have partial content)
unsigned long long JunkSize; // size of junk content (aka: server error pages)
unsigned long long StartPos;
time_t Date;


+ 3
- 3
test/interactive-helper/aptwebserver.cc View File

@@ -654,13 +654,13 @@ static void * handleClient(void * voidclient) /*{{{*/
if (filesize > filestart)
{
data.Skip(filestart);
std::ostringstream contentlength;
contentlength << "Content-Length: " << (filesize - filestart);
headers.push_back(contentlength.str());
std::ostringstream contentrange;
contentrange << "Content-Range: bytes " << filestart << "-"
<< filesize - 1 << "/" << filesize;
headers.push_back(contentrange.str());
std::ostringstream contentlength;
contentlength << "Content-Length: " << (filesize - filestart);
headers.push_back(contentlength.str());
sendHead(client, 206, headers);
if (sendContent == true)
sendFile(client, headers, data);


Loading…
Cancel
Save