1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // +build !appengine 5 6 package osutil 7 8 import ( 9 "fmt" 10 "io/ioutil" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "strconv" 15 "strings" 16 "sync" 17 "syscall" 18 "time" 19 "unsafe" 20 ) 21 22 // RemoveAll is similar to os.RemoveAll, but can handle more cases. 23 func RemoveAll(dir string) error { 24 files, _ := ioutil.ReadDir(dir) 25 for _, f := range files { 26 name := filepath.Join(dir, f.Name()) 27 if f.IsDir() { 28 RemoveAll(name) 29 } 30 fn := []byte(name + "\x00") 31 syscall.Syscall(syscall.SYS_UMOUNT2, uintptr(unsafe.Pointer(&fn[0])), syscall.MNT_FORCE, 0) 32 } 33 return os.RemoveAll(dir) 34 } 35 36 func Sandbox(cmd *exec.Cmd, user, net bool) error { 37 if cmd.SysProcAttr == nil { 38 cmd.SysProcAttr = new(syscall.SysProcAttr) 39 } 40 if net { 41 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC | 42 syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID 43 } 44 if user { 45 enabled, uid, gid, err := initSandbox() 46 if err != nil { 47 return err 48 } 49 if enabled { 50 cmd.SysProcAttr.Credential = &syscall.Credential{ 51 Uid: uid, 52 Gid: gid, 53 } 54 } 55 } 56 return nil 57 } 58 59 func SandboxChown(file string) error { 60 enabled, uid, gid, err := initSandbox() 61 if err != nil || !enabled { 62 return err 63 } 64 return os.Chown(file, int(uid), int(gid)) 65 } 66 67 var ( 68 sandboxOnce sync.Once 69 sandboxEnabled = true 70 sandboxUsername = "syzkaller" 71 sandboxUID = ^uint32(0) 72 sandboxGID = ^uint32(0) 73 ) 74 75 func initSandbox() (bool, uint32, uint32, error) { 76 sandboxOnce.Do(func() { 77 if syscall.Getuid() != 0 || os.Getenv("SYZ_DISABLE_SANDBOXING") == "yes" { 78 sandboxEnabled = false 79 return 80 } 81 uid, err := usernameToID("-u") 82 if err != nil { 83 return 84 } 85 gid, err := usernameToID("-g") 86 if err != nil { 87 return 88 } 89 sandboxUID = uid 90 sandboxGID = gid 91 }) 92 if sandboxEnabled && sandboxUID == ^uint32(0) { 93 return false, 0, 0, fmt.Errorf("user %q is not found, can't sandbox command", sandboxUsername) 94 } 95 return sandboxEnabled, sandboxUID, sandboxGID, nil 96 } 97 98 func usernameToID(what string) (uint32, error) { 99 out, err := RunCmd(time.Minute, "", "id", what, sandboxUsername) 100 if err != nil { 101 return 0, err 102 } 103 str := strings.Trim(string(out), " \t\n") 104 id, err := strconv.ParseUint(str, 10, 32) 105 if err != nil { 106 return 0, err 107 } 108 return uint32(id), nil 109 } 110 111 func setPdeathsig(cmd *exec.Cmd) { 112 if cmd.SysProcAttr == nil { 113 cmd.SysProcAttr = new(syscall.SysProcAttr) 114 } 115 cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL 116 } 117 118 func prolongPipe(r, w *os.File) { 119 for sz := 128 << 10; sz <= 2<<20; sz *= 2 { 120 syscall.Syscall(syscall.SYS_FCNTL, w.Fd(), syscall.F_SETPIPE_SZ, uintptr(sz)) 121 } 122 } 123