You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A Go program on Linux, *BSD, AIX, Solaris or Darwin is currently able to control the working directory and root directory of new processes launched with os.StartProcess by setting the (os.ProcAttr).Dir and (syscall.SysProcAttr).Chroot fields, respectively. In contrast, there is no way to control the file-creation mode mask (umask) attribute of started processes without introducing a race condition or paying a performance penalty to start an extraneous process or thread. I propose extending the syscall.SysProcAttr structs on the aforementioned platforms to permit setting the child's umask.
New processes inherit the umask value of the parent, so one might think they could control the umask by writing something like:
// DO NOT DO THISruntime.LockOSThread() // Does nothing to prevent the race condition below.deferruntime.UnlockOSThread()
old:=syscall.Umask(newUmask) // RACE CONDITION: modifies the umask attribute for the whole process.defersyscall.Umask(old) // Ditto.return os.StartProcess(...) // New process gets newUmask, maybe.
Because all threads of a Go process share the same working directory, root directory and umask attributes, any files created by other goroutines between the two syscall.Umask calls would be affected by the temporary umask change, and multiple goroutines interleaving temporary umask changes could result in an incorrect umask being restored.
The race conditions can be avoided by changing the umask in an execution context which does not share file system attributes with the threads of the Go process which goroutines execute on. The most portable method to do so requires performing an extra fork+exec (for example) though as of Go 1.10 a slightly less expensive alternative can be used on Linux which "only" costs one extra thread and the need to worry about #27505.
// Linux only:gofunc() {
runtime.LockOSThread()
// This operation is irreversible so the thread cannot be reused for other goroutines.syscall.Unshare(syscall.CLONE_FS)
syscall.Umask(newUmask) // Only affects the current goroutine, and any processes spawned from it.
os.StartProcess(...)
// Return without calling runtime.UnlockOSThread() so the thread terminates.// The runtime will have to spawn a new thread at some point to replace it.
}()
The extra process/thread would not be needed if the umask could be set between fork and exec, exactly like how the working directory and root directory are currently set when spawning child processes.
The text was updated successfully, but these errors were encountered:
A Go program on Linux, *BSD, AIX, Solaris or Darwin is currently able to control the working directory and root directory of new processes launched with
os.StartProcess
by setting the(os.ProcAttr).Dir
and(syscall.SysProcAttr).Chroot
fields, respectively. In contrast, there is no way to control the file-creation mode mask (umask) attribute of started processes without introducing a race condition or paying a performance penalty to start an extraneous process or thread. I propose extending thesyscall.SysProcAttr
structs on the aforementioned platforms to permit setting the child's umask.New processes inherit the umask value of the parent, so one might think they could control the umask by writing something like:
Because all threads of a Go process share the same working directory, root directory and umask attributes, any files created by other goroutines between the two
syscall.Umask
calls would be affected by the temporary umask change, and multiple goroutines interleaving temporary umask changes could result in an incorrect umask being restored.The race conditions can be avoided by changing the umask in an execution context which does not share file system attributes with the threads of the Go process which goroutines execute on. The most portable method to do so requires performing an extra fork+exec (for example) though as of Go 1.10 a slightly less expensive alternative can be used on Linux which "only" costs one extra thread and the need to worry about #27505.
The extra process/thread would not be needed if the umask could be set between fork and exec, exactly like how the working directory and root directory are currently set when spawning child processes.
The text was updated successfully, but these errors were encountered: