| |
| |
| |
|
|
| package syscall |
|
|
| import ( |
| "runtime" |
| "unsafe" |
| ) |
|
|
| type SysProcAttr struct { |
| Chroot string |
| Credential *Credential |
| Ptrace bool |
| Setsid bool |
| |
| |
| Setpgid bool |
| |
| |
| |
| |
| Setctty bool |
| Noctty bool |
| Ctty int |
| |
| |
| |
| |
| |
| Foreground bool |
| Pgid int |
| Pdeathsig Signal |
| Jail int |
| } |
|
|
| const ( |
| _P_PID = 0 |
|
|
| _PROC_PDEATHSIG_CTL = 11 |
| ) |
|
|
| |
| func runtime_BeforeFork() |
| func runtime_AfterFork() |
| func runtime_AfterForkInChild() |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { |
| |
| |
| var ( |
| r1 uintptr |
| err1 Errno |
| nextfd int |
| i int |
| pgrp _C_int |
| cred *Credential |
| ngroups, groups uintptr |
| upid, ppid uintptr |
| ) |
|
|
| rlim := origRlimitNofile.Load() |
|
|
| |
| if sys.Pdeathsig != 0 { |
| ppid, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) |
| } |
|
|
| |
| |
| |
| fd := make([]int, len(attr.Files)) |
| nextfd = len(attr.Files) |
| for i, ufd := range attr.Files { |
| if nextfd < int(ufd) { |
| nextfd = int(ufd) |
| } |
| fd[i] = int(ufd) |
| } |
| nextfd++ |
|
|
| |
| |
| runtime_BeforeFork() |
| r1, _, err1 = RawSyscall(SYS_FORK, 0, 0, 0) |
| if err1 != 0 { |
| runtime_AfterFork() |
| return 0, err1 |
| } |
|
|
| if r1 != 0 { |
| |
| runtime_AfterFork() |
| return int(r1), 0 |
| } |
|
|
| |
|
|
| |
| |
| if sys.Jail > 0 { |
| _, _, err1 = RawSyscall(SYS_JAIL_ATTACH, uintptr(sys.Jail), 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if sys.Ptrace { |
| _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if sys.Setsid { |
| _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if sys.Setpgid || sys.Foreground { |
| |
| _, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| if sys.Foreground { |
| |
| |
| pgrp = _C_int(sys.Pgid) |
| if pgrp == 0 { |
| r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
|
|
| pgrp = _C_int(r1) |
| } |
|
|
| |
| _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| |
| runtime_AfterForkInChild() |
|
|
| |
| if chroot != nil { |
| _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if cred = sys.Credential; cred != nil { |
| ngroups = uintptr(len(cred.Groups)) |
| groups = uintptr(0) |
| if ngroups > 0 { |
| groups = uintptr(unsafe.Pointer(&cred.Groups[0])) |
| } |
| if !cred.NoSetGroups { |
| _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
| _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if dir != nil { |
| _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if sys.Pdeathsig != 0 { |
| switch runtime.GOARCH { |
| case "386", "arm": |
| _, _, err1 = RawSyscall6(SYS_PROCCTL, _P_PID, 0, 0, _PROC_PDEATHSIG_CTL, uintptr(unsafe.Pointer(&sys.Pdeathsig)), 0) |
| default: |
| _, _, err1 = RawSyscall6(SYS_PROCCTL, _P_PID, 0, _PROC_PDEATHSIG_CTL, uintptr(unsafe.Pointer(&sys.Pdeathsig)), 0, 0) |
| } |
| if err1 != 0 { |
| goto childerror |
| } |
|
|
| |
| |
| |
| r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0) |
| if r1 != ppid { |
| upid, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) |
| _, _, err1 = RawSyscall(SYS_KILL, upid, uintptr(sys.Pdeathsig), 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
| } |
|
|
| |
| |
| if pipe < nextfd { |
| _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(pipe), F_DUP2FD_CLOEXEC, uintptr(nextfd)) |
| if err1 != 0 { |
| goto childerror |
| } |
| pipe = nextfd |
| nextfd++ |
| } |
| for i = 0; i < len(fd); i++ { |
| if fd[i] >= 0 && fd[i] < i { |
| if nextfd == pipe { |
| nextfd++ |
| } |
| _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_DUP2FD_CLOEXEC, uintptr(nextfd)) |
| if err1 != 0 { |
| goto childerror |
| } |
| fd[i] = nextfd |
| nextfd++ |
| } |
| } |
|
|
| |
| for i = 0; i < len(fd); i++ { |
| if fd[i] == -1 { |
| RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) |
| continue |
| } |
| if fd[i] == i { |
| |
| |
| _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| continue |
| } |
| |
| |
| _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| |
| |
| |
| for i = len(fd); i < 3; i++ { |
| RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) |
| } |
|
|
| |
| if sys.Noctty { |
| _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if sys.Setctty { |
| _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) |
| if err1 != 0 { |
| goto childerror |
| } |
| } |
|
|
| |
| if rlim != nil { |
| RawSyscall(SYS_SETRLIMIT, uintptr(RLIMIT_NOFILE), uintptr(unsafe.Pointer(rlim)), 0) |
| } |
|
|
| |
| _, _, err1 = RawSyscall(SYS_EXECVE, |
| uintptr(unsafe.Pointer(argv0)), |
| uintptr(unsafe.Pointer(&argv[0])), |
| uintptr(unsafe.Pointer(&envv[0]))) |
|
|
| childerror: |
| |
| RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) |
| for { |
| RawSyscall(SYS_EXIT, 253, 0, 0) |
| } |
| } |
|
|
| |
| func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { |
| |
| } |
|
|