]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.6.5/af_unix-fix-hard-linked-sockets-on-overlay.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.6.5 / af_unix-fix-hard-linked-sockets-on-overlay.patch
1 From eb0a4a47ae89aaa0674ab3180de6a162f3be2ddf Mon Sep 17 00:00:00 2001
2 From: Miklos Szeredi <mszeredi@redhat.com>
3 Date: Fri, 20 May 2016 22:13:45 +0200
4 Subject: af_unix: fix hard linked sockets on overlay
5
6 From: Miklos Szeredi <mszeredi@redhat.com>
7
8 commit eb0a4a47ae89aaa0674ab3180de6a162f3be2ddf upstream.
9
10 Overlayfs uses separate inodes even in the case of hard links on the
11 underlying filesystems. This is a problem for AF_UNIX socket
12 implementation which indexes sockets based on the inode. This resulted in
13 hard linked sockets not working.
14
15 The fix is to use the real, underlying inode.
16
17 Test case follows:
18
19 -- ovl-sock-test.c --
20 #include <unistd.h>
21 #include <err.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24
25 #define SOCK "test-sock"
26 #define SOCK2 "test-sock2"
27
28 int main(void)
29 {
30 int fd, fd2;
31 struct sockaddr_un addr = {
32 .sun_family = AF_UNIX,
33 .sun_path = SOCK,
34 };
35 struct sockaddr_un addr2 = {
36 .sun_family = AF_UNIX,
37 .sun_path = SOCK2,
38 };
39
40 unlink(SOCK);
41 unlink(SOCK2);
42 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
43 err(1, "socket");
44 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
45 err(1, "bind");
46 if (listen(fd, 0) == -1)
47 err(1, "listen");
48 if (link(SOCK, SOCK2) == -1)
49 err(1, "link");
50 if ((fd2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
51 err(1, "socket");
52 if (connect(fd2, (struct sockaddr *) &addr2, sizeof(addr2)) == -1)
53 err (1, "connect");
54 return 0;
55 }
56 ----
57
58 Reported-by: Alexander Morozov <alexandr.morozov@docker.com>
59 Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
60 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
61
62 ---
63 net/unix/af_unix.c | 6 +++---
64 1 file changed, 3 insertions(+), 3 deletions(-)
65
66 --- a/net/unix/af_unix.c
67 +++ b/net/unix/af_unix.c
68 @@ -315,7 +315,7 @@ static struct sock *unix_find_socket_byi
69 &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
70 struct dentry *dentry = unix_sk(s)->path.dentry;
71
72 - if (dentry && d_backing_inode(dentry) == i) {
73 + if (dentry && d_real_inode(dentry) == i) {
74 sock_hold(s);
75 goto found;
76 }
77 @@ -911,7 +911,7 @@ static struct sock *unix_find_other(stru
78 err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
79 if (err)
80 goto fail;
81 - inode = d_backing_inode(path.dentry);
82 + inode = d_real_inode(path.dentry);
83 err = inode_permission(inode, MAY_WRITE);
84 if (err)
85 goto put_fail;
86 @@ -1048,7 +1048,7 @@ static int unix_bind(struct socket *sock
87 goto out_up;
88 }
89 addr->hash = UNIX_HASH_SIZE;
90 - hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
91 + hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
92 spin_lock(&unix_table_lock);
93 u->path = u_path;
94 list = &unix_socket_table[hash];