Skip to content
/ linux Public

Commit db4a9f9

Browse files
chucklevergregkh
authored andcommitted
NFSD: Hold net reference for the lifetime of /proc/fs/nfs/exports fd
commit e7fcf17 upstream. The /proc/fs/nfs/exports proc entry is created at module init and persists for the module's lifetime. exports_proc_open() captures the caller's current network namespace and stores its svc_export_cache in seq->private, but takes no reference on the namespace. If the namespace is subsequently torn down (e.g. container destruction after the opener does setns() to a different namespace), nfsd_net_exit() calls nfsd_export_shutdown() which frees the cache. Subsequent reads on the still-open fd dereference the freed cache_detail, walking a freed hash table. Hold a reference on the struct net for the lifetime of the open file descriptor. This prevents nfsd_net_exit() from running -- and thus prevents nfsd_export_shutdown() from freeing the cache -- while any exports fd is open. cache_detail already stores its net pointer (cd->net, set by cache_create_net()), so exports_release() can retrieve it without additional per-file storage. Reported-by: Misbah Anjum N <misanjum@linux.ibm.com> Closes: https://lore.kernel.org/linux-nfs/dcd371d3a95815a84ba7de52cef447b8@linux.ibm.com/ Fixes: 96d851c ("nfsd: use proper net while reading "exports" file") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: NeilBrown <neil@brown.name> Tested-by: Olga Kornievskaia <okorniev@redhat.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2829e80 commit db4a9f9

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

fs/nfsd/nfsctl.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,19 @@ static int exports_net_open(struct net *net, struct file *file)
149149

150150
seq = file->private_data;
151151
seq->private = nn->svc_export_cache;
152+
get_net(net);
152153
return 0;
153154
}
154155

156+
static int exports_release(struct inode *inode, struct file *file)
157+
{
158+
struct seq_file *seq = file->private_data;
159+
struct cache_detail *cd = seq->private;
160+
161+
put_net(cd->net);
162+
return seq_release(inode, file);
163+
}
164+
155165
static int exports_nfsd_open(struct inode *inode, struct file *file)
156166
{
157167
return exports_net_open(inode->i_sb->s_fs_info, file);
@@ -161,7 +171,7 @@ static const struct file_operations exports_nfsd_operations = {
161171
.open = exports_nfsd_open,
162172
.read = seq_read,
163173
.llseek = seq_lseek,
164-
.release = seq_release,
174+
.release = exports_release,
165175
};
166176

167177
static int export_features_show(struct seq_file *m, void *v)
@@ -1375,7 +1385,7 @@ static const struct proc_ops exports_proc_ops = {
13751385
.proc_open = exports_proc_open,
13761386
.proc_read = seq_read,
13771387
.proc_lseek = seq_lseek,
1378-
.proc_release = seq_release,
1388+
.proc_release = exports_release,
13791389
};
13801390

13811391
static int create_proc_exports_entry(void)

0 commit comments

Comments
 (0)