[Ocfs2-commits] mfasheh commits r2722 - trunk/fs/ocfs2
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Wed Dec 7 20:02:07 CST 2005
Author: mfasheh
Signed-off-by: jlbec
Date: 2005-12-07 20:02:05 -0600 (Wed, 07 Dec 2005)
New Revision: 2722
Modified:
trunk/fs/ocfs2/file.c
Log:
* Clear suid / sgid early in the write path - otherwise we risk doing
recursive locking in ocfs2_setattr()
Signed-off-by: jlbec
Modified: trunk/fs/ocfs2/file.c
===================================================================
--- trunk/fs/ocfs2/file.c 2005-12-08 01:49:31 UTC (rev 2721)
+++ trunk/fs/ocfs2/file.c 2005-12-08 02:02:05 UTC (rev 2722)
@@ -867,6 +867,71 @@
return err;
}
+static int ocfs2_write_remove_suid(struct inode *inode)
+{
+ int ret;
+ struct buffer_head *bh = NULL;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_journal_handle *handle;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_dinode *di;
+
+ mlog_entry("(Inode %"MLFu64", mode 0%o)\n", oi->ip_blkno,
+ inode->i_mode);
+
+ handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_read_block(osb, oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_trans;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_bh;
+ }
+
+ inode->i_mode &= ~S_ISUID;
+ if ((inode->i_mode & S_ISGID) && (inode->i_mode & S_IXGRP))
+ inode->i_mode &= ~S_ISGID;
+
+ di = (struct ocfs2_dinode *) bh->b_data;
+ di->i_mode = cpu_to_le16(inode->i_mode);
+
+ ret = ocfs2_journal_dirty(handle, bh);
+ if (ret < 0)
+ mlog_errno(ret);
+out_bh:
+ brelse(bh);
+out_trans:
+ ocfs2_commit_trans(handle);
+out:
+ mlog_exit(ret);
+ return ret;
+}
+
+static inline int ocfs2_write_should_remove_suid(struct inode *inode)
+{
+ mode_t mode = inode->i_mode;
+
+ if (!capable(CAP_FSETID)) {
+ if (unlikely(mode & S_ISUID))
+ return 1;
+
+ if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
+ return 1;
+ }
+ return 0;
+}
+
static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
const char __user *buf,
size_t count,
@@ -905,7 +970,6 @@
filp->f_flags &= ~O_DIRECT;
#endif
-
down(&inode->i_sem);
/* to match setattr's i_sem -> i_alloc_sem -> rw_lock ordering */
if (filp->f_flags & O_DIRECT) {
@@ -936,6 +1000,29 @@
goto out;
}
+ /* Clear suid / sgid if necessary. We do this here
+ * instead of later in the write path because
+ * remove_suid() calls ->setattr without any hint that
+ * we may have already done our cluster locking. Since
+ * ocfs2_setattr() *must* take cluster locks to
+ * proceeed, this will lead us to recursively lock the
+ * inode. There's also the dinode i_size state which
+ * can be lost via setattr during extending writes (we
+ * set inode->i_size at the end of a write. */
+ if (ocfs2_write_should_remove_suid(inode)) {
+ if (meta_level == 0) {
+ ocfs2_meta_unlock(inode, meta_level);
+ meta_level = 1;
+ continue;
+ }
+
+ ret = ocfs2_write_remove_suid(inode);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
/* work on a copy of ppos until we're sure that we won't have
* to recalculate it due to relocking. */
if (filp->f_flags & O_APPEND) {
More information about the Ocfs2-commits
mailing list