summaryrefslogtreecommitdiff
path: root/sys-kernel/hardened-sources/ocfs2-hardlink.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/hardened-sources/ocfs2-hardlink.patch')
-rw-r--r--sys-kernel/hardened-sources/ocfs2-hardlink.patch125
1 files changed, 125 insertions, 0 deletions
diff --git a/sys-kernel/hardened-sources/ocfs2-hardlink.patch b/sys-kernel/hardened-sources/ocfs2-hardlink.patch
new file mode 100644
index 0000000..fe8f841
--- /dev/null
+++ b/sys-kernel/hardened-sources/ocfs2-hardlink.patch
@@ -0,0 +1,125 @@
+diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
+index 8add6f1030d7..a997d7f40608 100644
+--- a/fs/ocfs2/namei.c
++++ b/fs/ocfs2/namei.c
+@@ -94,6 +94,14 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
+ struct inode *inode,
+ const char *symname);
+
++static int ocfs2_double_lock(struct ocfs2_super *osb,
++ struct buffer_head **bh1,
++ struct inode *inode1,
++ struct buffer_head **bh2,
++ struct inode *inode2,
++ int rename);
++
++static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2);
+ /* An orphan dir name is an 8 byte value, printed as a hex string */
+ #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
+
+@@ -678,8 +686,10 @@ static int ocfs2_link(struct dentry *old_dentry,
+ {
+ handle_t *handle;
+ struct inode *inode = old_dentry->d_inode;
++ struct inode *old_dir = old_dentry->d_parent->d_inode;
+ int err;
+ struct buffer_head *fe_bh = NULL;
++ struct buffer_head *old_dir_bh = NULL;
+ struct buffer_head *parent_fe_bh = NULL;
+ struct ocfs2_dinode *fe = NULL;
+ struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+@@ -696,19 +706,33 @@ static int ocfs2_link(struct dentry *old_dentry,
+
+ dquot_initialize(dir);
+
+- err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT);
++ err = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
++ &parent_fe_bh, dir, 0);
+ if (err < 0) {
+ if (err != -ENOENT)
+ mlog_errno(err);
+ return err;
+ }
+
++ /* make sure both dirs have bhs
++ * get an extra ref on old_dir_bh if old==new */
++ if (!parent_fe_bh) {
++ if (old_dir_bh) {
++ parent_fe_bh = old_dir_bh;
++ get_bh(parent_fe_bh);
++ } else {
++ mlog(ML_ERROR, "%s: no old_dir_bh!\n", osb->uuid_str);
++ err = -EIO;
++ goto out;
++ }
++ }
++
+ if (!dir->i_nlink) {
+ err = -ENOENT;
+ goto out;
+ }
+
+- err = ocfs2_lookup_ino_from_name(dir, old_dentry->d_name.name,
++ err = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_de_ino);
+ if (err) {
+ err = -ENOENT;
+@@ -801,10 +825,11 @@ out_unlock_inode:
+ ocfs2_inode_unlock(inode, 1);
+
+ out:
+- ocfs2_inode_unlock(dir, 1);
++ ocfs2_double_unlock(old_dir, dir);
+
+ brelse(fe_bh);
+ brelse(parent_fe_bh);
++ brelse(old_dir_bh);
+
+ ocfs2_free_dir_lookup_result(&lookup);
+
+@@ -1072,14 +1097,15 @@ static int ocfs2_check_if_ancestor(struct ocfs2_super *osb,
+ }
+
+ /*
+- * The only place this should be used is rename!
++ * The only place this should be used is rename and link!
+ * if they have the same id, then the 1st one is the only one locked.
+ */
+ static int ocfs2_double_lock(struct ocfs2_super *osb,
+ struct buffer_head **bh1,
+ struct inode *inode1,
+ struct buffer_head **bh2,
+- struct inode *inode2)
++ struct inode *inode2,
++ int rename)
+ {
+ int status;
+ int inode1_is_ancestor, inode2_is_ancestor;
+@@ -1127,7 +1153,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
+ }
+ /* lock id2 */
+ status = ocfs2_inode_lock_nested(inode2, bh2, 1,
+- OI_LS_RENAME1);
++ rename == 1 ? OI_LS_RENAME1 : OI_LS_PARENT);
+ if (status < 0) {
+ if (status != -ENOENT)
+ mlog_errno(status);
+@@ -1136,7 +1162,8 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
+ }
+
+ /* lock id1 */
+- status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2);
++ status = ocfs2_inode_lock_nested(inode1, bh1, 1,
++ rename == 1 ? OI_LS_RENAME2 : OI_LS_PARENT);
+ if (status < 0) {
+ /*
+ * An error return must mean that no cluster locks
+@@ -1252,7 +1279,7 @@ static int ocfs2_rename(struct inode *old_dir,
+
+ /* if old and new are the same, this'll just do one lock. */
+ status = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
+- &new_dir_bh, new_dir);
++ &new_dir_bh, new_dir, 1);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;