[kernel/f20] CVE-2014-{5471, 5472} isofs: Fix unbounded recursion when processing relocated directories
Justin M. Forbes
jforbes at fedoraproject.org
Wed Aug 27 20:52:43 UTC 2014
commit 532f06fd8a70e1296bb085d4e6475af5a3da40af
Author: Justin M. Forbes <jforbes at redhat.com>
Date: Wed Aug 27 15:52:39 2014 -0500
CVE-2014-{5471,5472} isofs: Fix unbounded recursion when processing relocated directories
...ion-when-processing-relocated-directories.patch | 199 ++++++++++++++++++++
kernel.spec | 12 +-
2 files changed, 210 insertions(+), 1 deletions(-)
---
diff --git a/isofs-Fix-unbounded-recursion-when-processing-relocated-directories.patch b/isofs-Fix-unbounded-recursion-when-processing-relocated-directories.patch
new file mode 100644
index 0000000..e937682
--- /dev/null
+++ b/isofs-Fix-unbounded-recursion-when-processing-relocated-directories.patch
@@ -0,0 +1,199 @@
+commit 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4
+Author: Jan Kara <jack at suse.cz>
+Date: Sun Aug 17 11:49:57 2014 +0200
+
+ isofs: Fix unbounded recursion when processing relocated directories
+
+ We did not check relocated directory in any way when processing Rock
+ Ridge 'CL' tag. Thus a corrupted isofs image can possibly have a CL
+ entry pointing to another CL entry leading to possibly unbounded
+ recursion in kernel code and thus stack overflow or deadlocks (if there
+ is a loop created from CL entries).
+
+ Fix the problem by not allowing CL entry to point to a directory entry
+ with CL entry (such use makes no good sense anyway) and by checking
+ whether CL entry doesn't point to itself.
+
+ CC: stable at vger.kernel.org
+ Reported-by: Chris Evans <cevans at google.com>
+ Signed-off-by: Jan Kara <jack at suse.cz>
+
+diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
+index 4556ce1..5ddaf86 100644
+--- a/fs/isofs/inode.c
++++ b/fs/isofs/inode.c
+@@ -61,7 +61,7 @@ static void isofs_put_super(struct super_block *sb)
+ return;
+ }
+
+-static int isofs_read_inode(struct inode *);
++static int isofs_read_inode(struct inode *, int relocated);
+ static int isofs_statfs (struct dentry *, struct kstatfs *);
+
+ static struct kmem_cache *isofs_inode_cachep;
+@@ -1259,7 +1259,7 @@ out_toomany:
+ goto out;
+ }
+
+-static int isofs_read_inode(struct inode *inode)
++static int isofs_read_inode(struct inode *inode, int relocated)
+ {
+ struct super_block *sb = inode->i_sb;
+ struct isofs_sb_info *sbi = ISOFS_SB(sb);
+@@ -1404,7 +1404,7 @@ static int isofs_read_inode(struct inode *inode)
+ */
+
+ if (!high_sierra) {
+- parse_rock_ridge_inode(de, inode);
++ parse_rock_ridge_inode(de, inode, relocated);
+ /* if we want uid/gid set, override the rock ridge setting */
+ if (sbi->s_uid_set)
+ inode->i_uid = sbi->s_uid;
+@@ -1483,9 +1483,10 @@ static int isofs_iget5_set(struct inode *ino, void *data)
+ * offset that point to the underlying meta-data for the inode. The
+ * code below is otherwise similar to the iget() code in
+ * include/linux/fs.h */
+-struct inode *isofs_iget(struct super_block *sb,
+- unsigned long block,
+- unsigned long offset)
++struct inode *__isofs_iget(struct super_block *sb,
++ unsigned long block,
++ unsigned long offset,
++ int relocated)
+ {
+ unsigned long hashval;
+ struct inode *inode;
+@@ -1507,7 +1508,7 @@ struct inode *isofs_iget(struct super_block *sb,
+ return ERR_PTR(-ENOMEM);
+
+ if (inode->i_state & I_NEW) {
+- ret = isofs_read_inode(inode);
++ ret = isofs_read_inode(inode, relocated);
+ if (ret < 0) {
+ iget_failed(inode);
+ inode = ERR_PTR(ret);
+diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
+index 9916723..0ac4c1f 100644
+--- a/fs/isofs/isofs.h
++++ b/fs/isofs/isofs.h
+@@ -107,7 +107,7 @@ extern int iso_date(char *, int);
+
+ struct inode; /* To make gcc happy */
+
+-extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
++extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated);
+ extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
+ extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
+
+@@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int
+ extern struct buffer_head *isofs_bread(struct inode *, sector_t);
+ extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
+
+-extern struct inode *isofs_iget(struct super_block *sb,
+- unsigned long block,
+- unsigned long offset);
++struct inode *__isofs_iget(struct super_block *sb,
++ unsigned long block,
++ unsigned long offset,
++ int relocated);
++
++static inline struct inode *isofs_iget(struct super_block *sb,
++ unsigned long block,
++ unsigned long offset)
++{
++ return __isofs_iget(sb, block, offset, 0);
++}
++
++static inline struct inode *isofs_iget_reloc(struct super_block *sb,
++ unsigned long block,
++ unsigned long offset)
++{
++ return __isofs_iget(sb, block, offset, 1);
++}
+
+ /* Because the inode number is no longer relevant to finding the
+ * underlying meta-data for an inode, we are free to choose a more
+diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
+index c0bf424..f488bba 100644
+--- a/fs/isofs/rock.c
++++ b/fs/isofs/rock.c
+@@ -288,12 +288,16 @@ eio:
+ goto out;
+ }
+
++#define RR_REGARD_XA 1
++#define RR_RELOC_DE 2
++
+ static int
+ parse_rock_ridge_inode_internal(struct iso_directory_record *de,
+- struct inode *inode, int regard_xa)
++ struct inode *inode, int flags)
+ {
+ int symlink_len = 0;
+ int cnt, sig;
++ unsigned int reloc_block;
+ struct inode *reloc;
+ struct rock_ridge *rr;
+ int rootflag;
+@@ -305,7 +309,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de,
+
+ init_rock_state(&rs, inode);
+ setup_rock_ridge(de, inode, &rs);
+- if (regard_xa) {
++ if (flags & RR_REGARD_XA) {
+ rs.chr += 14;
+ rs.len -= 14;
+ if (rs.len < 0)
+@@ -485,12 +489,22 @@ repeat:
+ "relocated directory\n");
+ goto out;
+ case SIG('C', 'L'):
+- ISOFS_I(inode)->i_first_extent =
+- isonum_733(rr->u.CL.location);
+- reloc =
+- isofs_iget(inode->i_sb,
+- ISOFS_I(inode)->i_first_extent,
+- 0);
++ if (flags & RR_RELOC_DE) {
++ printk(KERN_ERR
++ "ISOFS: Recursive directory relocation "
++ "is not supported\n");
++ goto eio;
++ }
++ reloc_block = isonum_733(rr->u.CL.location);
++ if (reloc_block == ISOFS_I(inode)->i_iget5_block &&
++ ISOFS_I(inode)->i_iget5_offset == 0) {
++ printk(KERN_ERR
++ "ISOFS: Directory relocation points to "
++ "itself\n");
++ goto eio;
++ }
++ ISOFS_I(inode)->i_first_extent = reloc_block;
++ reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0);
+ if (IS_ERR(reloc)) {
+ ret = PTR_ERR(reloc);
+ goto out;
+@@ -637,9 +651,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
+ return rpnt;
+ }
+
+-int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
++int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode,
++ int relocated)
+ {
+- int result = parse_rock_ridge_inode_internal(de, inode, 0);
++ int flags = relocated ? RR_RELOC_DE : 0;
++ int result = parse_rock_ridge_inode_internal(de, inode, flags);
+
+ /*
+ * if rockridge flag was reset and we didn't look for attributes
+@@ -647,7 +663,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
+ */
+ if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
+ && (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
+- result = parse_rock_ridge_inode_internal(de, inode, 14);
++ result = parse_rock_ridge_inode_internal(de, inode,
++ flags | RR_REGARD_XA);
+ }
+ return result;
+ }
diff --git a/kernel.spec b/kernel.spec
index 84202b5..7e14d03 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -62,7 +62,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be appended after the rcX and
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
#
-%global baserelease 200
+%global baserelease 201
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@@ -762,6 +762,9 @@ Patch25132: nfs3_list_one_acl-check-get_acl-result-with-IS_ERR_O.patch
#rhbz 1132666
Patch26016: xhci-Disable-streams-on-Via-XHCI-with-device-id-0x34.patch
+#CVE-2014-{5471,5472} rhbz 1134099 1134101
+Patch26017: isofs-Fix-unbounded-recursion-when-processing-relocated-directories.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -1482,6 +1485,9 @@ ApplyPatch nfs3_list_one_acl-check-get_acl-result-with-IS_ERR_O.patch
#rhbz 1132666
ApplyPatch xhci-Disable-streams-on-Via-XHCI-with-device-id-0x34.patch
+#CVE-2014-{5471,5472} rhbz 1134099 1134101
+ApplyPatch isofs-Fix-unbounded-recursion-when-processing-relocated-directories.patch
+
# END OF PATCH APPLICATIONS
%endif
@@ -2293,6 +2299,10 @@ fi
# ||----w |
# || ||
%changelog
+* Wed Aug 27 2014 Justin M. Forbes <jforbes at fedoraproject.org> - 3.15.10-201
+- CVE-2014-{5471,5472} isofs: Fix unbounded recursion when processing relocated
+ directories (rhbz 1134099 1134101)
+
* Wed Aug 27 2014 Josh Boyer <jwboyer at fedoraproject.org>
- Disable streams on via XHCI (rhbz 1132666)
More information about the scm-commits
mailing list