diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 71 |
1 files changed, 26 insertions, 45 deletions
diff --git a/fs/namei.c b/fs/namei.c index 017c3fa3a08e..0a601cae23de 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -737,14 +737,31 @@ static inline void path_to_nameidata(const struct path *path, | |||
737 | nd->path.dentry = path->dentry; | 737 | nd->path.dentry = path->dentry; |
738 | } | 738 | } |
739 | 739 | ||
740 | static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) | ||
741 | { | ||
742 | struct inode *inode = link->dentry->d_inode; | ||
743 | if (!IS_ERR(cookie) && inode->i_op->put_link) | ||
744 | inode->i_op->put_link(link->dentry, nd, cookie); | ||
745 | path_put(link); | ||
746 | } | ||
747 | |||
740 | static __always_inline int | 748 | static __always_inline int |
741 | __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | 749 | follow_link(struct path *link, struct nameidata *nd, void **p) |
742 | { | 750 | { |
743 | int error; | 751 | int error; |
744 | struct dentry *dentry = link->dentry; | 752 | struct dentry *dentry = link->dentry; |
745 | 753 | ||
746 | BUG_ON(nd->flags & LOOKUP_RCU); | 754 | BUG_ON(nd->flags & LOOKUP_RCU); |
747 | 755 | ||
756 | if (unlikely(current->total_link_count >= 40)) { | ||
757 | *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */ | ||
758 | path_put_conditional(link, nd); | ||
759 | path_put(&nd->path); | ||
760 | return -ELOOP; | ||
761 | } | ||
762 | cond_resched(); | ||
763 | current->total_link_count++; | ||
764 | |||
748 | touch_atime(link->mnt, dentry); | 765 | touch_atime(link->mnt, dentry); |
749 | nd_set_link(nd, NULL); | 766 | nd_set_link(nd, NULL); |
750 | 767 | ||
@@ -1356,21 +1373,12 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd) | |||
1356 | do { | 1373 | do { |
1357 | struct path link = *path; | 1374 | struct path link = *path; |
1358 | void *cookie; | 1375 | void *cookie; |
1359 | if (unlikely(current->total_link_count >= 40)) { | 1376 | |
1360 | path_put_conditional(path, nd); | 1377 | res = follow_link(&link, nd, &cookie); |
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) | 1378 | if (!res) |
1369 | res = walk_component(nd, path, &nd->last, | 1379 | res = walk_component(nd, path, &nd->last, |
1370 | nd->last_type, LOOKUP_FOLLOW); | 1380 | nd->last_type, LOOKUP_FOLLOW); |
1371 | if (!IS_ERR(cookie) && link.dentry->d_inode->i_op->put_link) | 1381 | put_link(nd, &link, cookie); |
1372 | link.dentry->d_inode->i_op->put_link(link.dentry, nd, cookie); | ||
1373 | path_put(&link); | ||
1374 | } while (res > 0); | 1382 | } while (res > 0); |
1375 | 1383 | ||
1376 | current->link_count--; | 1384 | current->link_count--; |
@@ -1619,27 +1627,15 @@ static int path_lookupat(int dfd, const char *name, | |||
1619 | err = link_path_walk(name, nd); | 1627 | err = link_path_walk(name, nd); |
1620 | 1628 | ||
1621 | if (!err && !(flags & LOOKUP_PARENT)) { | 1629 | if (!err && !(flags & LOOKUP_PARENT)) { |
1622 | int count = 0; | ||
1623 | err = lookup_last(nd, &path); | 1630 | err = lookup_last(nd, &path); |
1624 | while (err > 0) { | 1631 | while (err > 0) { |
1625 | void *cookie; | 1632 | void *cookie; |
1626 | struct path link = path; | 1633 | struct path link = path; |
1627 | struct inode *inode = link.dentry->d_inode; | ||
1628 | |||
1629 | if (count++ > 32) { | ||
1630 | path_put_conditional(&path, nd); | ||
1631 | path_put(&nd->path); | ||
1632 | err = -ELOOP; | ||
1633 | break; | ||
1634 | } | ||
1635 | cond_resched(); | ||
1636 | nd->flags |= LOOKUP_PARENT; | 1634 | nd->flags |= LOOKUP_PARENT; |
1637 | err = __do_follow_link(&link, nd, &cookie); | 1635 | err = follow_link(&link, nd, &cookie); |
1638 | if (!err) | 1636 | if (!err) |
1639 | err = lookup_last(nd, &path); | 1637 | err = lookup_last(nd, &path); |
1640 | if (!IS_ERR(cookie) && inode->i_op->put_link) | 1638 | put_link(nd, &link, cookie); |
1641 | inode->i_op->put_link(link.dentry, nd, cookie); | ||
1642 | path_put(&link); | ||
1643 | } | 1639 | } |
1644 | } | 1640 | } |
1645 | 1641 | ||
@@ -2298,7 +2294,6 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
2298 | struct file *base = NULL; | 2294 | struct file *base = NULL; |
2299 | struct file *filp; | 2295 | struct file *filp; |
2300 | struct path path; | 2296 | struct path path; |
2301 | int count = 0; | ||
2302 | int error; | 2297 | int error; |
2303 | 2298 | ||
2304 | filp = get_empty_filp(); | 2299 | filp = get_empty_filp(); |
@@ -2322,35 +2317,21 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
2322 | filp = do_last(nd, &path, op, pathname); | 2317 | filp = do_last(nd, &path, op, pathname); |
2323 | while (unlikely(!filp)) { /* trailing symlink */ | 2318 | while (unlikely(!filp)) { /* trailing symlink */ |
2324 | struct path link = path; | 2319 | struct path link = path; |
2325 | struct inode *linki = link.dentry->d_inode; | ||
2326 | void *cookie; | 2320 | void *cookie; |
2327 | if (!(nd->flags & LOOKUP_FOLLOW) || count++ == 32) { | 2321 | if (!(nd->flags & LOOKUP_FOLLOW)) { |
2328 | path_put_conditional(&path, nd); | 2322 | path_put_conditional(&path, nd); |
2329 | path_put(&nd->path); | 2323 | path_put(&nd->path); |
2330 | filp = ERR_PTR(-ELOOP); | 2324 | filp = ERR_PTR(-ELOOP); |
2331 | break; | 2325 | break; |
2332 | } | 2326 | } |
2333 | /* | ||
2334 | * This is subtle. Instead of calling do_follow_link() we do | ||
2335 | * the thing by hands. The reason is that this way we have zero | ||
2336 | * link_count and path_walk() (called from ->follow_link) | ||
2337 | * honoring LOOKUP_PARENT. After that we have the parent and | ||
2338 | * last component, i.e. we are in the same situation as after | ||
2339 | * the first path_walk(). Well, almost - if the last component | ||
2340 | * is normal we get its copy stored in nd->last.name and we will | ||
2341 | * have to putname() it when we are done. Procfs-like symlinks | ||
2342 | * just set LAST_BIND. | ||
2343 | */ | ||
2344 | nd->flags |= LOOKUP_PARENT; | 2327 | nd->flags |= LOOKUP_PARENT; |
2345 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | 2328 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); |
2346 | error = __do_follow_link(&link, nd, &cookie); | 2329 | error = follow_link(&link, nd, &cookie); |
2347 | if (unlikely(error)) | 2330 | if (unlikely(error)) |
2348 | filp = ERR_PTR(error); | 2331 | filp = ERR_PTR(error); |
2349 | else | 2332 | else |
2350 | filp = do_last(nd, &path, op, pathname); | 2333 | filp = do_last(nd, &path, op, pathname); |
2351 | if (!IS_ERR(cookie) && linki->i_op->put_link) | 2334 | put_link(nd, &link, cookie); |
2352 | linki->i_op->put_link(link.dentry, nd, cookie); | ||
2353 | path_put(&link); | ||
2354 | } | 2335 | } |
2355 | out: | 2336 | out: |
2356 | if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) | 2337 | if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) |