Skip to content

Commit e7fcf17

Browse files
committed
NFSD: Hold net reference for the lifetime of /proc/fs/nfs/exports fd
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 <[email protected]> Closes: https://lore.kernel.org/linux-nfs/[email protected]/ Fixes: 96d851c ("nfsd: use proper net while reading "exports" file") Cc: [email protected] Reviewed-by: Jeff Layton <[email protected]> Reviewed-by: NeilBrown <[email protected]> Tested-by: Olga Kornievskaia <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 48db892 commit e7fcf17

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

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)
@@ -1376,7 +1386,7 @@ static const struct proc_ops exports_proc_ops = {
13761386
.proc_open = exports_proc_open,
13771387
.proc_read = seq_read,
13781388
.proc_lseek = seq_lseek,
1379-
.proc_release = seq_release,
1389+
.proc_release = exports_release,
13801390
};
13811391

13821392
static int create_proc_exports_entry(void)

0 commit comments

Comments
 (0)