github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/osutil/osutil_linux.go (about) 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 package osutil 5 6 import ( 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strconv" 12 "strings" 13 "sync" 14 "syscall" 15 "time" 16 17 "golang.org/x/sys/unix" 18 ) 19 20 // RemoveAll is similar to os.RemoveAll, but can handle more cases. 21 func RemoveAll(dir string) error { 22 files, _ := os.ReadDir(dir) 23 for _, f := range files { 24 name := filepath.Join(dir, f.Name()) 25 if f.IsDir() { 26 RemoveAll(name) 27 } 28 unix.Unmount(name, unix.MNT_FORCE) 29 } 30 if err := os.RemoveAll(dir); err != nil { 31 removeImmutable(dir) 32 return os.RemoveAll(dir) 33 } 34 return nil 35 } 36 37 func SystemMemorySize() uint64 { 38 var info syscall.Sysinfo_t 39 syscall.Sysinfo(&info) 40 return uint64(info.Totalram) // nolint:unconvert 41 } 42 43 func removeImmutable(fname string) error { 44 // Reset FS_XFLAG_IMMUTABLE/FS_XFLAG_APPEND. 45 fd, err := syscall.Open(fname, syscall.O_RDONLY, 0) 46 if err != nil { 47 return err 48 } 49 defer syscall.Close(fd) 50 return unix.IoctlSetPointerInt(fd, unix.FS_IOC_SETFLAGS, 0) 51 } 52 53 func Sandbox(cmd *exec.Cmd, user, net bool) error { 54 enabled, uid, gid, err := initSandbox() 55 if err != nil || !enabled { 56 return err 57 } 58 if cmd.SysProcAttr == nil { 59 cmd.SysProcAttr = new(syscall.SysProcAttr) 60 } 61 if net { 62 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC | 63 syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID 64 } 65 if user { 66 cmd.SysProcAttr.Credential = &syscall.Credential{ 67 Uid: uid, 68 Gid: gid, 69 } 70 } 71 return nil 72 } 73 74 func SandboxChown(file string) error { 75 enabled, uid, gid, err := initSandbox() 76 if err != nil || !enabled { 77 return err 78 } 79 return os.Chown(file, int(uid), int(gid)) 80 } 81 82 var ( 83 sandboxOnce sync.Once 84 sandboxEnabled = true 85 sandboxUsername = "syzkaller" 86 sandboxUID = ^uint32(0) 87 sandboxGID = ^uint32(0) 88 ) 89 90 func initSandbox() (bool, uint32, uint32, error) { 91 sandboxOnce.Do(func() { 92 if syscall.Getuid() != 0 || os.Getenv("CI") != "" || os.Getenv("SYZ_DISABLE_SANDBOXING") == "yes" { 93 sandboxEnabled = false 94 return 95 } 96 uid, err := usernameToID("-u") 97 if err != nil { 98 return 99 } 100 gid, err := usernameToID("-g") 101 if err != nil { 102 return 103 } 104 sandboxUID = uid 105 sandboxGID = gid 106 }) 107 if sandboxEnabled && sandboxUID == ^uint32(0) { 108 return false, 0, 0, fmt.Errorf("user %q is not found, can't sandbox command", sandboxUsername) 109 } 110 return sandboxEnabled, sandboxUID, sandboxGID, nil 111 } 112 113 func usernameToID(what string) (uint32, error) { 114 out, err := RunCmd(time.Minute, "", "id", what, sandboxUsername) 115 if err != nil { 116 return 0, err 117 } 118 str := strings.Trim(string(out), " \t\n") 119 id, err := strconv.ParseUint(str, 10, 32) 120 if err != nil { 121 return 0, err 122 } 123 return uint32(id), nil 124 } 125 126 func setPdeathsig(cmd *exec.Cmd, hardKill bool) { 127 if cmd.SysProcAttr == nil { 128 cmd.SysProcAttr = new(syscall.SysProcAttr) 129 } 130 if hardKill { 131 cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL 132 } else { 133 cmd.SysProcAttr.Pdeathsig = syscall.SIGTERM 134 } 135 // We will kill the whole process group. 136 cmd.SysProcAttr.Setpgid = true 137 } 138 139 func killPgroup(cmd *exec.Cmd) { 140 syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) 141 } 142 143 func prolongPipe(r, w *os.File) { 144 for sz := 128 << 10; sz <= 2<<20; sz *= 2 { 145 syscall.Syscall(syscall.SYS_FCNTL, w.Fd(), syscall.F_SETPIPE_SZ, uintptr(sz)) 146 } 147 }