diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 21:54:55 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-15 17:16:25 -0400 |
commit | b356379a020bb7197603118bb1cbc903963aa198 (patch) | |
tree | 834722d850b2f6a82a07464680244847ed477755 /fs | |
parent | ce0525449da56444948c368f52e10f3db0465338 (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.c | 104 |
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 | */ | ||
789 | static 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; | ||
810 | loop: | ||
811 | path_put_conditional(path, nd); | ||
812 | path_put(&nd->path); | ||
813 | return err; | ||
814 | } | ||
815 | |||
816 | static int follow_up_rcu(struct path *path) | 782 | static 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 | */ | ||
1342 | static 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 | ||
1460 | last_with_slashes: | ||
1461 | lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | ||
1462 | last_component: | 1469 | last_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); |