libgo: update to Go 1.10.2 release
[official-gcc.git] / libgo / go / cmd / go / internal / work / security.go
blob5c67aa945eff71d0fd926adf2b35240c8df89e5f
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Checking of compiler and linker flags.
6 // We must avoid flags like -fplugin=, which can allow
7 // arbitrary code execution during the build.
8 // Do not make changes here without carefully
9 // considering the implications.
10 // (That's why the code is isolated in a file named security.go.)
12 // Note that -Wl,foo means split foo on commas and pass to
13 // the linker, so that -Wl,-foo,bar means pass -foo bar to
14 // the linker. Similarly -Wa,foo for the assembler and so on.
15 // If any of these are permitted, the wildcard portion must
16 // disallow commas.
18 // Note also that GNU binutils accept any argument @foo
19 // as meaning "read more flags from the file foo", so we must
20 // guard against any command-line argument beginning with @,
21 // even things like "-I @foo".
22 // We use load.SafeArg (which is even more conservative)
23 // to reject these.
25 // Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args),
26 // so although gcc doesn't expand the @foo, cc1 will.
27 // So out of paranoia, we reject @ at the beginning of every
28 // flag argument that might be split into its own argument.
30 package work
32 import (
33 "cmd/go/internal/load"
34 "fmt"
35 "os"
36 "regexp"
37 "strings"
40 var re = regexp.MustCompile
42 var validCompilerFlags = []*regexp.Regexp{
43 re(`-D([A-Za-z_].*)`),
44 re(`-I([^@\-].*)`),
45 re(`-O`),
46 re(`-O([^@\-].*)`),
47 re(`-W`),
48 re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
49 re(`-Wa,-mbig-obj`),
50 re(`-ansi`),
51 re(`-f(no-)?blocks`),
52 re(`-f(no-)?common`),
53 re(`-f(no-)?constant-cfstrings`),
54 re(`-fdiagnostics-show-note-include-stack`),
55 re(`-f(no-)?exceptions`),
56 re(`-f(no-)?inline-functions`),
57 re(`-finput-charset=([^@\-].*)`),
58 re(`-f(no-)?fat-lto-objects`),
59 re(`-f(no-)?lto`),
60 re(`-fmacro-backtrace-limit=(.+)`),
61 re(`-fmessage-length=(.+)`),
62 re(`-f(no-)?modules`),
63 re(`-f(no-)?objc-arc`),
64 re(`-f(no-)?omit-frame-pointer`),
65 re(`-f(no-)?openmp(-simd)?`),
66 re(`-f(no-)?permissive`),
67 re(`-f(no-)?(pic|PIC|pie|PIE)`),
68 re(`-f(no-)?rtti`),
69 re(`-f(no-)?split-stack`),
70 re(`-f(no-)?stack-(.+)`),
71 re(`-f(no-)?strict-aliasing`),
72 re(`-f(un)signed-char`),
73 re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
74 re(`-fsanitize=(.+)`),
75 re(`-ftemplate-depth-(.+)`),
76 re(`-fvisibility=(.+)`),
77 re(`-g([^@\-].*)?`),
78 re(`-m32`),
79 re(`-m64`),
80 re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
81 re(`-m(no-)?avx[0-9a-z.]*`),
82 re(`-m(no-)?ms-bitfields`),
83 re(`-m(no-)?stack-(.+)`),
84 re(`-mmacosx-(.+)`),
85 re(`-mios-simulator-version-min=(.+)`),
86 re(`-miphoneos-version-min=(.+)`),
87 re(`-mnop-fun-dllimport`),
88 re(`-m(no-)?sse[0-9.]*`),
89 re(`-mwindows`),
90 re(`-pedantic(-errors)?`),
91 re(`-pipe`),
92 re(`-pthread`),
93 re(`-?-std=([^@\-].*)`),
94 re(`-?-stdlib=([^@\-].*)`),
95 re(`-w`),
96 re(`-x([^@\-].*)`),
99 var validCompilerFlagsWithNextArg = []string{
100 "-arch",
101 "-D",
102 "-I",
103 "-framework",
104 "-isysroot",
105 "-isystem",
106 "--sysroot",
107 "-target",
108 "-x",
111 var validLinkerFlags = []*regexp.Regexp{
112 re(`-F([^@\-].*)`),
113 re(`-l([^@\-].*)`),
114 re(`-L([^@\-].*)`),
115 re(`-O`),
116 re(`-O([^@\-].*)`),
117 re(`-f(no-)?(pic|PIC|pie|PIE)`),
118 re(`-fsanitize=([^@\-].*)`),
119 re(`-g([^@\-].*)?`),
120 re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
121 re(`-mmacosx-(.+)`),
122 re(`-mios-simulator-version-min=(.+)`),
123 re(`-miphoneos-version-min=(.+)`),
124 re(`-mwindows`),
125 re(`-(pic|PIC|pie|PIE)`),
126 re(`-pthread`),
127 re(`-shared`),
128 re(`-?-static([-a-z0-9+]*)`),
129 re(`-?-stdlib=([^@\-].*)`),
131 // Note that any wildcards in -Wl need to exclude comma,
132 // since -Wl splits its argument at commas and passes
133 // them all to the linker uninterpreted. Allowing comma
134 // in a wildcard would allow tunnelling arbitrary additional
135 // linker arguments through one of these.
136 re(`-Wl,--(no-)?allow-multiple-definition`),
137 re(`-Wl,--(no-)?as-needed`),
138 re(`-Wl,-Bdynamic`),
139 re(`-Wl,-Bstatic`),
140 re(`-Wl,-d[ny]`),
141 re(`-Wl,--disable-new-dtags`),
142 re(`-Wl,--enable-new-dtags`),
143 re(`-Wl,--end-group`),
144 re(`-Wl,-framework,[^,@\-][^,]+`),
145 re(`-Wl,-headerpad_max_install_names`),
146 re(`-Wl,--no-undefined`),
147 re(`-Wl,-rpath[=,]([^,@\-][^,]+)`),
148 re(`-Wl,-search_paths_first`),
149 re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
150 re(`-Wl,--start-group`),
151 re(`-Wl,-?-static`),
152 re(`-Wl,--subsystem,(native|windows|console|posix|xbox)`),
153 re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
154 re(`-Wl,-?-unresolved-symbols=[^,]+`),
155 re(`-Wl,--(no-)?warn-([^,]+)`),
156 re(`-Wl,-z,(no)?execstack`),
157 re(`-Wl,-z,relro`),
159 re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
162 var validLinkerFlagsWithNextArg = []string{
163 "-arch",
164 "-F",
165 "-l",
166 "-L",
167 "-framework",
168 "-isysroot",
169 "--sysroot",
170 "-target",
171 "-Wl,-framework",
172 "-Wl,-rpath",
173 "-Wl,-undefined",
176 func checkCompilerFlags(name, source string, list []string) error {
177 return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
180 func checkLinkerFlags(name, source string, list []string) error {
181 return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
184 func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
185 // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
186 var (
187 allow *regexp.Regexp
188 disallow *regexp.Regexp
190 if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
191 r, err := regexp.Compile(env)
192 if err != nil {
193 return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
195 allow = r
197 if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
198 r, err := regexp.Compile(env)
199 if err != nil {
200 return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
202 disallow = r
205 Args:
206 for i := 0; i < len(list); i++ {
207 arg := list[i]
208 if disallow != nil && disallow.FindString(arg) == arg {
209 goto Bad
211 if allow != nil && allow.FindString(arg) == arg {
212 continue Args
214 for _, re := range valid {
215 if re.FindString(arg) == arg { // must be complete match
216 continue Args
219 for _, x := range validNext {
220 if arg == x {
221 if i+1 < len(list) && load.SafeArg(list[i+1]) {
223 continue Args
226 // Permit -Wl,-framework -Wl,name.
227 if i+1 < len(list) &&
228 strings.HasPrefix(arg, "-Wl,") &&
229 strings.HasPrefix(list[i+1], "-Wl,") &&
230 load.SafeArg(list[i+1][4:]) &&
231 !strings.Contains(list[i+1][4:], ",") {
233 continue Args
236 if i+1 < len(list) {
237 return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
239 return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
242 Bad:
243 return fmt.Errorf("invalid flag in %s: %s", source, arg)
245 return nil