Skip to content

Commit 196500f

Browse files
committed
NewUnixSocketWithOpts(): reduce umask override time-window, document hack
This hack was originally added in moby/moby@24c73ce, but was scarce on information, and this code was cause for some confusion. net.Listen does not allow for permissions to be set. As a result, when specifying custom permissions ("WithChmod()"), there is a short time between creating the socket and applying the permissions, during which the socket permissions are Less restrictive than desired. To work around this limitation of net.Listen(), we temporarily set the umask to 0777, which forces the socket to be created with 000 permissions (i.e.: no access for anyone). After that, WithChmod() must be used to set the desired permissions. This patch also removes the use of `defer` here, so that we can reset the umask to its original value as soon as possible. Ideally we'd be able to detect if WithChmod() was passed as an option, and skip changing umask if default permissions are used. Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent ca1f92b commit 196500f

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

sockets/unix_socket.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func WithChown(uid, gid int) SockOption {
6767
}
6868
}
6969

70-
// WithChmod modifies socket file's access mode
70+
// WithChmod modifies socket file's access mode.
7171
func WithChmod(mask os.FileMode) SockOption {
7272
return func(path string) error {
7373
if err := os.Chmod(path, mask); err != nil {
@@ -77,15 +77,35 @@ func WithChmod(mask os.FileMode) SockOption {
7777
}
7878
}
7979

80-
// NewUnixSocketWithOpts creates a unix socket with the specified options
80+
// NewUnixSocketWithOpts creates a unix socket with the specified options.
81+
// By default, socket permissions are 0000 (i.e.: no access for anyone); pass
82+
// WithChmod() and WithChown() to set the desired ownership and permissions.
83+
//
84+
// This function temporarily changes the system's "umask" to 0777 to work around
85+
// a race condition between creating the socket and setting its permissions. While
86+
// this should only be for a short duration, it may affect other processes that
87+
// create files/directories during that period.
8188
func NewUnixSocketWithOpts(path string, opts ...SockOption) (net.Listener, error) {
8289
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
8390
return nil, err
8491
}
85-
mask := syscall.Umask(0777)
86-
defer syscall.Umask(mask)
8792

93+
// net.Listen does not allow for permissions to be set. As a result, when
94+
// specifying custom permissions ("WithChmod()"), there is a short time
95+
// between creating the socket and applying the permissions, during which
96+
// the socket permissions are Less restrictive than desired.
97+
//
98+
// To work around this limitation of net.Listen(), we temporarily set the
99+
// umask to 0777, which forces the socket to be created with 000 permissions
100+
// (i.e.: no access for anyone). After that, WithChmod() must be used to set
101+
// the desired permissions.
102+
//
103+
// We don't use "defer" here, to reset the umask to its original value as soon
104+
// as possible. Ideally we'd be able to detect if WithChmod() was passed as
105+
// an option, and skip changing umask if default permissions are used.
106+
origUmask := syscall.Umask(0777)
88107
l, err := net.Listen("unix", path)
108+
syscall.Umask(origUmask)
89109
if err != nil {
90110
return nil, err
91111
}

0 commit comments

Comments
 (0)