Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/cmd/path_interposer/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 6 kB image not shown  

Quelle  main.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This tool tries to prohibit access to tools on the system on which the build
// is run.
//
// The rationale is that if the build uses a binary that is not shipped in the
// source tree, it is unknowable which version of that binary will be installed
// and therefore the output of the build will be unpredictable. Therefore, we
// should make every effort to use only tools under our control.
//
// This is currently implemented by a "sandbox" that sets $PATH to a specific,
// single directory and creates a symlink for every binary in $PATH in it. That
// symlink will point to path_interposer, which then uses an embedded
// configuration to determine whether to allow access to the binary (in which
// case it calls the original executable) or not (in which case it fails). It
// can also optionally log invocations.
//
// This, of course, does not help if one invokes the tool in question with its
// full path.
package main

import (
 "bytes"
 "fmt"
 "io"
 "io/ioutil"
 "os"
 "os/exec"
 "path/filepath"
 "strconv"
 "syscall"

 "android/soong/ui/build/paths"
)

func main() {
 interposer, err := os.Executable()
 if err != nil {
  fmt.Fprintln(os.Stderr, "Unable to locate interposer executable:", err)
  os.Exit(1)
 }

 if fi, err := os.Lstat(interposer); err == nil {
  if fi.Mode()&os.ModeSymlink != 0 {
   link, err := os.Readlink(interposer)
   if err != nil {
    fmt.Fprintln(os.Stderr, "Unable to read link to interposer executable:", err)
    os.Exit(1)
   }
   if filepath.IsAbs(link) {
    interposer = link
   } else {
    interposer = filepath.Join(filepath.Dir(interposer), link)
   }
  }
 } else {
  fmt.Fprintln(os.Stderr, "Unable to stat interposer executable:", err)
  os.Exit(1)
 }

 exitCode, err := Main(os.Stdout, os.Stderr, interposer, os.Args, mainOpts{
  sendLog:       paths.SendLog,
  config:        paths.GetConfig,
  lookupParents: lookupParents,
 })
 if err != nil {
  fmt.Fprintln(os.Stderr, err.Error())
 }
 os.Exit(exitCode)
}

var usage = fmt.Errorf(`To use the PATH interposer:
 * Write the original PATH variable to <interposer>_origpath
 * Set up a directory of symlinks to the PATH interposer, and use that in PATH

If a tool isn't in the allowed list, a log will be posted to the unix domain
socket at <interposer>_log.`)

type mainOpts struct {
 sendLog       func(logSocket string, entry *paths.LogEntry, done chan interface{})
 config        func(name string) paths.PathConfig
 lookupParents func() []paths.LogProcess
}

func Main(stdout, stderr io.Writer, interposer string, args []string, opts mainOpts) (int, error) {
 base := filepath.Base(args[0])

 origPathFile := interposer + "_origpath"
 if base == filepath.Base(interposer) {
  return 1, usage
 }

 origPath, err := ioutil.ReadFile(origPathFile)
 if err != nil {
  if os.IsNotExist(err) {
   return 1, usage
  } else {
   return 1, fmt.Errorf("Failed to read original PATH: %v", err)
  }
 }

 cmd := &exec.Cmd{
  Args: args,
  Env:  os.Environ(),

  Stdin:  os.Stdin,
  Stdout: stdout,
  Stderr: stderr,
 }

 if err := os.Setenv("PATH", string(origPath)); err != nil {
  return 1, fmt.Errorf("Failed to set PATH env: %v", err)
 }

 if config := opts.config(base); config.Log || config.Error {
  var procs []paths.LogProcess
  if opts.lookupParents != nil {
   procs = opts.lookupParents()
  }

  if opts.sendLog != nil {
   waitForLog := make(chan interface{})
   opts.sendLog(interposer+"_log", &paths.LogEntry{
    Basename: base,
    Args:     args,
    Parents:  procs,
   }, waitForLog)
   defer func() { <-waitForLog }()
  }
  if config.Error {
   return 1, fmt.Errorf("%q is not allowed to be used. See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.", base)
  }
 }

 cmd.Path, err = exec.LookPath(base)
 if err != nil {
  return 1, err
 }

 if err = cmd.Run(); err != nil {
  if exitErr, ok := err.(*exec.ExitError); ok {
   if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
    if status.Exited() {
     return status.ExitStatus(), nil
    } else if status.Signaled() {
     exitCode := 128 + int(status.Signal())
     return exitCode, nil
    } else {
     return 1, exitErr
    }
   } else {
    return 1, nil
   }
  }
 }

 return 0, nil
}

type procEntry struct {
 Pid     int
 Ppid    int
 Command string
}

func readProcs() map[int]procEntry {
 cmd := exec.Command("ps", "-o", "pid,ppid,command")
 data, err := cmd.Output()
 if err != nil {
  return nil
 }

 return parseProcs(data)
}

func parseProcs(data []byte) map[int]procEntry {
 lines := bytes.Split(data, []byte("\n"))
 if len(lines) < 2 {
  return nil
 }
 // Remove the header
 lines = lines[1:]

 ret := make(map[int]procEntry, len(lines))
 for _, line := range lines {
  fields := bytes.SplitN(line, []byte(" "), 2)
  if len(fields) != 2 {
   continue
  }

  pid, err := strconv.Atoi(string(fields[0]))
  if err != nil {
   continue
  }

  line = bytes.TrimLeft(fields[1], " ")

  fields = bytes.SplitN(line, []byte(" "), 2)
  if len(fields) != 2 {
   continue
  }

  ppid, err := strconv.Atoi(string(fields[0]))
  if err != nil {
   continue
  }

  ret[pid] = procEntry{
   Pid:     pid,
   Ppid:    ppid,
   Command: string(bytes.TrimLeft(fields[1], " ")),
  }
 }

 return ret
}

func lookupParents() []paths.LogProcess {
 procs := readProcs()
 if procs == nil {
  return nil
 }

 list := []paths.LogProcess{}
 pid := os.Getpid()
 for {
  entry, ok := procs[pid]
  if !ok {
   break
  }

  list = append([]paths.LogProcess{
   {
    Pid:     pid,
    Command: entry.Command,
   },
  }, list...)

  pid = entry.Ppid
 }

 return list
}

[Dauer der Verarbeitung: 0.21 Sekunden, vorverarbeitet 2026-06-28]