提交 b4254745 编写于 作者: M Marc Dionne 提交者: Yang Yingliang

afs: Fix afs_find_server lookups for ipv4 peers

[ Upstream commit 9bd0160d12370a076e44f8d1320cde9c83f2c647 ]

afs_find_server tries to find a server that has an address that
matches the transport address of an rxrpc peer.  The code assumes
that the transport address is always ipv6, with ipv4 represented
as ipv4 mapped addresses, but that's not the case.  If the transport
family is AF_INET, srx->transport.sin6.sin6_addr.s6_addr32[] will
be beyond the actual ipv4 address and will always be 0, and all
ipv4 addresses will be seen as matching.

As a result, the first ipv4 address seen on any server will be
considered a match, and the server returned may be the wrong one.

One of the consequences is that callbacks received over ipv4 will
only be correctly applied for the server that happens to have the
first ipv4 address on the fs_addresses4 list.  Callbacks over ipv4
from all other servers are dropped, causing the client to serve stale
data.

This is fixed by looking at the transport family, and comparing ipv4
addresses based on a sockaddr_in structure rather than a sockaddr_in6.

Fixes: d2ddc776 ("afs: Overhaul volume and server record caching and fileserver rotation")
Signed-off-by: NMarc Dionne <marc.dionne@auristor.com>
Signed-off-by: NDavid Howells <dhowells@redhat.com>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 1e3a1eab
...@@ -34,18 +34,11 @@ static void afs_dec_servers_outstanding(struct afs_net *net) ...@@ -34,18 +34,11 @@ static void afs_dec_servers_outstanding(struct afs_net *net)
struct afs_server *afs_find_server(struct afs_net *net, struct afs_server *afs_find_server(struct afs_net *net,
const struct sockaddr_rxrpc *srx) const struct sockaddr_rxrpc *srx)
{ {
const struct sockaddr_in6 *a = &srx->transport.sin6, *b;
const struct afs_addr_list *alist; const struct afs_addr_list *alist;
struct afs_server *server = NULL; struct afs_server *server = NULL;
unsigned int i; unsigned int i;
bool ipv6 = true;
int seq = 0, diff; int seq = 0, diff;
if (srx->transport.sin6.sin6_addr.s6_addr32[0] == 0 ||
srx->transport.sin6.sin6_addr.s6_addr32[1] == 0 ||
srx->transport.sin6.sin6_addr.s6_addr32[2] == htonl(0xffff))
ipv6 = false;
rcu_read_lock(); rcu_read_lock();
do { do {
...@@ -54,7 +47,8 @@ struct afs_server *afs_find_server(struct afs_net *net, ...@@ -54,7 +47,8 @@ struct afs_server *afs_find_server(struct afs_net *net,
server = NULL; server = NULL;
read_seqbegin_or_lock(&net->fs_addr_lock, &seq); read_seqbegin_or_lock(&net->fs_addr_lock, &seq);
if (ipv6) { if (srx->transport.family == AF_INET6) {
const struct sockaddr_in6 *a = &srx->transport.sin6, *b;
hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) { hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) {
alist = rcu_dereference(server->addresses); alist = rcu_dereference(server->addresses);
for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
...@@ -70,15 +64,16 @@ struct afs_server *afs_find_server(struct afs_net *net, ...@@ -70,15 +64,16 @@ struct afs_server *afs_find_server(struct afs_net *net,
} }
} }
} else { } else {
const struct sockaddr_in *a = &srx->transport.sin, *b;
hlist_for_each_entry_rcu(server, &net->fs_addresses4, addr4_link) { hlist_for_each_entry_rcu(server, &net->fs_addresses4, addr4_link) {
alist = rcu_dereference(server->addresses); alist = rcu_dereference(server->addresses);
for (i = 0; i < alist->nr_ipv4; i++) { for (i = 0; i < alist->nr_ipv4; i++) {
b = &alist->addrs[i].transport.sin6; b = &alist->addrs[i].transport.sin;
diff = ((u16 __force)a->sin6_port - diff = ((u16 __force)a->sin_port -
(u16 __force)b->sin6_port); (u16 __force)b->sin_port);
if (diff == 0) if (diff == 0)
diff = ((u32 __force)a->sin6_addr.s6_addr32[3] - diff = ((u32 __force)a->sin_addr.s_addr -
(u32 __force)b->sin6_addr.s6_addr32[3]); (u32 __force)b->sin_addr.s_addr);
if (diff == 0) if (diff == 0)
goto found; goto found;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册