Skip to content

Commit c1b967d

Browse files
author
Al Viro
committed
nfs: fix UAF on pathwalk running into umount
NFS ->d_revalidate(), ->permission() and ->get_link() need to access some parts of nfs_server when called in RCU mode: server->flags server->caps *(server->io_stats) and, worst of all, call server->nfs_client->rpc_ops->have_delegation (the last one - as NFS_PROTO(inode)->have_delegation()). We really don't want to RCU-delay the entire nfs_free_server() (it would have to be done with schedule_work() from RCU callback, since it can't be made to run from interrupt context), but actual freeing of nfs_server and ->io_stats can be done via call_rcu() just fine. nfs_client part is handled simply by making nfs_free_client() use kfree_rcu(). Acked-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 10a973f commit c1b967d

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

fs/nfs/client.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ void nfs_free_client(struct nfs_client *clp)
246246
put_nfs_version(clp->cl_nfs_mod);
247247
kfree(clp->cl_hostname);
248248
kfree(clp->cl_acceptor);
249-
kfree(clp);
249+
kfree_rcu(clp, rcu);
250250
}
251251
EXPORT_SYMBOL_GPL(nfs_free_client);
252252

@@ -1006,6 +1006,14 @@ struct nfs_server *nfs_alloc_server(void)
10061006
}
10071007
EXPORT_SYMBOL_GPL(nfs_alloc_server);
10081008

1009+
static void delayed_free(struct rcu_head *p)
1010+
{
1011+
struct nfs_server *server = container_of(p, struct nfs_server, rcu);
1012+
1013+
nfs_free_iostats(server->io_stats);
1014+
kfree(server);
1015+
}
1016+
10091017
/*
10101018
* Free up a server record
10111019
*/
@@ -1031,10 +1039,9 @@ void nfs_free_server(struct nfs_server *server)
10311039

10321040
ida_destroy(&server->lockowner_id);
10331041
ida_destroy(&server->openowner_id);
1034-
nfs_free_iostats(server->io_stats);
10351042
put_cred(server->cred);
1036-
kfree(server);
10371043
nfs_release_automount_timer();
1044+
call_rcu(&server->rcu, delayed_free);
10381045
}
10391046
EXPORT_SYMBOL_GPL(nfs_free_server);
10401047

include/linux/nfs_fs_sb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct nfs_client {
124124
char cl_ipaddr[48];
125125
struct net *cl_net;
126126
struct list_head pending_cb_stateids;
127+
struct rcu_head rcu;
127128
};
128129

129130
/*
@@ -265,6 +266,7 @@ struct nfs_server {
265266
const struct cred *cred;
266267
bool has_sec_mnt_opts;
267268
struct kobject kobj;
269+
struct rcu_head rcu;
268270
};
269271

270272
/* Server capabilities */

0 commit comments

Comments
 (0)