af_unix: fix hard linked sockets on overlay
Overlayfs uses separate inodes even in the case of hard links on the underlying filesystems. This is a problem for AF_UNIX socket implementation which indexes sockets based on the inode. This resulted in hard linked sockets not working. The fix is to use the real, underlying inode. Test case follows: -- ovl-sock-test.c -- #include <unistd.h> #include <err.h> #include <sys/socket.h> #include <sys/un.h> #define SOCK "test-sock" #define SOCK2 "test-sock2" int main(void) { int fd, fd2; struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = SOCK, }; struct sockaddr_un addr2 = { .sun_family = AF_UNIX, .sun_path = SOCK2, }; unlink(SOCK); unlink(SOCK2); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) err(1, "bind"); if (listen(fd, 0) == -1) err(1, "listen"); if (link(SOCK, SOCK2) == -1) err(1, "link"); if ((fd2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); if (connect(fd2, (struct sockaddr *) &addr2, sizeof(addr2)) == -1) err (1, "connect"); return 0; } ---- Reported-by: Alexander Morozov <alexandr.morozov@docker.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Cc: <stable@vger.kernel.org>
This commit is contained in:
Родитель
a118084432
Коммит
eb0a4a47ae
|
@ -315,7 +315,7 @@ static struct sock *unix_find_socket_byinode(struct inode *i)
|
|||
&unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
|
||||
struct dentry *dentry = unix_sk(s)->path.dentry;
|
||||
|
||||
if (dentry && d_backing_inode(dentry) == i) {
|
||||
if (dentry && d_real_inode(dentry) == i) {
|
||||
sock_hold(s);
|
||||
goto found;
|
||||
}
|
||||
|
@ -911,7 +911,7 @@ static struct sock *unix_find_other(struct net *net,
|
|||
err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
|
||||
if (err)
|
||||
goto fail;
|
||||
inode = d_backing_inode(path.dentry);
|
||||
inode = d_real_inode(path.dentry);
|
||||
err = inode_permission(inode, MAY_WRITE);
|
||||
if (err)
|
||||
goto put_fail;
|
||||
|
@ -1048,7 +1048,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
|||
goto out_up;
|
||||
}
|
||||
addr->hash = UNIX_HASH_SIZE;
|
||||
hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
|
||||
hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
|
||||
spin_lock(&unix_table_lock);
|
||||
u->path = u_path;
|
||||
list = &unix_socket_table[hash];
|
||||
|
|
Загрузка…
Ссылка в новой задаче