1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Worker// This tool tries to prohibit access to tools on the system on which the build 16*333d2b36SAndroid Build Coastguard Worker// is run. 17*333d2b36SAndroid Build Coastguard Worker// 18*333d2b36SAndroid Build Coastguard Worker// The rationale is that if the build uses a binary that is not shipped in the 19*333d2b36SAndroid Build Coastguard Worker// source tree, it is unknowable which version of that binary will be installed 20*333d2b36SAndroid Build Coastguard Worker// and therefore the output of the build will be unpredictable. Therefore, we 21*333d2b36SAndroid Build Coastguard Worker// should make every effort to use only tools under our control. 22*333d2b36SAndroid Build Coastguard Worker// 23*333d2b36SAndroid Build Coastguard Worker// This is currently implemented by a "sandbox" that sets $PATH to a specific, 24*333d2b36SAndroid Build Coastguard Worker// single directory and creates a symlink for every binary in $PATH in it. That 25*333d2b36SAndroid Build Coastguard Worker// symlink will point to path_interposer, which then uses an embedded 26*333d2b36SAndroid Build Coastguard Worker// configuration to determine whether to allow access to the binary (in which 27*333d2b36SAndroid Build Coastguard Worker// case it calls the original executable) or not (in which case it fails). It 28*333d2b36SAndroid Build Coastguard Worker// can also optionally log invocations. 29*333d2b36SAndroid Build Coastguard Worker// 30*333d2b36SAndroid Build Coastguard Worker// This, of course, does not help if one invokes the tool in question with its 31*333d2b36SAndroid Build Coastguard Worker// full path. 32*333d2b36SAndroid Build Coastguard Workerpackage main 33*333d2b36SAndroid Build Coastguard Worker 34*333d2b36SAndroid Build Coastguard Workerimport ( 35*333d2b36SAndroid Build Coastguard Worker "bytes" 36*333d2b36SAndroid Build Coastguard Worker "fmt" 37*333d2b36SAndroid Build Coastguard Worker "io" 38*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 39*333d2b36SAndroid Build Coastguard Worker "os" 40*333d2b36SAndroid Build Coastguard Worker "os/exec" 41*333d2b36SAndroid Build Coastguard Worker "path/filepath" 42*333d2b36SAndroid Build Coastguard Worker "strconv" 43*333d2b36SAndroid Build Coastguard Worker "syscall" 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Worker "android/soong/ui/build/paths" 46*333d2b36SAndroid Build Coastguard Worker) 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Workerfunc main() { 49*333d2b36SAndroid Build Coastguard Worker interposer, err := os.Executable() 50*333d2b36SAndroid Build Coastguard Worker if err != nil { 51*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "Unable to locate interposer executable:", err) 52*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 53*333d2b36SAndroid Build Coastguard Worker } 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Worker if fi, err := os.Lstat(interposer); err == nil { 56*333d2b36SAndroid Build Coastguard Worker if fi.Mode()&os.ModeSymlink != 0 { 57*333d2b36SAndroid Build Coastguard Worker link, err := os.Readlink(interposer) 58*333d2b36SAndroid Build Coastguard Worker if err != nil { 59*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "Unable to read link to interposer executable:", err) 60*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 61*333d2b36SAndroid Build Coastguard Worker } 62*333d2b36SAndroid Build Coastguard Worker if filepath.IsAbs(link) { 63*333d2b36SAndroid Build Coastguard Worker interposer = link 64*333d2b36SAndroid Build Coastguard Worker } else { 65*333d2b36SAndroid Build Coastguard Worker interposer = filepath.Join(filepath.Dir(interposer), link) 66*333d2b36SAndroid Build Coastguard Worker } 67*333d2b36SAndroid Build Coastguard Worker } 68*333d2b36SAndroid Build Coastguard Worker } else { 69*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "Unable to stat interposer executable:", err) 70*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 71*333d2b36SAndroid Build Coastguard Worker } 72*333d2b36SAndroid Build Coastguard Worker 73*333d2b36SAndroid Build Coastguard Worker exitCode, err := Main(os.Stdout, os.Stderr, interposer, os.Args, mainOpts{ 74*333d2b36SAndroid Build Coastguard Worker sendLog: paths.SendLog, 75*333d2b36SAndroid Build Coastguard Worker config: paths.GetConfig, 76*333d2b36SAndroid Build Coastguard Worker lookupParents: lookupParents, 77*333d2b36SAndroid Build Coastguard Worker }) 78*333d2b36SAndroid Build Coastguard Worker if err != nil { 79*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 80*333d2b36SAndroid Build Coastguard Worker } 81*333d2b36SAndroid Build Coastguard Worker os.Exit(exitCode) 82*333d2b36SAndroid Build Coastguard Worker} 83*333d2b36SAndroid Build Coastguard Worker 84*333d2b36SAndroid Build Coastguard Workervar usage = fmt.Errorf(`To use the PATH interposer: 85*333d2b36SAndroid Build Coastguard Worker * Write the original PATH variable to <interposer>_origpath 86*333d2b36SAndroid Build Coastguard Worker * Set up a directory of symlinks to the PATH interposer, and use that in PATH 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard WorkerIf a tool isn't in the allowed list, a log will be posted to the unix domain 89*333d2b36SAndroid Build Coastguard Workersocket at <interposer>_log.`) 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Workertype mainOpts struct { 92*333d2b36SAndroid Build Coastguard Worker sendLog func(logSocket string, entry *paths.LogEntry, done chan interface{}) 93*333d2b36SAndroid Build Coastguard Worker config func(name string) paths.PathConfig 94*333d2b36SAndroid Build Coastguard Worker lookupParents func() []paths.LogProcess 95*333d2b36SAndroid Build Coastguard Worker} 96*333d2b36SAndroid Build Coastguard Worker 97*333d2b36SAndroid Build Coastguard Workerfunc Main(stdout, stderr io.Writer, interposer string, args []string, opts mainOpts) (int, error) { 98*333d2b36SAndroid Build Coastguard Worker base := filepath.Base(args[0]) 99*333d2b36SAndroid Build Coastguard Worker 100*333d2b36SAndroid Build Coastguard Worker origPathFile := interposer + "_origpath" 101*333d2b36SAndroid Build Coastguard Worker if base == filepath.Base(interposer) { 102*333d2b36SAndroid Build Coastguard Worker return 1, usage 103*333d2b36SAndroid Build Coastguard Worker } 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Worker origPath, err := ioutil.ReadFile(origPathFile) 106*333d2b36SAndroid Build Coastguard Worker if err != nil { 107*333d2b36SAndroid Build Coastguard Worker if os.IsNotExist(err) { 108*333d2b36SAndroid Build Coastguard Worker return 1, usage 109*333d2b36SAndroid Build Coastguard Worker } else { 110*333d2b36SAndroid Build Coastguard Worker return 1, fmt.Errorf("Failed to read original PATH: %v", err) 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker } 113*333d2b36SAndroid Build Coastguard Worker 114*333d2b36SAndroid Build Coastguard Worker cmd := &exec.Cmd{ 115*333d2b36SAndroid Build Coastguard Worker Args: args, 116*333d2b36SAndroid Build Coastguard Worker Env: os.Environ(), 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Worker Stdin: os.Stdin, 119*333d2b36SAndroid Build Coastguard Worker Stdout: stdout, 120*333d2b36SAndroid Build Coastguard Worker Stderr: stderr, 121*333d2b36SAndroid Build Coastguard Worker } 122*333d2b36SAndroid Build Coastguard Worker 123*333d2b36SAndroid Build Coastguard Worker if err := os.Setenv("PATH", string(origPath)); err != nil { 124*333d2b36SAndroid Build Coastguard Worker return 1, fmt.Errorf("Failed to set PATH env: %v", err) 125*333d2b36SAndroid Build Coastguard Worker } 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Worker if config := opts.config(base); config.Log || config.Error { 128*333d2b36SAndroid Build Coastguard Worker var procs []paths.LogProcess 129*333d2b36SAndroid Build Coastguard Worker if opts.lookupParents != nil { 130*333d2b36SAndroid Build Coastguard Worker procs = opts.lookupParents() 131*333d2b36SAndroid Build Coastguard Worker } 132*333d2b36SAndroid Build Coastguard Worker 133*333d2b36SAndroid Build Coastguard Worker if opts.sendLog != nil { 134*333d2b36SAndroid Build Coastguard Worker waitForLog := make(chan interface{}) 135*333d2b36SAndroid Build Coastguard Worker opts.sendLog(interposer+"_log", &paths.LogEntry{ 136*333d2b36SAndroid Build Coastguard Worker Basename: base, 137*333d2b36SAndroid Build Coastguard Worker Args: args, 138*333d2b36SAndroid Build Coastguard Worker Parents: procs, 139*333d2b36SAndroid Build Coastguard Worker }, waitForLog) 140*333d2b36SAndroid Build Coastguard Worker defer func() { <-waitForLog }() 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker if config.Error { 143*333d2b36SAndroid Build Coastguard Worker 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) 144*333d2b36SAndroid Build Coastguard Worker } 145*333d2b36SAndroid Build Coastguard Worker } 146*333d2b36SAndroid Build Coastguard Worker 147*333d2b36SAndroid Build Coastguard Worker cmd.Path, err = exec.LookPath(base) 148*333d2b36SAndroid Build Coastguard Worker if err != nil { 149*333d2b36SAndroid Build Coastguard Worker return 1, err 150*333d2b36SAndroid Build Coastguard Worker } 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker if err = cmd.Run(); err != nil { 153*333d2b36SAndroid Build Coastguard Worker if exitErr, ok := err.(*exec.ExitError); ok { 154*333d2b36SAndroid Build Coastguard Worker if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { 155*333d2b36SAndroid Build Coastguard Worker if status.Exited() { 156*333d2b36SAndroid Build Coastguard Worker return status.ExitStatus(), nil 157*333d2b36SAndroid Build Coastguard Worker } else if status.Signaled() { 158*333d2b36SAndroid Build Coastguard Worker exitCode := 128 + int(status.Signal()) 159*333d2b36SAndroid Build Coastguard Worker return exitCode, nil 160*333d2b36SAndroid Build Coastguard Worker } else { 161*333d2b36SAndroid Build Coastguard Worker return 1, exitErr 162*333d2b36SAndroid Build Coastguard Worker } 163*333d2b36SAndroid Build Coastguard Worker } else { 164*333d2b36SAndroid Build Coastguard Worker return 1, nil 165*333d2b36SAndroid Build Coastguard Worker } 166*333d2b36SAndroid Build Coastguard Worker } 167*333d2b36SAndroid Build Coastguard Worker } 168*333d2b36SAndroid Build Coastguard Worker 169*333d2b36SAndroid Build Coastguard Worker return 0, nil 170*333d2b36SAndroid Build Coastguard Worker} 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Workertype procEntry struct { 173*333d2b36SAndroid Build Coastguard Worker Pid int 174*333d2b36SAndroid Build Coastguard Worker Ppid int 175*333d2b36SAndroid Build Coastguard Worker Command string 176*333d2b36SAndroid Build Coastguard Worker} 177*333d2b36SAndroid Build Coastguard Worker 178*333d2b36SAndroid Build Coastguard Workerfunc readProcs() map[int]procEntry { 179*333d2b36SAndroid Build Coastguard Worker cmd := exec.Command("ps", "-o", "pid,ppid,command") 180*333d2b36SAndroid Build Coastguard Worker data, err := cmd.Output() 181*333d2b36SAndroid Build Coastguard Worker if err != nil { 182*333d2b36SAndroid Build Coastguard Worker return nil 183*333d2b36SAndroid Build Coastguard Worker } 184*333d2b36SAndroid Build Coastguard Worker 185*333d2b36SAndroid Build Coastguard Worker return parseProcs(data) 186*333d2b36SAndroid Build Coastguard Worker} 187*333d2b36SAndroid Build Coastguard Worker 188*333d2b36SAndroid Build Coastguard Workerfunc parseProcs(data []byte) map[int]procEntry { 189*333d2b36SAndroid Build Coastguard Worker lines := bytes.Split(data, []byte("\n")) 190*333d2b36SAndroid Build Coastguard Worker if len(lines) < 2 { 191*333d2b36SAndroid Build Coastguard Worker return nil 192*333d2b36SAndroid Build Coastguard Worker } 193*333d2b36SAndroid Build Coastguard Worker // Remove the header 194*333d2b36SAndroid Build Coastguard Worker lines = lines[1:] 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Worker ret := make(map[int]procEntry, len(lines)) 197*333d2b36SAndroid Build Coastguard Worker for _, line := range lines { 198*333d2b36SAndroid Build Coastguard Worker fields := bytes.SplitN(line, []byte(" "), 2) 199*333d2b36SAndroid Build Coastguard Worker if len(fields) != 2 { 200*333d2b36SAndroid Build Coastguard Worker continue 201*333d2b36SAndroid Build Coastguard Worker } 202*333d2b36SAndroid Build Coastguard Worker 203*333d2b36SAndroid Build Coastguard Worker pid, err := strconv.Atoi(string(fields[0])) 204*333d2b36SAndroid Build Coastguard Worker if err != nil { 205*333d2b36SAndroid Build Coastguard Worker continue 206*333d2b36SAndroid Build Coastguard Worker } 207*333d2b36SAndroid Build Coastguard Worker 208*333d2b36SAndroid Build Coastguard Worker line = bytes.TrimLeft(fields[1], " ") 209*333d2b36SAndroid Build Coastguard Worker 210*333d2b36SAndroid Build Coastguard Worker fields = bytes.SplitN(line, []byte(" "), 2) 211*333d2b36SAndroid Build Coastguard Worker if len(fields) != 2 { 212*333d2b36SAndroid Build Coastguard Worker continue 213*333d2b36SAndroid Build Coastguard Worker } 214*333d2b36SAndroid Build Coastguard Worker 215*333d2b36SAndroid Build Coastguard Worker ppid, err := strconv.Atoi(string(fields[0])) 216*333d2b36SAndroid Build Coastguard Worker if err != nil { 217*333d2b36SAndroid Build Coastguard Worker continue 218*333d2b36SAndroid Build Coastguard Worker } 219*333d2b36SAndroid Build Coastguard Worker 220*333d2b36SAndroid Build Coastguard Worker ret[pid] = procEntry{ 221*333d2b36SAndroid Build Coastguard Worker Pid: pid, 222*333d2b36SAndroid Build Coastguard Worker Ppid: ppid, 223*333d2b36SAndroid Build Coastguard Worker Command: string(bytes.TrimLeft(fields[1], " ")), 224*333d2b36SAndroid Build Coastguard Worker } 225*333d2b36SAndroid Build Coastguard Worker } 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Worker return ret 228*333d2b36SAndroid Build Coastguard Worker} 229*333d2b36SAndroid Build Coastguard Worker 230*333d2b36SAndroid Build Coastguard Workerfunc lookupParents() []paths.LogProcess { 231*333d2b36SAndroid Build Coastguard Worker procs := readProcs() 232*333d2b36SAndroid Build Coastguard Worker if procs == nil { 233*333d2b36SAndroid Build Coastguard Worker return nil 234*333d2b36SAndroid Build Coastguard Worker } 235*333d2b36SAndroid Build Coastguard Worker 236*333d2b36SAndroid Build Coastguard Worker list := []paths.LogProcess{} 237*333d2b36SAndroid Build Coastguard Worker pid := os.Getpid() 238*333d2b36SAndroid Build Coastguard Worker for { 239*333d2b36SAndroid Build Coastguard Worker entry, ok := procs[pid] 240*333d2b36SAndroid Build Coastguard Worker if !ok { 241*333d2b36SAndroid Build Coastguard Worker break 242*333d2b36SAndroid Build Coastguard Worker } 243*333d2b36SAndroid Build Coastguard Worker 244*333d2b36SAndroid Build Coastguard Worker list = append([]paths.LogProcess{ 245*333d2b36SAndroid Build Coastguard Worker { 246*333d2b36SAndroid Build Coastguard Worker Pid: pid, 247*333d2b36SAndroid Build Coastguard Worker Command: entry.Command, 248*333d2b36SAndroid Build Coastguard Worker }, 249*333d2b36SAndroid Build Coastguard Worker }, list...) 250*333d2b36SAndroid Build Coastguard Worker 251*333d2b36SAndroid Build Coastguard Worker pid = entry.Ppid 252*333d2b36SAndroid Build Coastguard Worker } 253*333d2b36SAndroid Build Coastguard Worker 254*333d2b36SAndroid Build Coastguard Worker return list 255*333d2b36SAndroid Build Coastguard Worker} 256