diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/fs/namei.c b/fs/namei.c index b55440baf7ab..a4855af776a8 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -561,6 +561,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
561 | dget(dentry); | 561 | dget(dentry); |
562 | } | 562 | } |
563 | mntget(path->mnt); | 563 | mntget(path->mnt); |
564 | nd->last_type = LAST_BIND; | ||
564 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); | 565 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); |
565 | error = PTR_ERR(cookie); | 566 | error = PTR_ERR(cookie); |
566 | if (!IS_ERR(cookie)) { | 567 | if (!IS_ERR(cookie)) { |
@@ -822,6 +823,17 @@ fail: | |||
822 | } | 823 | } |
823 | 824 | ||
824 | /* | 825 | /* |
826 | * This is a temporary kludge to deal with "automount" symlinks; proper | ||
827 | * solution is to trigger them on follow_mount(), so that do_lookup() | ||
828 | * would DTRT. To be killed before 2.6.34-final. | ||
829 | */ | ||
830 | static inline int follow_on_final(struct inode *inode, unsigned lookup_flags) | ||
831 | { | ||
832 | return inode && unlikely(inode->i_op->follow_link) && | ||
833 | ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode)); | ||
834 | } | ||
835 | |||
836 | /* | ||
825 | * Name resolution. | 837 | * Name resolution. |
826 | * This is the basic name resolution function, turning a pathname into | 838 | * This is the basic name resolution function, turning a pathname into |
827 | * the final dentry. We expect 'base' to be positive and a directory. | 839 | * the final dentry. We expect 'base' to be positive and a directory. |
@@ -941,8 +953,7 @@ last_component: | |||
941 | if (err) | 953 | if (err) |
942 | break; | 954 | break; |
943 | inode = next.dentry->d_inode; | 955 | inode = next.dentry->d_inode; |
944 | if ((lookup_flags & LOOKUP_FOLLOW) | 956 | if (follow_on_final(inode, lookup_flags)) { |
945 | && inode && inode->i_op->follow_link) { | ||
946 | err = do_follow_link(&next, nd); | 957 | err = do_follow_link(&next, nd); |
947 | if (err) | 958 | if (err) |
948 | goto return_err; | 959 | goto return_err; |
@@ -1603,11 +1614,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1603 | struct file *filp; | 1614 | struct file *filp; |
1604 | struct nameidata nd; | 1615 | struct nameidata nd; |
1605 | int error; | 1616 | int error; |
1606 | struct path path, save; | 1617 | struct path path; |
1607 | struct dentry *dir; | 1618 | struct dentry *dir; |
1608 | int count = 0; | 1619 | int count = 0; |
1609 | int will_truncate; | 1620 | int will_truncate; |
1610 | int flag = open_to_namei_flags(open_flag); | 1621 | int flag = open_to_namei_flags(open_flag); |
1622 | int force_reval = 0; | ||
1611 | 1623 | ||
1612 | /* | 1624 | /* |
1613 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 1625 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
@@ -1619,7 +1631,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1619 | open_flag |= O_DSYNC; | 1631 | open_flag |= O_DSYNC; |
1620 | 1632 | ||
1621 | if (!acc_mode) | 1633 | if (!acc_mode) |
1622 | acc_mode = MAY_OPEN | ACC_MODE(flag); | 1634 | acc_mode = MAY_OPEN | ACC_MODE(open_flag); |
1623 | 1635 | ||
1624 | /* O_TRUNC implies we need access checks for write permissions */ | 1636 | /* O_TRUNC implies we need access checks for write permissions */ |
1625 | if (flag & O_TRUNC) | 1637 | if (flag & O_TRUNC) |
@@ -1659,9 +1671,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1659 | /* | 1671 | /* |
1660 | * Create - we need to know the parent. | 1672 | * Create - we need to know the parent. |
1661 | */ | 1673 | */ |
1674 | reval: | ||
1662 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); | 1675 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); |
1663 | if (error) | 1676 | if (error) |
1664 | return ERR_PTR(error); | 1677 | return ERR_PTR(error); |
1678 | if (force_reval) | ||
1679 | nd.flags |= LOOKUP_REVAL; | ||
1665 | error = path_walk(pathname, &nd); | 1680 | error = path_walk(pathname, &nd); |
1666 | if (error) { | 1681 | if (error) { |
1667 | if (nd.root.mnt) | 1682 | if (nd.root.mnt) |
@@ -1731,8 +1746,7 @@ do_last: | |||
1731 | if (nd.root.mnt) | 1746 | if (nd.root.mnt) |
1732 | path_put(&nd.root); | 1747 | path_put(&nd.root); |
1733 | if (!IS_ERR(filp)) { | 1748 | if (!IS_ERR(filp)) { |
1734 | error = ima_path_check(&filp->f_path, filp->f_mode & | 1749 | error = ima_file_check(filp, acc_mode); |
1735 | (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
1736 | if (error) { | 1750 | if (error) { |
1737 | fput(filp); | 1751 | fput(filp); |
1738 | filp = ERR_PTR(error); | 1752 | filp = ERR_PTR(error); |
@@ -1792,8 +1806,7 @@ ok: | |||
1792 | } | 1806 | } |
1793 | filp = nameidata_to_filp(&nd); | 1807 | filp = nameidata_to_filp(&nd); |
1794 | if (!IS_ERR(filp)) { | 1808 | if (!IS_ERR(filp)) { |
1795 | error = ima_path_check(&filp->f_path, filp->f_mode & | 1809 | error = ima_file_check(filp, acc_mode); |
1796 | (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
1797 | if (error) { | 1810 | if (error) { |
1798 | fput(filp); | 1811 | fput(filp); |
1799 | filp = ERR_PTR(error); | 1812 | filp = ERR_PTR(error); |
@@ -1853,17 +1866,7 @@ do_link: | |||
1853 | error = security_inode_follow_link(path.dentry, &nd); | 1866 | error = security_inode_follow_link(path.dentry, &nd); |
1854 | if (error) | 1867 | if (error) |
1855 | goto exit_dput; | 1868 | goto exit_dput; |
1856 | save = nd.path; | ||
1857 | path_get(&save); | ||
1858 | error = __do_follow_link(&path, &nd); | 1869 | error = __do_follow_link(&path, &nd); |
1859 | if (error == -ESTALE) { | ||
1860 | /* nd.path had been dropped */ | ||
1861 | nd.path = save; | ||
1862 | path_get(&nd.path); | ||
1863 | nd.flags |= LOOKUP_REVAL; | ||
1864 | error = __do_follow_link(&path, &nd); | ||
1865 | } | ||
1866 | path_put(&save); | ||
1867 | path_put(&path); | 1870 | path_put(&path); |
1868 | if (error) { | 1871 | if (error) { |
1869 | /* Does someone understand code flow here? Or it is only | 1872 | /* Does someone understand code flow here? Or it is only |
@@ -1873,6 +1876,10 @@ do_link: | |||
1873 | release_open_intent(&nd); | 1876 | release_open_intent(&nd); |
1874 | if (nd.root.mnt) | 1877 | if (nd.root.mnt) |
1875 | path_put(&nd.root); | 1878 | path_put(&nd.root); |
1879 | if (error == -ESTALE && !force_reval) { | ||
1880 | force_reval = 1; | ||
1881 | goto reval; | ||
1882 | } | ||
1876 | return ERR_PTR(error); | 1883 | return ERR_PTR(error); |
1877 | } | 1884 | } |
1878 | nd.flags &= ~LOOKUP_PARENT; | 1885 | nd.flags &= ~LOOKUP_PARENT; |