Sophie

Sophie

distrib > Mageia > 6 > x86_64 > media > core-updates-src > by-pkgid > 094813109006ee764c607689096b6173 > files > 1

docker-18.06.1-1.2.mga6.src.rpm

From 11e17d3b79bc450a52d5e1dd1c1444f7ebe5f751 Mon Sep 17 00:00:00 2001
From: Antonio Murdaca <runcom@linux.com>
Date: Fri, 18 Jan 2019 17:13:36 +0100
Subject: [PATCH] Fix denial of service with large numbers in cpuset-cpus and
 cpuset-mems

Backport of https://github.com/moby/moby/pull/37967
Fix BZ https://bugzilla.redhat.com/show_bug.cgi?id=1666565

Signed-off-by: Antonio Murdaca <runcom@linux.com>
---
 pkg/parsers/parsers.go      | 28 ++++++++++++++++++++++++++++
 pkg/parsers/parsers_test.go | 13 +++++++++++++
 pkg/sysinfo/sysinfo.go      | 12 ++++++++++--
 3 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/components/engine/pkg/parsers/parsers.go b/components/engine/pkg/parsers/parsers.go
index acc897168f3c..710d734f49a8 100644
--- a/components/engine/pkg/parsers/parsers.go
+++ b/components/engine/pkg/parsers/parsers.go
@@ -18,6 +18,24 @@ func ParseKeyValueOpt(opt string) (string, string, error) {
 	return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
 }
 
+// ParseUintListMaximum parses and validates the specified string as the value
+// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
+// one of the formats below. Note that duplicates are actually allowed in the
+// input string. It returns a `map[int]bool` with available elements from `val`
+// set to `true`. Values larger than `maximum` cause an error if max is non zero,
+// in order to stop the map becoming excessively large.
+// Supported formats:
+//     7
+//     1-6
+//     0,3-4,7,8-10
+//     0-0,0,1-7
+//     03,1-3      <- this is gonna get parsed as [1,2,3]
+//     3,2,1
+//     0-2,3,1
+func ParseUintListMaximum(val string, maximum int) (map[int]bool, error) {
+	return parseUintList(val, maximum)
+}
+
 // ParseUintList parses and validates the specified string as the value
 // found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
 // one of the formats below. Note that duplicates are actually allowed in the
@@ -32,6 +50,10 @@ func ParseKeyValueOpt(opt string) (string, string, error) {
 //     3,2,1
 //     0-2,3,1
 func ParseUintList(val string) (map[int]bool, error) {
+	return parseUintList(val, 0)
+}
+
+func parseUintList(val string, maximum int) (map[int]bool, error) {
 	if val == "" {
 		return map[int]bool{}, nil
 	}
@@ -46,6 +68,9 @@ func ParseUintList(val string) (map[int]bool, error) {
 			if err != nil {
 				return nil, errInvalidFormat
 			}
+			if maximum != 0 && v > maximum {
+				return nil, fmt.Errorf("value of out range, maximum is %d", maximum)
+			}
 			availableInts[v] = true
 		} else {
 			split := strings.SplitN(r, "-", 2)
@@ -60,6 +85,9 @@ func ParseUintList(val string) (map[int]bool, error) {
 			if max < min {
 				return nil, errInvalidFormat
 			}
+			if maximum != 0 && max > maximum {
+				return nil, fmt.Errorf("value of out range, maximum is %d", maximum)
+			}
 			for i := min; i <= max; i++ {
 				availableInts[i] = true
 			}
diff --git a/components/engine/pkg/parsers/parsers_test.go b/components/engine/pkg/parsers/parsers_test.go
index 7f19e902799e..3225886cfdba 100644
--- a/components/engine/pkg/parsers/parsers_test.go
+++ b/components/engine/pkg/parsers/parsers_test.go
@@ -68,3 +68,16 @@ func TestParseUintList(t *testing.T) {
 		}
 	}
 }
+
+func TestParseUintListMaximumLimits(t *testing.T) {
+	v := "10,1000"
+	if _, err := ParseUintListMaximum(v, 0); err != nil {
+		t.Fatalf("Expected not to fail, got %v", err)
+	}
+	if _, err := ParseUintListMaximum(v, 1000); err != nil {
+		t.Fatalf("Expected not to fail, got %v", err)
+	}
+	if out, err := ParseUintListMaximum(v, 100); err == nil {
+		t.Fatalf("Expected failure with %s but got %v", v, out)
+	}
+}
diff --git a/components/engine/pkg/sysinfo/sysinfo.go b/components/engine/pkg/sysinfo/sysinfo.go
index f046de4b1698..3b66962b7860 100644
--- a/components/engine/pkg/sysinfo/sysinfo.go
+++ b/components/engine/pkg/sysinfo/sysinfo.go
@@ -117,11 +117,19 @@ func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) {
 }
 
 func isCpusetListAvailable(provided, available string) (bool, error) {
-	parsedProvided, err := parsers.ParseUintList(provided)
+	parsedAvailable, err := parsers.ParseUintList(available)
 	if err != nil {
 		return false, err
 	}
-	parsedAvailable, err := parsers.ParseUintList(available)
+	// 8192 is the normal maximum number of CPUs in Linux, so accept numbers up to this
+	// or more if we actually have more CPUs.
+	max := 8192
+	for m := range parsedAvailable {
+		if m > max {
+			max = m
+		}
+	}
+	parsedProvided, err := parsers.ParseUintListMaximum(provided, max)
 	if err != nil {
 		return false, err
 	}