aboutsummaryrefslogtreecommitdiffstats
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
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>
-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);