From: Ben Pfaff Date: Mon, 18 Apr 2011 18:24:50 +0000 (-0700) Subject: socket-util: Properly set socket permissions in make_unix_socket(). X-Git-Tag: v1.1.1~21 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=2556693b6dfa48afdd39c891350fb6e0a8013374 socket-util: Properly set socket permissions in make_unix_socket(). Under Linux, at least, bind and fchmod interact for Unix sockets in a way that surprised me. Calling fchmod() on a Unix socket successfully sets the permissions for the socket's own inode. But that has no effect on any inode that has already been created in the file system by bind(), because that inode is not the same as the one for the Unix socket itself. However, if you bind() *after* calling fchmod(), then the bind() takes the permissions for the new inode from the Unix socket inode, which has the desired effect. This also adds a more portable fallback for non-Linux systems. Reported-by: YAMAMOTO Takashi --- diff --git a/lib/socket-util.c b/lib/socket-util.c index 12bbc716d..7e4b8be84 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -302,6 +302,24 @@ make_sockaddr_un(const char *name, struct sockaddr_un *un, socklen_t *un_len, } } +/* Binds Unix domain socket 'fd' to a file with permissions 0700. */ +static int +bind_unix_socket(int fd, struct sockaddr *sun, socklen_t sun_len) +{ +#ifdef __linux__ + /* On Linux, calling fchmod() *before* bind() sets permissions for the file + * about to be created. Calling fchmod() *after* bind has no effect on the + * file that was created.) */ + return fchmod(fd, 0700) || bind(fd, sun, sun_len) ? errno : 0; +#else + /* According to _Unix Network Programming_, umask should affect bind(). */ + mode_t old_umask = umask(0077); + int error = bind(fd, sun, sun_len) ? errno : 0; + umask(old_umask); + return error; +#endif +} + /* Creates a Unix domain socket in the given 'style' (either SOCK_DGRAM or * SOCK_STREAM) that is bound to '*bind_path' (if 'bind_path' is non-null) and * connected to '*connect_path' (if 'connect_path' is non-null). If 'nonblock' @@ -348,9 +366,8 @@ make_unix_socket(int style, bool nonblock, bool passcred OVS_UNUSED, fatal_signal_add_file_to_unlink(bind_path); error = make_sockaddr_un(bind_path, &un, &un_len, &dirfd); - if (!error && (bind(fd, (struct sockaddr*) &un, un_len) - || fchmod(fd, S_IRWXU))) { - error = errno; + if (!error) { + error = bind_unix_socket(fd, (struct sockaddr *) &un, un_len); } if (dirfd >= 0) { close(dirfd);