diff options
| -rw-r--r-- | fs/namei.c | 55 |
1 files changed, 24 insertions, 31 deletions
diff --git a/fs/namei.c b/fs/namei.c index adfbaf5c04a7..1f5d86d1fbf5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -498,8 +498,6 @@ static int link_path_walk(const char *, struct nameidata *); | |||
| 498 | 498 | ||
| 499 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 499 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
| 500 | { | 500 | { |
| 501 | int res = 0; | ||
| 502 | char *name; | ||
| 503 | if (IS_ERR(link)) | 501 | if (IS_ERR(link)) |
| 504 | goto fail; | 502 | goto fail; |
| 505 | 503 | ||
| @@ -510,22 +508,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l | |||
| 510 | path_get(&nd->root); | 508 | path_get(&nd->root); |
| 511 | } | 509 | } |
| 512 | 510 | ||
| 513 | res = link_path_walk(link, nd); | 511 | return link_path_walk(link, nd); |
| 514 | if (nd->depth || res || nd->last_type!=LAST_NORM) | ||
| 515 | return res; | ||
| 516 | /* | ||
| 517 | * If it is an iterative symlinks resolution in open_namei() we | ||
| 518 | * have to copy the last component. And all that crap because of | ||
| 519 | * bloody create() on broken symlinks. Furrfu... | ||
| 520 | */ | ||
| 521 | name = __getname(); | ||
| 522 | if (unlikely(!name)) { | ||
| 523 | path_put(&nd->path); | ||
| 524 | return -ENOMEM; | ||
| 525 | } | ||
| 526 | strcpy(name, nd->last.name); | ||
| 527 | nd->last.name = name; | ||
| 528 | return 0; | ||
| 529 | fail: | 512 | fail: |
| 530 | path_put(&nd->path); | 513 | path_put(&nd->path); |
| 531 | return PTR_ERR(link); | 514 | return PTR_ERR(link); |
| @@ -547,10 +530,10 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd) | |||
| 547 | nd->path.dentry = path->dentry; | 530 | nd->path.dentry = path->dentry; |
| 548 | } | 531 | } |
| 549 | 532 | ||
| 550 | static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) | 533 | static __always_inline int |
| 534 | __do_follow_link(struct path *path, struct nameidata *nd, void **p) | ||
| 551 | { | 535 | { |
| 552 | int error; | 536 | int error; |
| 553 | void *cookie; | ||
| 554 | struct dentry *dentry = path->dentry; | 537 | struct dentry *dentry = path->dentry; |
| 555 | 538 | ||
| 556 | touch_atime(path->mnt, dentry); | 539 | touch_atime(path->mnt, dentry); |
| @@ -562,9 +545,9 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
| 562 | } | 545 | } |
| 563 | mntget(path->mnt); | 546 | mntget(path->mnt); |
| 564 | nd->last_type = LAST_BIND; | 547 | nd->last_type = LAST_BIND; |
| 565 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); | 548 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); |
| 566 | error = PTR_ERR(cookie); | 549 | error = PTR_ERR(*p); |
| 567 | if (!IS_ERR(cookie)) { | 550 | if (!IS_ERR(*p)) { |
| 568 | char *s = nd_get_link(nd); | 551 | char *s = nd_get_link(nd); |
| 569 | error = 0; | 552 | error = 0; |
| 570 | if (s) | 553 | if (s) |
| @@ -574,8 +557,6 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
| 574 | if (error) | 557 | if (error) |
| 575 | path_put(&nd->path); | 558 | path_put(&nd->path); |
| 576 | } | 559 | } |
| 577 | if (dentry->d_inode->i_op->put_link) | ||
| 578 | dentry->d_inode->i_op->put_link(dentry, nd, cookie); | ||
| 579 | } | 560 | } |
| 580 | return error; | 561 | return error; |
| 581 | } | 562 | } |
| @@ -589,6 +570,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
| 589 | */ | 570 | */ |
| 590 | static inline int do_follow_link(struct path *path, struct nameidata *nd) | 571 | static inline int do_follow_link(struct path *path, struct nameidata *nd) |
| 591 | { | 572 | { |
| 573 | void *cookie; | ||
| 592 | int err = -ELOOP; | 574 | int err = -ELOOP; |
| 593 | if (current->link_count >= MAX_NESTED_LINKS) | 575 | if (current->link_count >= MAX_NESTED_LINKS) |
| 594 | goto loop; | 576 | goto loop; |
| @@ -602,7 +584,9 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) | |||
| 602 | current->link_count++; | 584 | current->link_count++; |
| 603 | current->total_link_count++; | 585 | current->total_link_count++; |
| 604 | nd->depth++; | 586 | nd->depth++; |
| 605 | err = __do_follow_link(path, nd); | 587 | err = __do_follow_link(path, nd, &cookie); |
| 588 | if (!IS_ERR(cookie) && path->dentry->d_inode->i_op->put_link) | ||
| 589 | path->dentry->d_inode->i_op->put_link(path->dentry, nd, cookie); | ||
| 606 | path_put(path); | 590 | path_put(path); |
| 607 | current->link_count--; | 591 | current->link_count--; |
| 608 | nd->depth--; | 592 | nd->depth--; |
| @@ -1847,6 +1831,9 @@ reval: | |||
| 1847 | nd.flags |= LOOKUP_EXCL; | 1831 | nd.flags |= LOOKUP_EXCL; |
| 1848 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1832 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
| 1849 | while (unlikely(!filp)) { /* trailing symlink */ | 1833 | while (unlikely(!filp)) { /* trailing symlink */ |
| 1834 | struct path holder; | ||
| 1835 | struct inode *inode; | ||
| 1836 | void *cookie; | ||
| 1850 | error = -ELOOP; | 1837 | error = -ELOOP; |
| 1851 | if ((open_flag & O_NOFOLLOW) || count++ == 32) | 1838 | if ((open_flag & O_NOFOLLOW) || count++ == 32) |
| 1852 | goto exit_dput; | 1839 | goto exit_dput; |
| @@ -1865,18 +1852,24 @@ reval: | |||
| 1865 | error = security_inode_follow_link(path.dentry, &nd); | 1852 | error = security_inode_follow_link(path.dentry, &nd); |
| 1866 | if (error) | 1853 | if (error) |
| 1867 | goto exit_dput; | 1854 | goto exit_dput; |
| 1868 | error = __do_follow_link(&path, &nd); | 1855 | error = __do_follow_link(&path, &nd, &cookie); |
| 1869 | path_put(&path); | 1856 | if (unlikely(error)) { |
| 1870 | if (error) { | ||
| 1871 | /* nd.path had been dropped */ | 1857 | /* nd.path had been dropped */ |
| 1858 | inode = path.dentry->d_inode; | ||
| 1859 | if (!IS_ERR(cookie) && inode->i_op->put_link) | ||
| 1860 | inode->i_op->put_link(path.dentry, &nd, cookie); | ||
| 1861 | path_put(&path); | ||
| 1872 | release_open_intent(&nd); | 1862 | release_open_intent(&nd); |
| 1873 | filp = ERR_PTR(error); | 1863 | filp = ERR_PTR(error); |
| 1874 | goto out; | 1864 | goto out; |
| 1875 | } | 1865 | } |
| 1866 | holder = path; | ||
| 1876 | nd.flags &= ~LOOKUP_PARENT; | 1867 | nd.flags &= ~LOOKUP_PARENT; |
| 1877 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1868 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
| 1878 | if (nd.last_type == LAST_NORM) | 1869 | inode = holder.dentry->d_inode; |
| 1879 | __putname(nd.last.name); | 1870 | if (inode->i_op->put_link) |
| 1871 | inode->i_op->put_link(holder.dentry, &nd, cookie); | ||
| 1872 | path_put(&holder); | ||
| 1880 | } | 1873 | } |
| 1881 | out: | 1874 | out: |
| 1882 | if (nd.root.mnt) | 1875 | if (nd.root.mnt) |
