Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a090d913 authored by Al Viro's avatar Al Viro Committed by Linus Torvalds
Browse files

[PATCH] protect ext3 ioctl modifying append_only, immutable, etc. with i_mutex



All modifications of ->i_flags in inodes that might be visible to
somebody else must be under ->i_mutex.  That patch fixes ext3 ioctl()
setting S_APPEND and friends.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6ad0013b
Loading
Loading
Loading
Loading
+14 −4
Original line number Original line Diff line number Diff line
@@ -48,6 +48,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
		if (!S_ISDIR(inode->i_mode))
		if (!S_ISDIR(inode->i_mode))
			flags &= ~EXT3_DIRSYNC_FL;
			flags &= ~EXT3_DIRSYNC_FL;


		mutex_lock(&inode->i_mutex);
		oldflags = ei->i_flags;
		oldflags = ei->i_flags;


		/* The JOURNAL_DATA flag is modifiable only by root */
		/* The JOURNAL_DATA flag is modifiable only by root */
@@ -60,23 +61,29 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
		 * This test looks nicer. Thanks to Pauline Middelink
		 * This test looks nicer. Thanks to Pauline Middelink
		 */
		 */
		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
			if (!capable(CAP_LINUX_IMMUTABLE))
			if (!capable(CAP_LINUX_IMMUTABLE)) {
				mutex_unlock(&inode->i_mutex);
				return -EPERM;
				return -EPERM;
			}
			}
		}


		/*
		/*
		 * The JOURNAL_DATA flag can only be changed by
		 * The JOURNAL_DATA flag can only be changed by
		 * the relevant capability.
		 * the relevant capability.
		 */
		 */
		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
			if (!capable(CAP_SYS_RESOURCE))
			if (!capable(CAP_SYS_RESOURCE)) {
				mutex_unlock(&inode->i_mutex);
				return -EPERM;
				return -EPERM;
			}
			}
		}




		handle = ext3_journal_start(inode, 1);
		handle = ext3_journal_start(inode, 1);
		if (IS_ERR(handle))
		if (IS_ERR(handle)) {
			mutex_unlock(&inode->i_mutex);
			return PTR_ERR(handle);
			return PTR_ERR(handle);
		}
		if (IS_SYNC(inode))
		if (IS_SYNC(inode))
			handle->h_sync = 1;
			handle->h_sync = 1;
		err = ext3_reserve_inode_write(handle, inode, &iloc);
		err = ext3_reserve_inode_write(handle, inode, &iloc);
@@ -93,11 +100,14 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
flags_err:
flags_err:
		ext3_journal_stop(handle);
		ext3_journal_stop(handle);
		if (err)
		if (err) {
			mutex_unlock(&inode->i_mutex);
			return err;
			return err;
		}


		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
			err = ext3_change_inode_journal_flag(inode, jflag);
			err = ext3_change_inode_journal_flag(inode, jflag);
		mutex_unlock(&inode->i_mutex);
		return err;
		return err;
	}
	}
	case EXT3_IOC_GETVERSION:
	case EXT3_IOC_GETVERSION: