Loading ui/build/path.go +46 −5 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ import ( "android/soong/ui/metrics" ) // parsePathDir returns the list of filenames of readable files in a directory. // This does not recurse into subdirectories, and does not contain subdirectory // names in the list. func parsePathDir(dir string) []string { f, err := os.Open(dir) if err != nil { Loading @@ -54,10 +57,12 @@ func parsePathDir(dir string) []string { return ret } // A "lite" version of SetupPath used for dumpvars, or other places that need // minimal overhead (but at the expense of logging). If tmpDir is empty, the // default TMPDIR is used from config. // SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other // places that does not need the full logging capabilities of path_interposer, // wants the minimal performance overhead, and still get the benefits of $PATH // hermeticity. func SetupLitePath(ctx Context, config Config, tmpDir string) { // Don't replace the path twice. if config.pathReplaced { return } Loading @@ -67,6 +72,7 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { origPath, _ := config.Environment().Get("PATH") // If tmpDir is empty, the default TMPDIR is used from config. if tmpDir == "" { tmpDir, _ = config.Environment().Get("TMPDIR") } Loading @@ -74,8 +80,10 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { ensureEmptyDirectoriesExist(ctx, myPath) os.Setenv("PATH", origPath) // Iterate over the ACL configuration of host tools for this build. for name, pathConfig := range paths.Configuration { if !pathConfig.Symlink { // Excludes 'Forbidden' and 'LinuxOnlyPrebuilt' PathConfigs. continue } Loading @@ -88,6 +96,7 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { continue } // Symlink allowed host tools into a directory for hermeticity. err = os.Symlink(origExec, filepath.Join(myPath, name)) if err != nil { ctx.Fatalln("Failed to create symlink:", err) Loading @@ -96,14 +105,26 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { myPath, _ = filepath.Abs(myPath) // Set up the checked-in prebuilts path directory for the current host OS. prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86") myPath = prebuiltsPath + string(os.PathListSeparator) + myPath // Set $PATH to be the directories containing the host tool symlinks, and // the prebuilts directory for the current host OS. config.Environment().Set("PATH", myPath) config.pathReplaced = true } // SetupPath uses the path_interposer to intercept calls to $PATH binaries, and // communicates with the interposer to validate allowed $PATH binaries at // runtime, using logs as a medium. // // This results in hermetic directories in $PATH containing only allowed host // tools for the build, and replaces $PATH to contain *only* these directories, // and enables an incremental restriction of tools allowed in the $PATH without // breaking existing use cases. func SetupPath(ctx Context, config Config) { // Don't replace $PATH twice. if config.pathReplaced { return } Loading @@ -112,9 +133,11 @@ func SetupPath(ctx Context, config Config) { defer ctx.EndTrace() origPath, _ := config.Environment().Get("PATH") // The directory containing symlinks from binaries in $PATH to the interposer. myPath := filepath.Join(config.OutDir(), ".path") interposer := myPath + "_interposer" // Bootstrap the path_interposer Go binary with microfactory. var cfg microfactory.Config cfg.Map("android/soong", "build/soong") cfg.TrimPath, _ = filepath.Abs(".") Loading @@ -122,15 +145,20 @@ func SetupPath(ctx Context, config Config) { ctx.Fatalln("Failed to build path interposer:", err) } // Save the original $PATH in a file. if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil { ctx.Fatalln("Failed to write original path:", err) } // Communication with the path interposer works over log entries. Set up the // listener channel for the log entries here. entries, err := paths.LogListener(ctx.Context, interposer+"_log") if err != nil { ctx.Fatalln("Failed to listen for path logs:", err) } // Loop over all log entry listener channels to validate usage of only // allowed PATH tools at runtime. go func() { for log := range entries { curPid := os.Getpid() Loading @@ -140,6 +168,8 @@ func SetupPath(ctx Context, config Config) { break } } // Compute the error message along with the process tree, including // parents, for this log line. procPrints := []string{ "See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.", } Loading @@ -150,6 +180,7 @@ func SetupPath(ctx Context, config Config) { } } // Validate usage against disallowed or missing PATH tools. config := paths.GetConfig(log.Basename) if config.Error { ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args) Loading @@ -165,8 +196,10 @@ func SetupPath(ctx Context, config Config) { } }() // Create the .path directory. ensureEmptyDirectoriesExist(ctx, myPath) // Compute the full list of binaries available in the original $PATH. var execs []string for _, pathEntry := range filepath.SplitList(origPath) { if pathEntry == "" { Loading @@ -185,8 +218,14 @@ func SetupPath(ctx Context, config Config) { ctx.Fatalln("TEMPORARY_DISABLE_PATH_RESTRICTIONS was a temporary migration method, and is now obsolete.") } // Create symlinks from the path_interposer binary to all binaries for each // directory in the original $PATH. This ensures that during the build, // every call to a binary that's expected to be in the $PATH will be // intercepted by the path_interposer binary, and validated with the // LogEntry listener above at build time. for _, name := range execs { if !paths.GetConfig(name).Symlink { // Ignore host tools that shouldn't be symlinked. continue } Loading @@ -200,11 +239,13 @@ func SetupPath(ctx Context, config Config) { myPath, _ = filepath.Abs(myPath) // We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of // them. // We put some prebuilts in $PATH, since it's infeasible to add dependencies // for all of them. prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86") myPath = prebuiltsPath + string(os.PathListSeparator) + myPath // Replace the $PATH variable with the path_interposer symlinks, and // checked-in prebuilts. config.Environment().Set("PATH", myPath) config.pathReplaced = true } Loading
ui/build/path.go +46 −5 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ import ( "android/soong/ui/metrics" ) // parsePathDir returns the list of filenames of readable files in a directory. // This does not recurse into subdirectories, and does not contain subdirectory // names in the list. func parsePathDir(dir string) []string { f, err := os.Open(dir) if err != nil { Loading @@ -54,10 +57,12 @@ func parsePathDir(dir string) []string { return ret } // A "lite" version of SetupPath used for dumpvars, or other places that need // minimal overhead (but at the expense of logging). If tmpDir is empty, the // default TMPDIR is used from config. // SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other // places that does not need the full logging capabilities of path_interposer, // wants the minimal performance overhead, and still get the benefits of $PATH // hermeticity. func SetupLitePath(ctx Context, config Config, tmpDir string) { // Don't replace the path twice. if config.pathReplaced { return } Loading @@ -67,6 +72,7 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { origPath, _ := config.Environment().Get("PATH") // If tmpDir is empty, the default TMPDIR is used from config. if tmpDir == "" { tmpDir, _ = config.Environment().Get("TMPDIR") } Loading @@ -74,8 +80,10 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { ensureEmptyDirectoriesExist(ctx, myPath) os.Setenv("PATH", origPath) // Iterate over the ACL configuration of host tools for this build. for name, pathConfig := range paths.Configuration { if !pathConfig.Symlink { // Excludes 'Forbidden' and 'LinuxOnlyPrebuilt' PathConfigs. continue } Loading @@ -88,6 +96,7 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { continue } // Symlink allowed host tools into a directory for hermeticity. err = os.Symlink(origExec, filepath.Join(myPath, name)) if err != nil { ctx.Fatalln("Failed to create symlink:", err) Loading @@ -96,14 +105,26 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) { myPath, _ = filepath.Abs(myPath) // Set up the checked-in prebuilts path directory for the current host OS. prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86") myPath = prebuiltsPath + string(os.PathListSeparator) + myPath // Set $PATH to be the directories containing the host tool symlinks, and // the prebuilts directory for the current host OS. config.Environment().Set("PATH", myPath) config.pathReplaced = true } // SetupPath uses the path_interposer to intercept calls to $PATH binaries, and // communicates with the interposer to validate allowed $PATH binaries at // runtime, using logs as a medium. // // This results in hermetic directories in $PATH containing only allowed host // tools for the build, and replaces $PATH to contain *only* these directories, // and enables an incremental restriction of tools allowed in the $PATH without // breaking existing use cases. func SetupPath(ctx Context, config Config) { // Don't replace $PATH twice. if config.pathReplaced { return } Loading @@ -112,9 +133,11 @@ func SetupPath(ctx Context, config Config) { defer ctx.EndTrace() origPath, _ := config.Environment().Get("PATH") // The directory containing symlinks from binaries in $PATH to the interposer. myPath := filepath.Join(config.OutDir(), ".path") interposer := myPath + "_interposer" // Bootstrap the path_interposer Go binary with microfactory. var cfg microfactory.Config cfg.Map("android/soong", "build/soong") cfg.TrimPath, _ = filepath.Abs(".") Loading @@ -122,15 +145,20 @@ func SetupPath(ctx Context, config Config) { ctx.Fatalln("Failed to build path interposer:", err) } // Save the original $PATH in a file. if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil { ctx.Fatalln("Failed to write original path:", err) } // Communication with the path interposer works over log entries. Set up the // listener channel for the log entries here. entries, err := paths.LogListener(ctx.Context, interposer+"_log") if err != nil { ctx.Fatalln("Failed to listen for path logs:", err) } // Loop over all log entry listener channels to validate usage of only // allowed PATH tools at runtime. go func() { for log := range entries { curPid := os.Getpid() Loading @@ -140,6 +168,8 @@ func SetupPath(ctx Context, config Config) { break } } // Compute the error message along with the process tree, including // parents, for this log line. procPrints := []string{ "See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.", } Loading @@ -150,6 +180,7 @@ func SetupPath(ctx Context, config Config) { } } // Validate usage against disallowed or missing PATH tools. config := paths.GetConfig(log.Basename) if config.Error { ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args) Loading @@ -165,8 +196,10 @@ func SetupPath(ctx Context, config Config) { } }() // Create the .path directory. ensureEmptyDirectoriesExist(ctx, myPath) // Compute the full list of binaries available in the original $PATH. var execs []string for _, pathEntry := range filepath.SplitList(origPath) { if pathEntry == "" { Loading @@ -185,8 +218,14 @@ func SetupPath(ctx Context, config Config) { ctx.Fatalln("TEMPORARY_DISABLE_PATH_RESTRICTIONS was a temporary migration method, and is now obsolete.") } // Create symlinks from the path_interposer binary to all binaries for each // directory in the original $PATH. This ensures that during the build, // every call to a binary that's expected to be in the $PATH will be // intercepted by the path_interposer binary, and validated with the // LogEntry listener above at build time. for _, name := range execs { if !paths.GetConfig(name).Symlink { // Ignore host tools that shouldn't be symlinked. continue } Loading @@ -200,11 +239,13 @@ func SetupPath(ctx Context, config Config) { myPath, _ = filepath.Abs(myPath) // We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of // them. // We put some prebuilts in $PATH, since it's infeasible to add dependencies // for all of them. prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86") myPath = prebuiltsPath + string(os.PathListSeparator) + myPath // Replace the $PATH variable with the path_interposer symlinks, and // checked-in prebuilts. config.Environment().Set("PATH", myPath) config.pathReplaced = true }