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