afs: Fix dynamic root lookup DNS check
[ Upstream commit 74cef6872ceaefb5b6c5c60641371ea28702d358 ]
In the afs dynamic root directory, the ->lookup() function does a DNS check
on the cell being asked for and if the DNS upcall reports an error it will
report an error back to userspace (typically ENOENT).
However, if a failed DNS upcall returns a new-style result, it will return
a valid result, with the status field set appropriately to indicate the
type of failure - and in that case, dns_query() doesn't return an error and
we let stat() complete with no error - which can cause confusion in
userspace as subsequent calls that trigger d_automount then fail with
ENOENT.
Fix this by checking the status result from a valid dns_query() and
returning an error if it indicates a failure.
Fixes: bbb4c4323a
("dns: Allow the dns resolver to retrieve a server set")
Reported-by: Markus Suvanto <markus.suvanto@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=216637
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Markus Suvanto <markus.suvanto@gmail.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
3f85785bc4
Коммит
56eaa3ec31
|
@ -113,6 +113,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
|
|||
struct afs_net *net = afs_d2net(dentry);
|
||||
const char *name = dentry->d_name.name;
|
||||
size_t len = dentry->d_name.len;
|
||||
char *result = NULL;
|
||||
int ret;
|
||||
|
||||
/* Names prefixed with a dot are R/W mounts. */
|
||||
|
@ -130,9 +131,22 @@ static int afs_probe_cell_name(struct dentry *dentry)
|
|||
}
|
||||
|
||||
ret = dns_query(net->net, "afsdb", name, len, "srv=1",
|
||||
NULL, NULL, false);
|
||||
if (ret == -ENODATA || ret == -ENOKEY)
|
||||
&result, NULL, false);
|
||||
if (ret == -ENODATA || ret == -ENOKEY || ret == 0)
|
||||
ret = -ENOENT;
|
||||
if (ret > 0 && ret >= sizeof(struct dns_server_list_v1_header)) {
|
||||
struct dns_server_list_v1_header *v1 = (void *)result;
|
||||
|
||||
if (v1->hdr.zero == 0 &&
|
||||
v1->hdr.content == DNS_PAYLOAD_IS_SERVER_LIST &&
|
||||
v1->hdr.version == 1 &&
|
||||
(v1->status != DNS_LOOKUP_GOOD &&
|
||||
v1->status != DNS_LOOKUP_GOOD_WITH_BAD))
|
||||
return -ENOENT;
|
||||
|
||||
}
|
||||
|
||||
kfree(result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче