aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/client.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2014-07-31 07:35:20 -0400
committerEric W. Biederman <ebiederm@xmission.com>2014-08-04 12:28:32 -0400
commit65b38851a17472d31fec9019fc3a55b0802dab88 (patch)
tree4b5830300b5cbd722f5b1680b96aaa5e72c0d638 /fs/nfs/client.c
parentdb181ce011e3c033328608299cd6fac06ea50130 (diff)
NFS: Fix /proc/fs/nfsfs/servers and /proc/fs/nfsfs/volumes
The usage of pid_ns->child_reaper->nsproxy->net_ns in nfs_server_list_open and nfs_client_list_open is not safe. /proc for a pid namespace can remain mounted after the all of the process in that pid namespace have exited. There are also times before the initial process in a pid namespace has started or after the initial process in a pid namespace has exited where pid_ns->child_reaper can be NULL or stale. Making the idiom pid_ns->child_reaper->nsproxy a double whammy of problems. Luckily all that needs to happen is to move /proc/fs/nfsfs/servers and /proc/fs/nfsfs/volumes under /proc/net to /proc/net/nfsfs/servers and /proc/net/nfsfs/volumes and add a symlink from the original location, and to use seq_open_net as it has been designed. Cc: stable@vger.kernel.org Cc: Trond Myklebust <trond.myklebust@primarydata.com> Cc: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r--fs/nfs/client.c95
1 files changed, 55 insertions, 40 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 1d09289c8f0e..180d1ec9c32e 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1205,7 +1205,7 @@ static const struct file_operations nfs_server_list_fops = {
1205 .open = nfs_server_list_open, 1205 .open = nfs_server_list_open,
1206 .read = seq_read, 1206 .read = seq_read,
1207 .llseek = seq_lseek, 1207 .llseek = seq_lseek,
1208 .release = seq_release, 1208 .release = seq_release_net,
1209 .owner = THIS_MODULE, 1209 .owner = THIS_MODULE,
1210}; 1210};
1211 1211
@@ -1226,7 +1226,7 @@ static const struct file_operations nfs_volume_list_fops = {
1226 .open = nfs_volume_list_open, 1226 .open = nfs_volume_list_open,
1227 .read = seq_read, 1227 .read = seq_read,
1228 .llseek = seq_lseek, 1228 .llseek = seq_lseek,
1229 .release = seq_release, 1229 .release = seq_release_net,
1230 .owner = THIS_MODULE, 1230 .owner = THIS_MODULE,
1231}; 1231};
1232 1232
@@ -1236,19 +1236,8 @@ static const struct file_operations nfs_volume_list_fops = {
1236 */ 1236 */
1237static int nfs_server_list_open(struct inode *inode, struct file *file) 1237static int nfs_server_list_open(struct inode *inode, struct file *file)
1238{ 1238{
1239 struct seq_file *m; 1239 return seq_open_net(inode, file, &nfs_server_list_ops,
1240 int ret; 1240 sizeof(struct seq_net_private));
1241 struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
1242 struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
1243
1244 ret = seq_open(file, &nfs_server_list_ops);
1245 if (ret < 0)
1246 return ret;
1247
1248 m = file->private_data;
1249 m->private = net;
1250
1251 return 0;
1252} 1241}
1253 1242
1254/* 1243/*
@@ -1256,7 +1245,7 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
1256 */ 1245 */
1257static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) 1246static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
1258{ 1247{
1259 struct nfs_net *nn = net_generic(m->private, nfs_net_id); 1248 struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1260 1249
1261 /* lock the list against modification */ 1250 /* lock the list against modification */
1262 spin_lock(&nn->nfs_client_lock); 1251 spin_lock(&nn->nfs_client_lock);
@@ -1268,7 +1257,7 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
1268 */ 1257 */
1269static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) 1258static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
1270{ 1259{
1271 struct nfs_net *nn = net_generic(p->private, nfs_net_id); 1260 struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1272 1261
1273 return seq_list_next(v, &nn->nfs_client_list, pos); 1262 return seq_list_next(v, &nn->nfs_client_list, pos);
1274} 1263}
@@ -1278,7 +1267,7 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
1278 */ 1267 */
1279static void nfs_server_list_stop(struct seq_file *p, void *v) 1268static void nfs_server_list_stop(struct seq_file *p, void *v)
1280{ 1269{
1281 struct nfs_net *nn = net_generic(p->private, nfs_net_id); 1270 struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1282 1271
1283 spin_unlock(&nn->nfs_client_lock); 1272 spin_unlock(&nn->nfs_client_lock);
1284} 1273}
@@ -1289,7 +1278,7 @@ static void nfs_server_list_stop(struct seq_file *p, void *v)
1289static int nfs_server_list_show(struct seq_file *m, void *v) 1278static int nfs_server_list_show(struct seq_file *m, void *v)
1290{ 1279{
1291 struct nfs_client *clp; 1280 struct nfs_client *clp;
1292 struct nfs_net *nn = net_generic(m->private, nfs_net_id); 1281 struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1293 1282
1294 /* display header on line 1 */ 1283 /* display header on line 1 */
1295 if (v == &nn->nfs_client_list) { 1284 if (v == &nn->nfs_client_list) {
@@ -1321,19 +1310,8 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
1321 */ 1310 */
1322static int nfs_volume_list_open(struct inode *inode, struct file *file) 1311static int nfs_volume_list_open(struct inode *inode, struct file *file)
1323{ 1312{
1324 struct seq_file *m; 1313 return seq_open_net(inode, file, &nfs_server_list_ops,
1325 int ret; 1314 sizeof(struct seq_net_private));
1326 struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
1327 struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
1328
1329 ret = seq_open(file, &nfs_volume_list_ops);
1330 if (ret < 0)
1331 return ret;
1332
1333 m = file->private_data;
1334 m->private = net;
1335
1336 return 0;
1337} 1315}
1338 1316
1339/* 1317/*
@@ -1341,7 +1319,7 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
1341 */ 1319 */
1342static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) 1320static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
1343{ 1321{
1344 struct nfs_net *nn = net_generic(m->private, nfs_net_id); 1322 struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1345 1323
1346 /* lock the list against modification */ 1324 /* lock the list against modification */
1347 spin_lock(&nn->nfs_client_lock); 1325 spin_lock(&nn->nfs_client_lock);
@@ -1353,7 +1331,7 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
1353 */ 1331 */
1354static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) 1332static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
1355{ 1333{
1356 struct nfs_net *nn = net_generic(p->private, nfs_net_id); 1334 struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1357 1335
1358 return seq_list_next(v, &nn->nfs_volume_list, pos); 1336 return seq_list_next(v, &nn->nfs_volume_list, pos);
1359} 1337}
@@ -1363,7 +1341,7 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
1363 */ 1341 */
1364static void nfs_volume_list_stop(struct seq_file *p, void *v) 1342static void nfs_volume_list_stop(struct seq_file *p, void *v)
1365{ 1343{
1366 struct nfs_net *nn = net_generic(p->private, nfs_net_id); 1344 struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1367 1345
1368 spin_unlock(&nn->nfs_client_lock); 1346 spin_unlock(&nn->nfs_client_lock);
1369} 1347}
@@ -1376,7 +1354,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
1376 struct nfs_server *server; 1354 struct nfs_server *server;
1377 struct nfs_client *clp; 1355 struct nfs_client *clp;
1378 char dev[8], fsid[17]; 1356 char dev[8], fsid[17];
1379 struct nfs_net *nn = net_generic(m->private, nfs_net_id); 1357 struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1380 1358
1381 /* display header on line 1 */ 1359 /* display header on line 1 */
1382 if (v == &nn->nfs_volume_list) { 1360 if (v == &nn->nfs_volume_list) {
@@ -1407,6 +1385,45 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
1407 return 0; 1385 return 0;
1408} 1386}
1409 1387
1388int nfs_fs_proc_net_init(struct net *net)
1389{
1390 struct nfs_net *nn = net_generic(net, nfs_net_id);
1391 struct proc_dir_entry *p;
1392
1393 nn->proc_nfsfs = proc_net_mkdir(net, "nfsfs", net->proc_net);
1394 if (!nn->proc_nfsfs)
1395 goto error_0;
1396
1397 /* a file of servers with which we're dealing */
1398 p = proc_create("servers", S_IFREG|S_IRUGO,
1399 nn->proc_nfsfs, &nfs_server_list_fops);
1400 if (!p)
1401 goto error_1;
1402
1403 /* a file of volumes that we have mounted */
1404 p = proc_create("volumes", S_IFREG|S_IRUGO,
1405 nn->proc_nfsfs, &nfs_volume_list_fops);
1406 if (!p)
1407 goto error_2;
1408 return 0;
1409
1410error_2:
1411 remove_proc_entry("servers", nn->proc_nfsfs);
1412error_1:
1413 remove_proc_entry("fs/nfsfs", NULL);
1414error_0:
1415 return -ENOMEM;
1416}
1417
1418void nfs_fs_proc_net_exit(struct net *net)
1419{
1420 struct nfs_net *nn = net_generic(net, nfs_net_id);
1421
1422 remove_proc_entry("volumes", nn->proc_nfsfs);
1423 remove_proc_entry("servers", nn->proc_nfsfs);
1424 remove_proc_entry("fs/nfsfs", NULL);
1425}
1426
1410/* 1427/*
1411 * initialise the /proc/fs/nfsfs/ directory 1428 * initialise the /proc/fs/nfsfs/ directory
1412 */ 1429 */
@@ -1419,14 +1436,12 @@ int __init nfs_fs_proc_init(void)
1419 goto error_0; 1436 goto error_0;
1420 1437
1421 /* a file of servers with which we're dealing */ 1438 /* a file of servers with which we're dealing */
1422 p = proc_create("servers", S_IFREG|S_IRUGO, 1439 p = proc_symlink("servers", proc_fs_nfs, "../../net/nfsfs/servers");
1423 proc_fs_nfs, &nfs_server_list_fops);
1424 if (!p) 1440 if (!p)
1425 goto error_1; 1441 goto error_1;
1426 1442
1427 /* a file of volumes that we have mounted */ 1443 /* a file of volumes that we have mounted */
1428 p = proc_create("volumes", S_IFREG|S_IRUGO, 1444 p = proc_symlink("volumes", proc_fs_nfs, "../../net/nfsfs/volumes");
1429 proc_fs_nfs, &nfs_volume_list_fops);
1430 if (!p) 1445 if (!p)
1431 goto error_2; 1446 goto error_2;
1432 return 0; 1447 return 0;