summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Borg <jakob@nym.se>2016-05-06 13:58:34 +0000
committerAudrius Butkevicius <audrius.butkevicius@gmail.com>2016-05-06 13:58:34 +0000
commit38166e976f0b5e58c1192d6d070cf769a4193b0c (patch)
treeb0dace3351abfa9972307b5acd1e35ff42ddbe39
parentd6a7ffe0d432aa8760a6dc3e7b71b2675d6c8755 (diff)
lib/upgrade: Enforce limits on download archives (fixes #3045)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3046
-rw-r--r--lib/upgrade/upgrade_supported.go49
1 files changed, 44 insertions, 5 deletions
diff --git a/lib/upgrade/upgrade_supported.go b/lib/upgrade/upgrade_supported.go
index a67821eb48..ae63b48c3d 100644
--- a/lib/upgrade/upgrade_supported.go
+++ b/lib/upgrade/upgrade_supported.go
@@ -25,6 +25,7 @@ import (
"runtime"
"sort"
"strings"
+ "time"
"github.com/syncthing/syncthing/lib/dialer"
"github.com/syncthing/syncthing/lib/signature"
@@ -32,12 +33,38 @@ import (
const DisabledByCompilation = false
+const (
+ // Current binary size hovers around 10 MB. We give it some room to grow
+ // and say that we never expect the binary to be larger than 64 MB.
+ maxBinarySize = 64 << 20 // 64 MiB
+
+ // The max expected size of the signature file.
+ maxSignatureSize = 1 << 10 // 1 KiB
+
+ // We set the same limit on the archive. The binary will compress and we
+ // include some other stuff - currently the release archive size is
+ // around 6 MB.
+ maxArchiveSize = maxBinarySize
+
+ // When looking through the archive for the binary and signature, stop
+ // looking once we've searched this many files.
+ maxArchiveMembers = 100
+
+ // Archive reads, or metadata checks, that take longer than this will be
+ // rejected.
+ readTimeout = 30 * time.Minute
+
+ // The limit on the size of metadata that we accept.
+ maxMetadataSize = 100 << 10 // 100 KiB
+)
+
// This is an HTTP/HTTPS client that does *not* perform certificate
// validation. We do this because some systems where Syncthing runs have
// issues with old or missing CA roots. It doesn't actually matter that we
// load the upgrade insecurely as we verify an ECDSA signature of the actual
// binary contents before accepting the upgrade.
var insecureHTTP = &http.Client{
+ Timeout: readTimeout,
Transport: &http.Transport{
Dial: dialer.Dial,
Proxy: http.ProxyFromEnvironment,
@@ -61,7 +88,7 @@ func FetchLatestReleases(releasesURL, version string) []Release {
}
var rels []Release
- json.NewDecoder(resp.Body).Decode(&rels)
+ json.NewDecoder(io.LimitReader(resp.Body, maxMetadataSize)).Decode(&rels)
resp.Body.Close()
return rels
@@ -164,9 +191,9 @@ func readRelease(archiveName, dir, url string) (string, error) {
switch runtime.GOOS {
case "windows":
- return readZip(archiveName, dir, resp.Body)
+ return readZip(archiveName, dir, io.LimitReader(resp.Body, maxArchiveSize))
default:
- return readTarGz(archiveName, dir, resp.Body)
+ return readTarGz(archiveName, dir, io.LimitReader(resp.Body, maxArchiveSize))
}
}
@@ -182,7 +209,13 @@ func readTarGz(archiveName, dir string, r io.Reader) (string, error) {
var sig []byte
// Iterate through the files in the archive.
+ i := 0
for {
+ if i >= maxArchiveMembers {
+ break
+ }
+ i++
+
hdr, err := tr.Next()
if err == io.EOF {
// end of tar archive
@@ -224,7 +257,13 @@ func readZip(archiveName, dir string, r io.Reader) (string, error) {
var sig []byte
// Iterate through the files in the archive.
+ i := 0
for _, file := range archive.File {
+ if i >= maxArchiveMembers {
+ break
+ }
+ i++
+
inFile, err := file.Open()
if err != nil {
return "", err
@@ -264,14 +303,14 @@ func archiveFileVisitor(dir string, tempFile *string, signature *[]byte, archive
return nil
}
l.Debugf("found upgrade binary %s", archivePath)
- *tempFile, err = writeBinary(dir, filedata)
+ *tempFile, err = writeBinary(dir, io.LimitReader(filedata, maxBinarySize))
if err != nil {
return err
}
case "release.sig":
l.Debugf("found signature %s", archivePath)
- *signature, err = ioutil.ReadAll(filedata)
+ *signature, err = ioutil.ReadAll(io.LimitReader(filedata, maxSignatureSize))
if err != nil {
return err
}