Skip to content

Commit 2248fc6

Browse files
committed
cmd/compile: give every really deep type a unique name
This avoids the security problem in #29312 where two very deep, but distinct, types are given the same name. They both make it to the linker which chooses one, and the use of the other is now type unsafe. Instead, give every very deep type its own name. This errs on the other side, in that very deep types that should be convertible to each other might now not be. But at least that's not a security hole. Update #29312. Change-Id: Iac0ebe73fdc50594fd6fbf7432eef65f9a053126 Reviewed-on: https://go-review.googlesource.com/c/go/+/213517 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent 77c1302 commit 2248fc6

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

src/cmd/compile/internal/gc/fmt.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,8 @@ func typeFormat(t *types.Type, s fmt.State, verb rune, mode fmtMode) {
17311731
}
17321732
}
17331733

1734+
var deepTypes map[*types.Type]string
1735+
17341736
// See #16897 before changing the implementation of tconv.
17351737
func tconv(t *types.Type, flag FmtFlag, mode fmtMode, depth int) string {
17361738
if t == nil {
@@ -1747,8 +1749,19 @@ func tconv(t *types.Type, flag FmtFlag, mode fmtMode, depth int) string {
17471749
// limits the depths of valid composite types, but they are likely
17481750
// artificially created.
17491751
// TODO(gri) should have proper cycle detection here, eventually (issue #29312)
1752+
// For now, ensure that each of these really deep types are at least uniquely
1753+
// named, so that such types don't collide in the linker and thus allow security holes.
17501754
if depth > 250 {
1751-
return "<...>"
1755+
if str := deepTypes[t]; str != "" {
1756+
return str
1757+
}
1758+
if deepTypes == nil {
1759+
deepTypes = map[*types.Type]string{}
1760+
}
1761+
id := len(deepTypes)
1762+
str := fmt.Sprintf("<...uniquetype_%d_in_%s>", id, curpkg().Path)
1763+
deepTypes[t] = str
1764+
return str
17521765
}
17531766

17541767
flag, mode = flag.update(mode)

test/fixedbugs/issue29312.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// run
2+
3+
// Copyright 2020 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// This test is not for a fix of 29312 proper, but for the patch that
8+
// makes sure we at least don't have a security hole because of 29312.
9+
10+
// This code generates lots of types. The binary should contain
11+
// a runtime.slicetype for each of the following 253 types:
12+
//
13+
// []*pwn
14+
// [][]*pwn
15+
// ...
16+
// [][]...[][]*pwn - 249 total "[]"
17+
// [][]...[][][]*pwn - 250 total "[]"
18+
// [][]...[][][][]*pwn - 251 total "[]"
19+
// [][]...[][][][][]*pwn - 252 total "[]"
20+
// [][]...[][][][][][]*pwn - 253 total "[]"
21+
//
22+
// The type names for these types are as follows. Because we truncate
23+
// the name at depth 250, the last few names are all identical:
24+
//
25+
// type.[]*"".pwn
26+
// type.[][]*"".pwn
27+
// ...
28+
// type.[][]...[][]*pwn - 249 total "[]"
29+
// type.[][]...[][][]*<...> - 250 total "[]"
30+
// type.[][]...[][][][]<...> - 251 total "[]"
31+
// type.[][]...[][][][]<...> - 252 total "[]" (but only 251 "[]" in the name)
32+
// type.[][]...[][][][]<...> - 253 total "[]" (but only 251 "[]" in the name)
33+
//
34+
// Because the names of the last 3 types are all identical, the
35+
// compiler will generate only a single runtime.slicetype data
36+
// structure for all 3 underlying types. It turns out the compiler
37+
// generates just the 251-entry one. There aren't any
38+
// runtime.slicetypes generated for the final two types.
39+
//
40+
// The compiler passes type.[]...[]<...> (251 total "[]") to
41+
// fmt.Sprintf (instead of the correct 253 one). But the data
42+
// structure at runtime actually has 253 nesting levels. So we end up
43+
// calling String on something that is of type [][]*pwn instead of
44+
// something of type *pwn. The way arg passing in Go works, the
45+
// backing store pointer for the outer slice becomes the "this"
46+
// pointer of the String method, which points to the inner []*pwn
47+
// slice. The String method then modifies the length of that inner
48+
// slice.
49+
package main
50+
51+
import "fmt"
52+
53+
type pwn struct {
54+
a [3]uint
55+
}
56+
57+
func (this *pwn) String() string {
58+
this.a[1] = 7 // update length
59+
return ""
60+
}
61+
62+
func main() {
63+
var a pwn
64+
s := [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]*pwn{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{&a}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} // depth 253
65+
fmt.Sprint(s)
66+
n := len(s[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]) // depth 252, type []*pwn
67+
if n != 1 {
68+
panic(fmt.Sprintf("length was changed, want 1 got %d", n))
69+
}
70+
}

0 commit comments

Comments
 (0)