aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-14 21:54:55 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-15 17:16:25 -0400
commitb356379a020bb7197603118bb1cbc903963aa198 (patch)
tree834722d850b2f6a82a07464680244847ed477755 /fs
parentce0525449da56444948c368f52e10f3db0465338 (diff)
Turn resolution of trailing symlinks iterative everywhere
The last remaining place (resolution of nested symlink) converted to the loop of the same kind we have in path_lookupat() and path_openat(). Note that we still *do* have a recursion in pathname resolution; can't avoid it, really. However, it's strictly for nested symlinks now - i.e. ones in the middle of a pathname. link_path_walk() has lost the tail now - it always walks everything except the last component. do_follow_link() renamed to nested_symlink() and moved down. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c104
1 files changed, 50 insertions, 54 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 9575d0039699..017c3fa3a08e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -779,40 +779,6 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
779 return error; 779 return error;
780} 780}
781 781
782/*
783 * This limits recursive symlink follows to 8, while
784 * limiting consecutive symlinks to 40.
785 *
786 * Without that kind of total limit, nasty chains of consecutive
787 * symlinks can cause almost arbitrarily long lookups.
788 */
789static inline int do_follow_link(struct path *path, struct nameidata *nd)
790{
791 void *cookie;
792 int err = -ELOOP;
793
794 if (current->link_count >= MAX_NESTED_LINKS)
795 goto loop;
796 if (current->total_link_count >= 40)
797 goto loop;
798 BUG_ON(nd->depth >= MAX_NESTED_LINKS);
799 cond_resched();
800 current->link_count++;
801 current->total_link_count++;
802 nd->depth++;
803 err = __do_follow_link(path, nd, &cookie);
804 if (!IS_ERR(cookie) && path->dentry->d_inode->i_op->put_link)
805 path->dentry->d_inode->i_op->put_link(path->dentry, nd, cookie);
806 path_put(path);
807 current->link_count--;
808 nd->depth--;
809 return err;
810loop:
811 path_put_conditional(path, nd);
812 path_put(&nd->path);
813 return err;
814}
815
816static int follow_up_rcu(struct path *path) 782static int follow_up_rcu(struct path *path)
817{ 783{
818 struct vfsmount *parent; 784 struct vfsmount *parent;
@@ -1367,6 +1333,52 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
1367} 1333}
1368 1334
1369/* 1335/*
1336 * This limits recursive symlink follows to 8, while
1337 * limiting consecutive symlinks to 40.
1338 *
1339 * Without that kind of total limit, nasty chains of consecutive
1340 * symlinks can cause almost arbitrarily long lookups.
1341 */
1342static inline int nested_symlink(struct path *path, struct nameidata *nd)
1343{
1344 int res;
1345
1346 BUG_ON(nd->depth >= MAX_NESTED_LINKS);
1347 if (unlikely(current->link_count >= MAX_NESTED_LINKS)) {
1348 path_put_conditional(path, nd);
1349 path_put(&nd->path);
1350 return -ELOOP;
1351 }
1352
1353 nd->depth++;
1354 current->link_count++;
1355
1356 do {
1357 struct path link = *path;
1358 void *cookie;
1359 if (unlikely(current->total_link_count >= 40)) {
1360 path_put_conditional(path, nd);
1361 path_put(&nd->path);
1362 res = -ELOOP;
1363 break;
1364 }
1365 cond_resched();
1366 current->total_link_count++;
1367 res = __do_follow_link(&link, nd, &cookie);
1368 if (!res)
1369 res = walk_component(nd, path, &nd->last,
1370 nd->last_type, LOOKUP_FOLLOW);
1371 if (!IS_ERR(cookie) && link.dentry->d_inode->i_op->put_link)
1372 link.dentry->d_inode->i_op->put_link(link.dentry, nd, cookie);
1373 path_put(&link);
1374 } while (res > 0);
1375
1376 current->link_count--;
1377 nd->depth--;
1378 return res;
1379}
1380
1381/*
1370 * Name resolution. 1382 * Name resolution.
1371 * This is the basic name resolution function, turning a pathname into 1383 * This is the basic name resolution function, turning a pathname into
1372 * the final dentry. We expect 'base' to be positive and a directory. 1384 * the final dentry. We expect 'base' to be positive and a directory.
@@ -1385,9 +1397,6 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1385 if (!*name) 1397 if (!*name)
1386 return 0; 1398 return 0;
1387 1399
1388 if (nd->depth)
1389 lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
1390
1391 /* At this point we know we have a real path component. */ 1400 /* At this point we know we have a real path component. */
1392 for(;;) { 1401 for(;;) {
1393 unsigned long hash; 1402 unsigned long hash;
@@ -1440,14 +1449,14 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1440 goto last_component; 1449 goto last_component;
1441 while (*++name == '/'); 1450 while (*++name == '/');
1442 if (!*name) 1451 if (!*name)
1443 goto last_with_slashes; 1452 goto last_component;
1444 1453
1445 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); 1454 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
1446 if (err < 0) 1455 if (err < 0)
1447 return err; 1456 return err;
1448 1457
1449 if (err) { 1458 if (err) {
1450 err = do_follow_link(&next, nd); 1459 err = nested_symlink(&next, nd);
1451 if (err) 1460 if (err)
1452 return err; 1461 return err;
1453 } 1462 }
@@ -1457,24 +1466,11 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1457 continue; 1466 continue;
1458 /* here ends the main loop */ 1467 /* here ends the main loop */
1459 1468
1460last_with_slashes:
1461 lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
1462last_component: 1469last_component:
1463 /* Clear LOOKUP_CONTINUE iff it was previously unset */ 1470 /* Clear LOOKUP_CONTINUE iff it was previously unset */
1464 nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; 1471 nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
1465 if (lookup_flags & LOOKUP_PARENT) { 1472 nd->last = this;
1466 nd->last = this; 1473 nd->last_type = type;
1467 nd->last_type = type;
1468 return 0;
1469 }
1470 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
1471 if (err < 0)
1472 return err;
1473 if (err) {
1474 err = do_follow_link(&next, nd);
1475 if (err)
1476 return err;
1477 }
1478 return 0; 1474 return 0;
1479 } 1475 }
1480 terminate_walk(nd); 1476 terminate_walk(nd);