diff options
| author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:46 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:29:24 -0400 |
| commit | 42a74f206b914db13ee1f5ae932dcd91a77c8579 (patch) | |
| tree | 24e3dbe55edaacc750067ab9e01778255a6bff08 /fs/ext2 | |
| parent | 20ddee2c75339cc095f6191c3115f81da8955e96 (diff) | |
[PATCH] r/o bind mounts: elevate write count for ioctls()
Some ioctl()s can cause writes to the filesystem. Take these, and make them
use mnt_want/drop_write() instead.
[AV: updated]
Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ext2')
| -rw-r--r-- | fs/ext2/ioctl.c | 57 |
1 files changed, 37 insertions, 20 deletions
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index b8ea11fee5c6..de876fa793e1 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| 13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 14 | #include <linux/compat.h> | 14 | #include <linux/compat.h> |
| 15 | #include <linux/mount.h> | ||
| 15 | #include <linux/smp_lock.h> | 16 | #include <linux/smp_lock.h> |
| 16 | #include <asm/current.h> | 17 | #include <asm/current.h> |
| 17 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
| @@ -23,6 +24,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 23 | struct ext2_inode_info *ei = EXT2_I(inode); | 24 | struct ext2_inode_info *ei = EXT2_I(inode); |
| 24 | unsigned int flags; | 25 | unsigned int flags; |
| 25 | unsigned short rsv_window_size; | 26 | unsigned short rsv_window_size; |
| 27 | int ret; | ||
| 26 | 28 | ||
| 27 | ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); | 29 | ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); |
| 28 | 30 | ||
| @@ -34,14 +36,19 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 34 | case EXT2_IOC_SETFLAGS: { | 36 | case EXT2_IOC_SETFLAGS: { |
| 35 | unsigned int oldflags; | 37 | unsigned int oldflags; |
| 36 | 38 | ||
| 37 | if (IS_RDONLY(inode)) | 39 | ret = mnt_want_write(filp->f_path.mnt); |
| 38 | return -EROFS; | 40 | if (ret) |
| 41 | return ret; | ||
| 39 | 42 | ||
| 40 | if (!is_owner_or_cap(inode)) | 43 | if (!is_owner_or_cap(inode)) { |
| 41 | return -EACCES; | 44 | ret = -EACCES; |
| 45 | goto setflags_out; | ||
| 46 | } | ||
| 42 | 47 | ||
| 43 | if (get_user(flags, (int __user *) arg)) | 48 | if (get_user(flags, (int __user *) arg)) { |
| 44 | return -EFAULT; | 49 | ret = -EFAULT; |
| 50 | goto setflags_out; | ||
| 51 | } | ||
| 45 | 52 | ||
| 46 | if (!S_ISDIR(inode->i_mode)) | 53 | if (!S_ISDIR(inode->i_mode)) |
| 47 | flags &= ~EXT2_DIRSYNC_FL; | 54 | flags &= ~EXT2_DIRSYNC_FL; |
| @@ -50,7 +57,8 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 50 | /* Is it quota file? Do not allow user to mess with it */ | 57 | /* Is it quota file? Do not allow user to mess with it */ |
| 51 | if (IS_NOQUOTA(inode)) { | 58 | if (IS_NOQUOTA(inode)) { |
| 52 | mutex_unlock(&inode->i_mutex); | 59 | mutex_unlock(&inode->i_mutex); |
| 53 | return -EPERM; | 60 | ret = -EPERM; |
| 61 | goto setflags_out; | ||
| 54 | } | 62 | } |
| 55 | oldflags = ei->i_flags; | 63 | oldflags = ei->i_flags; |
| 56 | 64 | ||
| @@ -63,7 +71,8 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 63 | if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { | 71 | if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { |
| 64 | if (!capable(CAP_LINUX_IMMUTABLE)) { | 72 | if (!capable(CAP_LINUX_IMMUTABLE)) { |
| 65 | mutex_unlock(&inode->i_mutex); | 73 | mutex_unlock(&inode->i_mutex); |
| 66 | return -EPERM; | 74 | ret = -EPERM; |
| 75 | goto setflags_out; | ||
| 67 | } | 76 | } |
| 68 | } | 77 | } |
| 69 | 78 | ||
| @@ -75,20 +84,26 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 75 | ext2_set_inode_flags(inode); | 84 | ext2_set_inode_flags(inode); |
| 76 | inode->i_ctime = CURRENT_TIME_SEC; | 85 | inode->i_ctime = CURRENT_TIME_SEC; |
| 77 | mark_inode_dirty(inode); | 86 | mark_inode_dirty(inode); |
| 78 | return 0; | 87 | setflags_out: |
| 88 | mnt_drop_write(filp->f_path.mnt); | ||
| 89 | return ret; | ||
| 79 | } | 90 | } |
| 80 | case EXT2_IOC_GETVERSION: | 91 | case EXT2_IOC_GETVERSION: |
| 81 | return put_user(inode->i_generation, (int __user *) arg); | 92 | return put_user(inode->i_generation, (int __user *) arg); |
| 82 | case EXT2_IOC_SETVERSION: | 93 | case EXT2_IOC_SETVERSION: |
| 83 | if (!is_owner_or_cap(inode)) | 94 | if (!is_owner_or_cap(inode)) |
| 84 | return -EPERM; | 95 | return -EPERM; |
| 85 | if (IS_RDONLY(inode)) | 96 | ret = mnt_want_write(filp->f_path.mnt); |
| 86 | return -EROFS; | 97 | if (ret) |
| 87 | if (get_user(inode->i_generation, (int __user *) arg)) | 98 | return ret; |
| 88 | return -EFAULT; | 99 | if (get_user(inode->i_generation, (int __user *) arg)) { |
| 89 | inode->i_ctime = CURRENT_TIME_SEC; | 100 | ret = -EFAULT; |
| 90 | mark_inode_dirty(inode); | 101 | } else { |
| 91 | return 0; | 102 | inode->i_ctime = CURRENT_TIME_SEC; |
| 103 | mark_inode_dirty(inode); | ||
| 104 | } | ||
| 105 | mnt_drop_write(filp->f_path.mnt); | ||
| 106 | return ret; | ||
| 92 | case EXT2_IOC_GETRSVSZ: | 107 | case EXT2_IOC_GETRSVSZ: |
| 93 | if (test_opt(inode->i_sb, RESERVATION) | 108 | if (test_opt(inode->i_sb, RESERVATION) |
| 94 | && S_ISREG(inode->i_mode) | 109 | && S_ISREG(inode->i_mode) |
| @@ -102,15 +117,16 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 102 | if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) | 117 | if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) |
| 103 | return -ENOTTY; | 118 | return -ENOTTY; |
| 104 | 119 | ||
| 105 | if (IS_RDONLY(inode)) | 120 | if (!is_owner_or_cap(inode)) |
| 106 | return -EROFS; | ||
| 107 | |||
| 108 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | ||
| 109 | return -EACCES; | 121 | return -EACCES; |
| 110 | 122 | ||
| 111 | if (get_user(rsv_window_size, (int __user *)arg)) | 123 | if (get_user(rsv_window_size, (int __user *)arg)) |
| 112 | return -EFAULT; | 124 | return -EFAULT; |
| 113 | 125 | ||
| 126 | ret = mnt_want_write(filp->f_path.mnt); | ||
| 127 | if (ret) | ||
| 128 | return ret; | ||
| 129 | |||
| 114 | if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) | 130 | if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) |
| 115 | rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; | 131 | rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; |
| 116 | 132 | ||
| @@ -131,6 +147,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 131 | rsv->rsv_goal_size = rsv_window_size; | 147 | rsv->rsv_goal_size = rsv_window_size; |
| 132 | } | 148 | } |
| 133 | mutex_unlock(&ei->truncate_mutex); | 149 | mutex_unlock(&ei->truncate_mutex); |
| 150 | mnt_drop_write(filp->f_path.mnt); | ||
| 134 | return 0; | 151 | return 0; |
| 135 | } | 152 | } |
| 136 | default: | 153 | default: |
