Skip to content

Commit 11e17d3

Browse files
committed
Fix denial of service with large numbers in cpuset-cpus and cpuset-mems
Backport of moby#37967 Fix BZ https://bugzilla.redhat.com/show_bug.cgi?id=1666565 Signed-off-by: Antonio Murdaca <runcom@linux.com>
1 parent 454f327 commit 11e17d3

3 files changed

Lines changed: 51 additions & 2 deletions

File tree

pkg/parsers/parsers.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ func ParseKeyValueOpt(opt string) (string, string, error) {
1818
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
1919
}
2020

21+
// ParseUintListMaximum parses and validates the specified string as the value
22+
// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
23+
// one of the formats below. Note that duplicates are actually allowed in the
24+
// input string. It returns a `map[int]bool` with available elements from `val`
25+
// set to `true`. Values larger than `maximum` cause an error if max is non zero,
26+
// in order to stop the map becoming excessively large.
27+
// Supported formats:
28+
// 7
29+
// 1-6
30+
// 0,3-4,7,8-10
31+
// 0-0,0,1-7
32+
// 03,1-3 <- this is gonna get parsed as [1,2,3]
33+
// 3,2,1
34+
// 0-2,3,1
35+
func ParseUintListMaximum(val string, maximum int) (map[int]bool, error) {
36+
return parseUintList(val, maximum)
37+
}
38+
2139
// ParseUintList parses and validates the specified string as the value
2240
// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
2341
// one of the formats below. Note that duplicates are actually allowed in the
@@ -32,6 +50,10 @@ func ParseKeyValueOpt(opt string) (string, string, error) {
3250
// 3,2,1
3351
// 0-2,3,1
3452
func ParseUintList(val string) (map[int]bool, error) {
53+
return parseUintList(val, 0)
54+
}
55+
56+
func parseUintList(val string, maximum int) (map[int]bool, error) {
3557
if val == "" {
3658
return map[int]bool{}, nil
3759
}
@@ -46,6 +68,9 @@ func ParseUintList(val string) (map[int]bool, error) {
4668
if err != nil {
4769
return nil, errInvalidFormat
4870
}
71+
if maximum != 0 && v > maximum {
72+
return nil, fmt.Errorf("value of out range, maximum is %d", maximum)
73+
}
4974
availableInts[v] = true
5075
} else {
5176
split := strings.SplitN(r, "-", 2)
@@ -60,6 +85,9 @@ func ParseUintList(val string) (map[int]bool, error) {
6085
if max < min {
6186
return nil, errInvalidFormat
6287
}
88+
if maximum != 0 && max > maximum {
89+
return nil, fmt.Errorf("value of out range, maximum is %d", maximum)
90+
}
6391
for i := min; i <= max; i++ {
6492
availableInts[i] = true
6593
}

pkg/parsers/parsers_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,16 @@ func TestParseUintList(t *testing.T) {
6868
}
6969
}
7070
}
71+
72+
func TestParseUintListMaximumLimits(t *testing.T) {
73+
v := "10,1000"
74+
if _, err := ParseUintListMaximum(v, 0); err != nil {
75+
t.Fatalf("Expected not to fail, got %v", err)
76+
}
77+
if _, err := ParseUintListMaximum(v, 1000); err != nil {
78+
t.Fatalf("Expected not to fail, got %v", err)
79+
}
80+
if out, err := ParseUintListMaximum(v, 100); err == nil {
81+
t.Fatalf("Expected failure with %s but got %v", v, out)
82+
}
83+
}

pkg/sysinfo/sysinfo.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,19 @@ func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) {
117117
}
118118

119119
func isCpusetListAvailable(provided, available string) (bool, error) {
120-
parsedProvided, err := parsers.ParseUintList(provided)
120+
parsedAvailable, err := parsers.ParseUintList(available)
121121
if err != nil {
122122
return false, err
123123
}
124-
parsedAvailable, err := parsers.ParseUintList(available)
124+
// 8192 is the normal maximum number of CPUs in Linux, so accept numbers up to this
125+
// or more if we actually have more CPUs.
126+
max := 8192
127+
for m := range parsedAvailable {
128+
if m > max {
129+
max = m
130+
}
131+
}
132+
parsedProvided, err := parsers.ParseUintListMaximum(provided, max)
125133
if err != nil {
126134
return false, err
127135
}

0 commit comments

Comments
 (0)