github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/src/cmd/go/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 main
    31  
    32  import (
    33  	"fmt"
    34  	"os"
    35  	"regexp"
    36  )
    37  
    38  var re = regexp.MustCompile
    39  
    40  var validCompilerFlags = []*regexp.Regexp{
    41  	re(`-D([A-Za-z_].*)`),
    42  	re(`-I([^@\-].*)`),
    43  	re(`-O`),
    44  	re(`-O([^@\-].*)`),
    45  	re(`-W`),
    46  	re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
    47  	re(`-f(no-)?objc-arc`),
    48  	re(`-f(no-)?omit-frame-pointer`),
    49  	re(`-f(no-)?(pic|PIC|pie|PIE)`),
    50  	re(`-f(no-)?split-stack`),
    51  	re(`-f(no-)?stack-(.+)`),
    52  	re(`-f(no-)?strict-aliasing`),
    53  	re(`-fsanitize=(.+)`),
    54  	re(`-g([^@\-].*)?`),
    55  	re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
    56  	re(`-m(no-)?stack-(.+)`),
    57  	re(`-mmacosx-(.+)`),
    58  	re(`-mnop-fun-dllimport`),
    59  	re(`-pthread`),
    60  	re(`-std=([^@\-].*)`),
    61  	re(`-x([^@\-].*)`),
    62  }
    63  
    64  var validCompilerFlagsWithNextArg = []string{
    65  	"-D",
    66  	"-I",
    67  	"-framework",
    68  	"-x",
    69  }
    70  
    71  var validLinkerFlags = []*regexp.Regexp{
    72  	re(`-F([^@\-].*)`),
    73  	re(`-l([^@\-].*)`),
    74  	re(`-L([^@\-].*)`),
    75  	re(`-f(no-)?(pic|PIC|pie|PIE)`),
    76  	re(`-fsanitize=([^@\-].*)`),
    77  	re(`-g([^@\-].*)?`),
    78  	re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
    79  	re(`-(pic|PIC|pie|PIE)`),
    80  	re(`-pthread`),
    81  
    82  	// Note that any wildcards in -Wl need to exclude comma,
    83  	// since -Wl splits its argument at commas and passes
    84  	// them all to the linker uninterpreted. Allowing comma
    85  	// in a wildcard would allow tunnelling arbitrary additional
    86  	// linker arguments through one of these.
    87  	re(`-Wl,-rpath,([^,@\-][^,]+)`),
    88  	re(`-Wl,--(no-)?warn-([^,]+)`),
    89  
    90  	re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
    91  }
    92  
    93  var validLinkerFlagsWithNextArg = []string{
    94  	"-F",
    95  	"-l",
    96  	"-L",
    97  	"-framework",
    98  }
    99  
   100  func checkCompilerFlags(name, source string, list []string) error {
   101  	return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
   102  }
   103  
   104  func checkLinkerFlags(name, source string, list []string) error {
   105  	return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
   106  }
   107  
   108  func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
   109  	// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
   110  	var (
   111  		allow    *regexp.Regexp
   112  		disallow *regexp.Regexp
   113  	)
   114  	if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
   115  		r, err := regexp.Compile(env)
   116  		if err != nil {
   117  			return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
   118  		}
   119  		allow = r
   120  	}
   121  	if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
   122  		r, err := regexp.Compile(env)
   123  		if err != nil {
   124  			return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
   125  		}
   126  		disallow = r
   127  	}
   128  
   129  Args:
   130  	for i := 0; i < len(list); i++ {
   131  		arg := list[i]
   132  		if disallow != nil && disallow.FindString(arg) == arg {
   133  			goto Bad
   134  		}
   135  		if allow != nil && allow.FindString(arg) == arg {
   136  			continue Args
   137  		}
   138  		for _, re := range valid {
   139  			if re.FindString(arg) == arg { // must be complete match
   140  				continue Args
   141  			}
   142  		}
   143  		for _, x := range validNext {
   144  			if arg == x {
   145  				if i+1 < len(list) && SafeArg(list[i+1]) {
   146  					i++
   147  					continue Args
   148  				}
   149  				if i+1 < len(list) {
   150  					return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1])
   151  				}
   152  				return fmt.Errorf("invalid flag in %s: %s without argument", source, arg)
   153  			}
   154  		}
   155  	Bad:
   156  		return fmt.Errorf("invalid flag in %s: %s", source, arg)
   157  	}
   158  	return nil
   159  }