libgo: update to Go 1.10.3 release
[official-gcc.git] / libgo / go / cmd / go / internal / work / security.go
blob1b82af9c97cad4fe14a69ea634bf2bd827dcafce
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(`-F([^@\-].*)`),
45 re(`-I([^@\-].*)`),
46 re(`-O`),
47 re(`-O([^@\-].*)`),
48 re(`-W`),
49 re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
50 re(`-Wa,-mbig-obj`),
51 re(`-Wp,-D([A-Za-z_].*)`),
52 re(`-ansi`),
53 re(`-f(no-)?asynchronous-unwind-tables`),
54 re(`-f(no-)?blocks`),
55 re(`-f(no-)builtin-[a-zA-Z0-9_]*`),
56 re(`-f(no-)?common`),
57 re(`-f(no-)?constant-cfstrings`),
58 re(`-fdiagnostics-show-note-include-stack`),
59 re(`-f(no-)?eliminate-unused-debug-types`),
60 re(`-f(no-)?exceptions`),
61 re(`-f(no-)?fast-math`),
62 re(`-f(no-)?inline-functions`),
63 re(`-finput-charset=([^@\-].*)`),
64 re(`-f(no-)?fat-lto-objects`),
65 re(`-f(no-)?keep-inline-dllexport`),
66 re(`-f(no-)?lto`),
67 re(`-fmacro-backtrace-limit=(.+)`),
68 re(`-fmessage-length=(.+)`),
69 re(`-f(no-)?modules`),
70 re(`-f(no-)?objc-arc`),
71 re(`-f(no-)?objc-nonfragile-abi`),
72 re(`-f(no-)?objc-legacy-dispatch`),
73 re(`-f(no-)?omit-frame-pointer`),
74 re(`-f(no-)?openmp(-simd)?`),
75 re(`-f(no-)?permissive`),
76 re(`-f(no-)?(pic|PIC|pie|PIE)`),
77 re(`-f(no-)?plt`),
78 re(`-f(no-)?rtti`),
79 re(`-f(no-)?split-stack`),
80 re(`-f(no-)?stack-(.+)`),
81 re(`-f(no-)?strict-aliasing`),
82 re(`-f(un)signed-char`),
83 re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
84 re(`-f(no-)?visibility-inlines-hidden`),
85 re(`-fsanitize=(.+)`),
86 re(`-ftemplate-depth-(.+)`),
87 re(`-fvisibility=(.+)`),
88 re(`-g([^@\-].*)?`),
89 re(`-m32`),
90 re(`-m64`),
91 re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
92 re(`-marm`),
93 re(`-mfloat-abi=([^@\-].*)`),
94 re(`-mfpmath=[0-9a-z,+]*`),
95 re(`-m(no-)?avx[0-9a-z.]*`),
96 re(`-m(no-)?ms-bitfields`),
97 re(`-m(no-)?stack-(.+)`),
98 re(`-mmacosx-(.+)`),
99 re(`-mios-simulator-version-min=(.+)`),
100 re(`-miphoneos-version-min=(.+)`),
101 re(`-mnop-fun-dllimport`),
102 re(`-m(no-)?sse[0-9.]*`),
103 re(`-mthumb(-interwork)?`),
104 re(`-mthreads`),
105 re(`-mwindows`),
106 re(`--param=ssp-buffer-size=[0-9]*`),
107 re(`-pedantic(-errors)?`),
108 re(`-pipe`),
109 re(`-pthread`),
110 re(`-?-std=([^@\-].*)`),
111 re(`-?-stdlib=([^@\-].*)`),
112 re(`--sysroot=([^@\-].*)`),
113 re(`-w`),
114 re(`-x([^@\-].*)`),
117 var validCompilerFlagsWithNextArg = []string{
118 "-arch",
119 "-D",
120 "-I",
121 "-framework",
122 "-isysroot",
123 "-isystem",
124 "--sysroot",
125 "-target",
126 "-x",
129 var validLinkerFlags = []*regexp.Regexp{
130 re(`-F([^@\-].*)`),
131 re(`-l([^@\-].*)`),
132 re(`-L([^@\-].*)`),
133 re(`-O`),
134 re(`-O([^@\-].*)`),
135 re(`-f(no-)?(pic|PIC|pie|PIE)`),
136 re(`-f(no-)?openmp(-simd)?`),
137 re(`-fsanitize=([^@\-].*)`),
138 re(`-g([^@\-].*)?`),
139 re(`-headerpad_max_install_names`),
140 re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
141 re(`-mfloat-abi=([^@\-].*)`),
142 re(`-mmacosx-(.+)`),
143 re(`-mios-simulator-version-min=(.+)`),
144 re(`-miphoneos-version-min=(.+)`),
145 re(`-mthreads`),
146 re(`-mwindows`),
147 re(`-(pic|PIC|pie|PIE)`),
148 re(`-pthread`),
149 re(`-rdynamic`),
150 re(`-shared`),
151 re(`-?-static([-a-z0-9+]*)`),
152 re(`-?-stdlib=([^@\-].*)`),
154 // Note that any wildcards in -Wl need to exclude comma,
155 // since -Wl splits its argument at commas and passes
156 // them all to the linker uninterpreted. Allowing comma
157 // in a wildcard would allow tunnelling arbitrary additional
158 // linker arguments through one of these.
159 re(`-Wl,--(no-)?allow-multiple-definition`),
160 re(`-Wl,--(no-)?allow-shlib-undefined`),
161 re(`-Wl,--(no-)?as-needed`),
162 re(`-Wl,-Bdynamic`),
163 re(`-Wl,-Bstatic`),
164 re(`-WL,-O([^@,\-][^,]*)?`),
165 re(`-Wl,-d[ny]`),
166 re(`-Wl,--disable-new-dtags`),
167 re(`-Wl,-e[=,][a-zA-Z0-9]*`),
168 re(`-Wl,--enable-new-dtags`),
169 re(`-Wl,--end-group`),
170 re(`-Wl,-framework,[^,@\-][^,]+`),
171 re(`-Wl,-headerpad_max_install_names`),
172 re(`-Wl,--no-undefined`),
173 re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
174 re(`-Wl,-s`),
175 re(`-Wl,-search_paths_first`),
176 re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
177 re(`-Wl,--start-group`),
178 re(`-Wl,-?-static`),
179 re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
180 re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
181 re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
182 re(`-Wl,-?-unresolved-symbols=[^,]+`),
183 re(`-Wl,--(no-)?warn-([^,]+)`),
184 re(`-Wl,-z,(no)?execstack`),
185 re(`-Wl,-z,relro`),
187 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)
188 re(`\./.*\.(a|o|obj|dll|dylib|so)`),
191 var validLinkerFlagsWithNextArg = []string{
192 "-arch",
193 "-F",
194 "-l",
195 "-L",
196 "-framework",
197 "-isysroot",
198 "--sysroot",
199 "-target",
200 "-Wl,-framework",
201 "-Wl,-rpath",
202 "-Wl,-undefined",
205 func checkCompilerFlags(name, source string, list []string) error {
206 return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
209 func checkLinkerFlags(name, source string, list []string) error {
210 return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
213 func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
214 // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
215 var (
216 allow *regexp.Regexp
217 disallow *regexp.Regexp
219 if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
220 r, err := regexp.Compile(env)
221 if err != nil {
222 return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
224 allow = r
226 if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
227 r, err := regexp.Compile(env)
228 if err != nil {
229 return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
231 disallow = r
234 Args:
235 for i := 0; i < len(list); i++ {
236 arg := list[i]
237 if disallow != nil && disallow.FindString(arg) == arg {
238 goto Bad
240 if allow != nil && allow.FindString(arg) == arg {
241 continue Args
243 for _, re := range valid {
244 if re.FindString(arg) == arg { // must be complete match
245 continue Args
248 for _, x := range validNext {
249 if arg == x {
250 if i+1 < len(list) && load.SafeArg(list[i+1]) {
252 continue Args
255 // Permit -Wl,-framework -Wl,name.
256 if i+1 < len(list) &&
257 strings.HasPrefix(arg, "-Wl,") &&
258 strings.HasPrefix(list[i+1], "-Wl,") &&
259 load.SafeArg(list[i+1][4:]) &&
260 !strings.Contains(list[i+1][4:], ",") {
262 continue Args
265 if i+1 < len(list) {
266 return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
268 return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
271 Bad:
272 return fmt.Errorf("invalid flag in %s: %s", source, arg)
274 return nil