diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-01-17 14:01:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-01-17 14:01:16 -0500 |
commit | 7dc9c484a71525794ca05cf7a47f283f1b54cd12 (patch) | |
tree | e150ea705069b06af5c6e0d077a94437f24e991a /fs | |
parent | 3a5dd791abef032fe57fc652c0232913c696e59b (diff) | |
parent | 27d55f1f4c190b14092fcca3069c7d15df83514f (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
do_add_mount() should sanitize mnt_flags
CIFS shouldn't make mountpoints shrinkable
mnt_flags fixes in do_remount()
attach_recursive_mnt() needs to hold vfsmount_lock over set_mnt_shared()
may_umount() needs namespace_sem
Fix configfs leak
Fix the -ESTALE handling in do_filp_open()
ecryptfs: Fix refcnt leak on ecryptfs_follow_link() error path
Fix ACC_MODE() for real
Unrot uml mconsole a bit
hppfs: handle ->put_link()
Kill 9p readlink()
fix autofs/afs/etc. magic mountpoint breakage
Diffstat (limited to 'fs')
-rw-r--r-- | fs/9p/vfs_inode.c | 41 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 3 | ||||
-rw-r--r-- | fs/configfs/symlink.c | 4 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 24 | ||||
-rw-r--r-- | fs/hppfs/hppfs.c | 18 | ||||
-rw-r--r-- | fs/namei.c | 23 | ||||
-rw-r--r-- | fs/namespace.c | 14 | ||||
-rw-r--r-- | fs/proc/base.c | 1 |
8 files changed, 51 insertions, 77 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 18f74ec4dce9..9d03d1ebca6f 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -1001,44 +1001,6 @@ done: | |||
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | /** | 1003 | /** |
1004 | * v9fs_vfs_readlink - read a symlink's location | ||
1005 | * @dentry: dentry for symlink | ||
1006 | * @buffer: buffer to load symlink location into | ||
1007 | * @buflen: length of buffer | ||
1008 | * | ||
1009 | */ | ||
1010 | |||
1011 | static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, | ||
1012 | int buflen) | ||
1013 | { | ||
1014 | int retval; | ||
1015 | int ret; | ||
1016 | char *link = __getname(); | ||
1017 | |||
1018 | if (unlikely(!link)) | ||
1019 | return -ENOMEM; | ||
1020 | |||
1021 | if (buflen > PATH_MAX) | ||
1022 | buflen = PATH_MAX; | ||
1023 | |||
1024 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, | ||
1025 | dentry); | ||
1026 | |||
1027 | retval = v9fs_readlink(dentry, link, buflen); | ||
1028 | |||
1029 | if (retval > 0) { | ||
1030 | if ((ret = copy_to_user(buffer, link, retval)) != 0) { | ||
1031 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
1032 | "problem copying to user: %d\n", ret); | ||
1033 | retval = ret; | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | __putname(link); | ||
1038 | return retval; | ||
1039 | } | ||
1040 | |||
1041 | /** | ||
1042 | * v9fs_vfs_follow_link - follow a symlink path | 1004 | * v9fs_vfs_follow_link - follow a symlink path |
1043 | * @dentry: dentry for symlink | 1005 | * @dentry: dentry for symlink |
1044 | * @nd: nameidata | 1006 | * @nd: nameidata |
@@ -1230,7 +1192,6 @@ static const struct inode_operations v9fs_dir_inode_operations_ext = { | |||
1230 | .rmdir = v9fs_vfs_rmdir, | 1192 | .rmdir = v9fs_vfs_rmdir, |
1231 | .mknod = v9fs_vfs_mknod, | 1193 | .mknod = v9fs_vfs_mknod, |
1232 | .rename = v9fs_vfs_rename, | 1194 | .rename = v9fs_vfs_rename, |
1233 | .readlink = v9fs_vfs_readlink, | ||
1234 | .getattr = v9fs_vfs_getattr, | 1195 | .getattr = v9fs_vfs_getattr, |
1235 | .setattr = v9fs_vfs_setattr, | 1196 | .setattr = v9fs_vfs_setattr, |
1236 | }; | 1197 | }; |
@@ -1253,7 +1214,7 @@ static const struct inode_operations v9fs_file_inode_operations = { | |||
1253 | }; | 1214 | }; |
1254 | 1215 | ||
1255 | static const struct inode_operations v9fs_symlink_inode_operations = { | 1216 | static const struct inode_operations v9fs_symlink_inode_operations = { |
1256 | .readlink = v9fs_vfs_readlink, | 1217 | .readlink = generic_readlink, |
1257 | .follow_link = v9fs_vfs_follow_link, | 1218 | .follow_link = v9fs_vfs_follow_link, |
1258 | .put_link = v9fs_vfs_put_link, | 1219 | .put_link = v9fs_vfs_put_link, |
1259 | .getattr = v9fs_vfs_getattr, | 1220 | .getattr = v9fs_vfs_getattr, |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index fea9e898c4ba..b44ce0a0711c 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -269,7 +269,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
269 | int err; | 269 | int err; |
270 | 270 | ||
271 | mntget(newmnt); | 271 | mntget(newmnt); |
272 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags, mntlist); | 272 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist); |
273 | switch (err) { | 273 | switch (err) { |
274 | case 0: | 274 | case 0: |
275 | path_put(&nd->path); | 275 | path_put(&nd->path); |
@@ -371,7 +371,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
371 | if (IS_ERR(mnt)) | 371 | if (IS_ERR(mnt)) |
372 | goto out_err; | 372 | goto out_err; |
373 | 373 | ||
374 | nd->path.mnt->mnt_flags |= MNT_SHRINKABLE; | ||
375 | rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); | 374 | rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); |
376 | 375 | ||
377 | out: | 376 | out: |
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index c8afa6b1d91d..32a5f46b1157 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c | |||
@@ -121,8 +121,10 @@ static int get_target(const char *symname, struct path *path, | |||
121 | ret = -ENOENT; | 121 | ret = -ENOENT; |
122 | path_put(path); | 122 | path_put(path); |
123 | } | 123 | } |
124 | } else | 124 | } else { |
125 | ret = -EPERM; | 125 | ret = -EPERM; |
126 | path_put(path); | ||
127 | } | ||
126 | } | 128 | } |
127 | 129 | ||
128 | return ret; | 130 | return ret; |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 429ca0b3ba08..7f8545032930 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -715,31 +715,31 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
715 | /* Released in ecryptfs_put_link(); only release here on error */ | 715 | /* Released in ecryptfs_put_link(); only release here on error */ |
716 | buf = kmalloc(len, GFP_KERNEL); | 716 | buf = kmalloc(len, GFP_KERNEL); |
717 | if (!buf) { | 717 | if (!buf) { |
718 | rc = -ENOMEM; | 718 | buf = ERR_PTR(-ENOMEM); |
719 | goto out; | 719 | goto out; |
720 | } | 720 | } |
721 | old_fs = get_fs(); | 721 | old_fs = get_fs(); |
722 | set_fs(get_ds()); | 722 | set_fs(get_ds()); |
723 | rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); | 723 | rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); |
724 | set_fs(old_fs); | 724 | set_fs(old_fs); |
725 | if (rc < 0) | 725 | if (rc < 0) { |
726 | goto out_free; | 726 | kfree(buf); |
727 | else | 727 | buf = ERR_PTR(rc); |
728 | } else | ||
728 | buf[rc] = '\0'; | 729 | buf[rc] = '\0'; |
729 | rc = 0; | ||
730 | nd_set_link(nd, buf); | ||
731 | goto out; | ||
732 | out_free: | ||
733 | kfree(buf); | ||
734 | out: | 730 | out: |
735 | return ERR_PTR(rc); | 731 | nd_set_link(nd, buf); |
732 | return NULL; | ||
736 | } | 733 | } |
737 | 734 | ||
738 | static void | 735 | static void |
739 | ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) | 736 | ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) |
740 | { | 737 | { |
741 | /* Free the char* */ | 738 | char *buf = nd_get_link(nd); |
742 | kfree(nd_get_link(nd)); | 739 | if (!IS_ERR(buf)) { |
740 | /* Free the char* */ | ||
741 | kfree(buf); | ||
742 | } | ||
743 | } | 743 | } |
744 | 744 | ||
745 | /** | 745 | /** |
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index a5089a6dd67a..7239efc690d8 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c | |||
@@ -646,22 +646,27 @@ static const struct super_operations hppfs_sbops = { | |||
646 | static int hppfs_readlink(struct dentry *dentry, char __user *buffer, | 646 | static int hppfs_readlink(struct dentry *dentry, char __user *buffer, |
647 | int buflen) | 647 | int buflen) |
648 | { | 648 | { |
649 | struct dentry *proc_dentry; | 649 | struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; |
650 | |||
651 | proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; | ||
652 | return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, | 650 | return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, |
653 | buflen); | 651 | buflen); |
654 | } | 652 | } |
655 | 653 | ||
656 | static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 654 | static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
657 | { | 655 | { |
658 | struct dentry *proc_dentry; | 656 | struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; |
659 | |||
660 | proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; | ||
661 | 657 | ||
662 | return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); | 658 | return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); |
663 | } | 659 | } |
664 | 660 | ||
661 | static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd, | ||
662 | void *cookie) | ||
663 | { | ||
664 | struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; | ||
665 | |||
666 | if (proc_dentry->d_inode->i_op->put_link) | ||
667 | proc_dentry->d_inode->i_op->put_link(proc_dentry, nd, cookie); | ||
668 | } | ||
669 | |||
665 | static const struct inode_operations hppfs_dir_iops = { | 670 | static const struct inode_operations hppfs_dir_iops = { |
666 | .lookup = hppfs_lookup, | 671 | .lookup = hppfs_lookup, |
667 | }; | 672 | }; |
@@ -669,6 +674,7 @@ static const struct inode_operations hppfs_dir_iops = { | |||
669 | static const struct inode_operations hppfs_link_iops = { | 674 | static const struct inode_operations hppfs_link_iops = { |
670 | .readlink = hppfs_readlink, | 675 | .readlink = hppfs_readlink, |
671 | .follow_link = hppfs_follow_link, | 676 | .follow_link = hppfs_follow_link, |
677 | .put_link = hppfs_put_link, | ||
672 | }; | 678 | }; |
673 | 679 | ||
674 | static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) | 680 | static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) |
diff --git a/fs/namei.c b/fs/namei.c index b55440baf7ab..94a5e60779f9 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)) { |
@@ -1603,11 +1604,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1603 | struct file *filp; | 1604 | struct file *filp; |
1604 | struct nameidata nd; | 1605 | struct nameidata nd; |
1605 | int error; | 1606 | int error; |
1606 | struct path path, save; | 1607 | struct path path; |
1607 | struct dentry *dir; | 1608 | struct dentry *dir; |
1608 | int count = 0; | 1609 | int count = 0; |
1609 | int will_truncate; | 1610 | int will_truncate; |
1610 | int flag = open_to_namei_flags(open_flag); | 1611 | int flag = open_to_namei_flags(open_flag); |
1612 | int force_reval = 0; | ||
1611 | 1613 | ||
1612 | /* | 1614 | /* |
1613 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 1615 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
@@ -1619,7 +1621,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1619 | open_flag |= O_DSYNC; | 1621 | open_flag |= O_DSYNC; |
1620 | 1622 | ||
1621 | if (!acc_mode) | 1623 | if (!acc_mode) |
1622 | acc_mode = MAY_OPEN | ACC_MODE(flag); | 1624 | acc_mode = MAY_OPEN | ACC_MODE(open_flag); |
1623 | 1625 | ||
1624 | /* O_TRUNC implies we need access checks for write permissions */ | 1626 | /* O_TRUNC implies we need access checks for write permissions */ |
1625 | if (flag & O_TRUNC) | 1627 | if (flag & O_TRUNC) |
@@ -1659,9 +1661,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1659 | /* | 1661 | /* |
1660 | * Create - we need to know the parent. | 1662 | * Create - we need to know the parent. |
1661 | */ | 1663 | */ |
1664 | reval: | ||
1662 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); | 1665 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); |
1663 | if (error) | 1666 | if (error) |
1664 | return ERR_PTR(error); | 1667 | return ERR_PTR(error); |
1668 | if (force_reval) | ||
1669 | nd.flags |= LOOKUP_REVAL; | ||
1665 | error = path_walk(pathname, &nd); | 1670 | error = path_walk(pathname, &nd); |
1666 | if (error) { | 1671 | if (error) { |
1667 | if (nd.root.mnt) | 1672 | if (nd.root.mnt) |
@@ -1853,17 +1858,7 @@ do_link: | |||
1853 | error = security_inode_follow_link(path.dentry, &nd); | 1858 | error = security_inode_follow_link(path.dentry, &nd); |
1854 | if (error) | 1859 | if (error) |
1855 | goto exit_dput; | 1860 | goto exit_dput; |
1856 | save = nd.path; | ||
1857 | path_get(&save); | ||
1858 | error = __do_follow_link(&path, &nd); | 1861 | 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); | 1862 | path_put(&path); |
1868 | if (error) { | 1863 | if (error) { |
1869 | /* Does someone understand code flow here? Or it is only | 1864 | /* Does someone understand code flow here? Or it is only |
@@ -1873,6 +1868,10 @@ do_link: | |||
1873 | release_open_intent(&nd); | 1868 | release_open_intent(&nd); |
1874 | if (nd.root.mnt) | 1869 | if (nd.root.mnt) |
1875 | path_put(&nd.root); | 1870 | path_put(&nd.root); |
1871 | if (error == -ESTALE && !force_reval) { | ||
1872 | force_reval = 1; | ||
1873 | goto reval; | ||
1874 | } | ||
1876 | return ERR_PTR(error); | 1875 | return ERR_PTR(error); |
1877 | } | 1876 | } |
1878 | nd.flags &= ~LOOKUP_PARENT; | 1877 | nd.flags &= ~LOOKUP_PARENT; |
diff --git a/fs/namespace.c b/fs/namespace.c index 7d70d63ceb29..c768f733c8d6 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -965,10 +965,12 @@ EXPORT_SYMBOL(may_umount_tree); | |||
965 | int may_umount(struct vfsmount *mnt) | 965 | int may_umount(struct vfsmount *mnt) |
966 | { | 966 | { |
967 | int ret = 1; | 967 | int ret = 1; |
968 | down_read(&namespace_sem); | ||
968 | spin_lock(&vfsmount_lock); | 969 | spin_lock(&vfsmount_lock); |
969 | if (propagate_mount_busy(mnt, 2)) | 970 | if (propagate_mount_busy(mnt, 2)) |
970 | ret = 0; | 971 | ret = 0; |
971 | spin_unlock(&vfsmount_lock); | 972 | spin_unlock(&vfsmount_lock); |
973 | up_read(&namespace_sem); | ||
972 | return ret; | 974 | return ret; |
973 | } | 975 | } |
974 | 976 | ||
@@ -1352,12 +1354,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
1352 | if (err) | 1354 | if (err) |
1353 | goto out_cleanup_ids; | 1355 | goto out_cleanup_ids; |
1354 | 1356 | ||
1357 | spin_lock(&vfsmount_lock); | ||
1358 | |||
1355 | if (IS_MNT_SHARED(dest_mnt)) { | 1359 | if (IS_MNT_SHARED(dest_mnt)) { |
1356 | for (p = source_mnt; p; p = next_mnt(p, source_mnt)) | 1360 | for (p = source_mnt; p; p = next_mnt(p, source_mnt)) |
1357 | set_mnt_shared(p); | 1361 | set_mnt_shared(p); |
1358 | } | 1362 | } |
1359 | |||
1360 | spin_lock(&vfsmount_lock); | ||
1361 | if (parent_path) { | 1363 | if (parent_path) { |
1362 | detach_mnt(source_mnt, parent_path); | 1364 | detach_mnt(source_mnt, parent_path); |
1363 | attach_mnt(source_mnt, path); | 1365 | attach_mnt(source_mnt, path); |
@@ -1534,8 +1536,12 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
1534 | err = change_mount_flags(path->mnt, flags); | 1536 | err = change_mount_flags(path->mnt, flags); |
1535 | else | 1537 | else |
1536 | err = do_remount_sb(sb, flags, data, 0); | 1538 | err = do_remount_sb(sb, flags, data, 0); |
1537 | if (!err) | 1539 | if (!err) { |
1540 | spin_lock(&vfsmount_lock); | ||
1541 | mnt_flags |= path->mnt->mnt_flags & MNT_PNODE_MASK; | ||
1538 | path->mnt->mnt_flags = mnt_flags; | 1542 | path->mnt->mnt_flags = mnt_flags; |
1543 | spin_unlock(&vfsmount_lock); | ||
1544 | } | ||
1539 | up_write(&sb->s_umount); | 1545 | up_write(&sb->s_umount); |
1540 | if (!err) { | 1546 | if (!err) { |
1541 | security_sb_post_remount(path->mnt, flags, data); | 1547 | security_sb_post_remount(path->mnt, flags, data); |
@@ -1665,6 +1671,8 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, | |||
1665 | { | 1671 | { |
1666 | int err; | 1672 | int err; |
1667 | 1673 | ||
1674 | mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD); | ||
1675 | |||
1668 | down_write(&namespace_sem); | 1676 | down_write(&namespace_sem); |
1669 | /* Something was mounted here while we slept */ | 1677 | /* Something was mounted here while we slept */ |
1670 | while (d_mountpoint(path->dentry) && | 1678 | while (d_mountpoint(path->dentry) && |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 18d5cc62d8ed..e42bbd843ed1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1419,7 +1419,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
1419 | goto out; | 1419 | goto out; |
1420 | 1420 | ||
1421 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); | 1421 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); |
1422 | nd->last_type = LAST_BIND; | ||
1423 | out: | 1422 | out: |
1424 | return ERR_PTR(error); | 1423 | return ERR_PTR(error); |
1425 | } | 1424 | } |