github.com/Cloud-Foundations/Dominator@v0.3.4/lib/wsyscall/wrappers_linux.go (about) 1 //go:build go1.11.6 || go1.12 2 // +build go1.11.6 go1.12 3 4 // Go versions prior to 1.10 would re-use a thread that was locked to a 5 // goroutine that exited. While go1.10 prevented thread re-use, it wasn't until 6 // go1.11.6/go1.12 that this was reliable: 7 // https://github.com/golang/go/issues/28979 8 9 package wsyscall 10 11 import ( 12 "errors" 13 "os" 14 "runtime" 15 "strconv" 16 "syscall" 17 ) 18 19 const ( 20 S_IFBLK = syscall.S_IFBLK 21 S_IFCHR = syscall.S_IFCHR 22 S_IFDIR = syscall.S_IFDIR 23 S_IFIFO = syscall.S_IFIFO 24 S_IFLNK = syscall.S_IFLNK 25 S_IFMT = syscall.S_IFMT 26 S_IFREG = syscall.S_IFREG 27 S_IFSOCK = syscall.S_IFSOCK 28 S_IREAD = syscall.S_IREAD 29 S_IRGRP = syscall.S_IRGRP 30 S_IROTH = syscall.S_IROTH 31 S_IRUSR = syscall.S_IRUSR 32 S_IRWXG = syscall.S_IRWXG 33 S_IRWXO = syscall.S_IRWXO 34 S_IRWXU = syscall.S_IRWXU 35 S_ISGID = syscall.S_ISGID 36 S_ISUID = syscall.S_ISUID 37 S_ISVTX = syscall.S_ISVTX 38 S_IWGRP = syscall.S_IWGRP 39 S_IWOTH = syscall.S_IWOTH 40 S_IWRITE = syscall.S_IWRITE 41 S_IWUSR = syscall.S_IWUSR 42 S_IXGRP = syscall.S_IXGRP 43 S_IXOTH = syscall.S_IXOTH 44 S_IXUSR = syscall.S_IXUSR 45 46 sys_SETNS = 308 // 64 bit only. 47 ) 48 49 func convertStat(dest *Stat_t, source *syscall.Stat_t) { 50 dest.Dev = source.Dev 51 dest.Ino = source.Ino 52 dest.Nlink = uint64(source.Nlink) 53 dest.Mode = source.Mode 54 dest.Uid = source.Uid 55 dest.Gid = source.Gid 56 dest.Rdev = source.Rdev 57 dest.Size = source.Size 58 dest.Blksize = int64(source.Blksize) 59 dest.Blocks = source.Blocks 60 dest.Atim = source.Atim 61 dest.Mtim = source.Mtim 62 dest.Ctim = source.Ctim 63 } 64 65 func dup(oldfd int) (int, error) { 66 return syscall.Dup(oldfd) 67 } 68 69 // Arm64 linux does NOT support the Dup2 syscall 70 // https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html 71 // and dup3 is more supported so doing it here: 72 func dup2(oldfd int, newfd int) error { 73 return syscall.Dup3(oldfd, newfd, 0) 74 } 75 76 func dup3(oldfd int, newfd int, flags int) error { 77 return syscall.Dup3(oldfd, newfd, flags) 78 } 79 80 func fallocate(fd int, mode uint32, off int64, len int64) error { 81 return syscall.Fallocate(fd, mode, off, len) 82 } 83 84 func getFileDescriptorLimit() (uint64, uint64, error) { 85 var rlim syscall.Rlimit 86 if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil { 87 return 0, 0, err 88 } 89 return rlim.Cur, rlim.Max, nil 90 } 91 92 func getrusage(who int, rusage *Rusage) error { 93 switch who { 94 case RUSAGE_CHILDREN: 95 who = syscall.RUSAGE_CHILDREN 96 case RUSAGE_SELF: 97 who = syscall.RUSAGE_SELF 98 case RUSAGE_THREAD: 99 who = syscall.RUSAGE_THREAD 100 default: 101 return syscall.ENOTSUP 102 } 103 var syscallRusage syscall.Rusage 104 if err := syscall.Getrusage(who, &syscallRusage); err != nil { 105 return err 106 } 107 rusage.Utime.Sec = int64(syscallRusage.Utime.Sec) 108 rusage.Utime.Usec = int64(syscallRusage.Utime.Usec) 109 rusage.Stime.Sec = int64(syscallRusage.Stime.Sec) 110 rusage.Stime.Usec = int64(syscallRusage.Stime.Usec) 111 rusage.Maxrss = int64(syscallRusage.Maxrss) 112 rusage.Ixrss = int64(syscallRusage.Ixrss) 113 rusage.Idrss = int64(syscallRusage.Idrss) 114 rusage.Minflt = int64(syscallRusage.Minflt) 115 rusage.Majflt = int64(syscallRusage.Majflt) 116 rusage.Nswap = int64(syscallRusage.Nswap) 117 rusage.Inblock = int64(syscallRusage.Inblock) 118 rusage.Oublock = int64(syscallRusage.Oublock) 119 rusage.Msgsnd = int64(syscallRusage.Msgsnd) 120 rusage.Msgrcv = int64(syscallRusage.Msgrcv) 121 rusage.Nsignals = int64(syscallRusage.Nsignals) 122 rusage.Nvcsw = int64(syscallRusage.Nvcsw) 123 rusage.Nivcsw = int64(syscallRusage.Nivcsw) 124 return nil 125 } 126 127 func ioctl(fd int, request, argp uintptr) error { 128 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), request, 129 argp) 130 if errno != 0 { 131 return os.NewSyscallError("ioctl", errno) 132 } 133 return nil 134 } 135 136 func lstat(path string, statbuf *Stat_t) error { 137 var rawStatbuf syscall.Stat_t 138 if err := syscall.Lstat(path, &rawStatbuf); err != nil { 139 return err 140 } 141 convertStat(statbuf, &rawStatbuf) 142 return nil 143 } 144 145 func mount(source string, target string, fstype string, flags uintptr, 146 data string) error { 147 var linuxFlags uintptr 148 if flags&MS_BIND != 0 { 149 linuxFlags |= syscall.MS_BIND 150 } 151 if flags&MS_RDONLY != 0 { 152 linuxFlags |= syscall.MS_RDONLY 153 } 154 return syscall.Mount(source, target, fstype, linuxFlags, data) 155 } 156 157 func reboot() error { 158 return syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART) 159 } 160 161 func setAllGid(gid int) error { 162 return syscall.Setresgid(gid, gid, gid) 163 } 164 165 func setAllUid(uid int) error { 166 return syscall.Setresuid(uid, uid, uid) 167 } 168 169 // setMyPriority sets the priority of the current process, for all OS threads. 170 // It will iterate over all the threads and set the priority on each, since the 171 // Linux implementation of setpriority(2) only applies to a thread, not the 172 // whole process (contrary to the POSIX specification). 173 func setMyPriority(priority int) error { 174 file, err := os.Open("/proc/self/task") 175 if err != nil { 176 return err 177 } 178 defer file.Close() 179 taskNames, err := file.Readdirnames(0) 180 if err != nil { 181 return err 182 } 183 for _, taskName := range taskNames { 184 taskId, err := strconv.Atoi(taskName) 185 if err != nil { 186 return err 187 } 188 err = syscall.Setpriority(syscall.PRIO_PROCESS, taskId, priority) 189 if err != nil { 190 return err 191 } 192 } 193 return nil 194 } 195 196 func setNetNamespace(namespaceFd int) error { 197 runtime.LockOSThread() 198 _, _, errno := syscall.Syscall(sys_SETNS, uintptr(namespaceFd), 199 uintptr(syscall.CLONE_NEWNET), 0) 200 if errno != 0 { 201 return os.NewSyscallError("setns", errno) 202 } 203 return nil 204 205 } 206 207 func stat(path string, statbuf *Stat_t) error { 208 var rawStatbuf syscall.Stat_t 209 if err := syscall.Stat(path, &rawStatbuf); err != nil { 210 return err 211 } 212 convertStat(statbuf, &rawStatbuf) 213 return nil 214 } 215 216 func unshareMountNamespace() error { 217 // Pin goroutine to OS thread. This hack is required because 218 // syscall.Unshare() operates on only one thread in the process, and Go 219 // switches execution between threads randomly. Thus, the namespace can be 220 // suddenly switched for running code. This is an aspect of Go that was not 221 // well thought out. 222 runtime.LockOSThread() 223 if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil { 224 return errors.New("error unsharing mount namespace: " + err.Error()) 225 } 226 err := syscall.Mount("none", "/", "", syscall.MS_REC|syscall.MS_PRIVATE, "") 227 if err != nil { 228 return errors.New("error making mounts private: " + err.Error()) 229 } 230 return nil 231 } 232 233 func sync() error { 234 syscall.Sync() 235 return nil 236 } 237 238 func unshareNetNamespace() (int, int, error) { 239 runtime.LockOSThread() 240 if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil { 241 return -1, -1, 242 errors.New("error unsharing net namespace: " + err.Error()) 243 } 244 tid := syscall.Gettid() 245 tidString := strconv.FormatInt(int64(tid), 10) 246 fd, err := syscall.Open("/proc/"+tidString+"/ns/net", syscall.O_RDONLY, 0) 247 if err != nil { 248 return -1, -1, 249 errors.New("error getting FD for namespace: " + err.Error()) 250 } 251 return fd, tid, nil 252 }