[meta-freescale] [meta-fsl-ppc][PATCH] isofs: CVE-2014-5471, CVE-2014-5472

Sona Sarmadi sona.sarmadi at enea.com
Fri Sep 19 06:08:44 PDT 2014


Fix unbounded recursion when processing relocated directories

Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
---
 .../files/Fix-CVE-2014-5471_CVE-2014-5472.patch    | 212 +++++++++++++++++++++
 recipes-kernel/linux/linux-qoriq_3.12.bb           |   1 +
 2 files changed, 213 insertions(+)
 create mode 100644 recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch

diff --git a/recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch b/recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch
new file mode 100644
index 0000000..65107d6
--- /dev/null
+++ b/recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch
@@ -0,0 +1,212 @@
+From 4488e1f5ef40441c9846b1d0a29152c208a05e66 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack at suse.cz>
+Date: Sun, 17 Aug 2014 11:49:57 +0200
+Subject: [PATCH] isofs: Fix unbounded recursion when processing relocated
+ directories
+
+commit 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4 upstream.
+
+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.
+
+Upstream status: backported (from v3.12 e4ca8b780c82c04ec0)
+
+Reported-by: Chris Evans <cevans at google.com>
+Signed-off-by: Jan Kara <jack at suse.cz>
+Signed-off-by: Jiri Slaby <jslaby at suse.cz>
+Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
+---
+ fs/isofs/inode.c | 15 ++++++++-------
+ fs/isofs/isofs.h | 23 +++++++++++++++++++----
+ fs/isofs/rock.c  | 39 ++++++++++++++++++++++++++++-----------
+ 3 files changed, 55 insertions(+), 22 deletions(-)
+
+diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
+index e5d408a..2e2af97 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;
+@@ -1258,7 +1258,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);
+@@ -1403,7 +1403,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;
+@@ -1482,9 +1482,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;
+@@ -1506,7 +1507,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;
+ }
+-- 
+1.9.1
+
diff --git a/recipes-kernel/linux/linux-qoriq_3.12.bb b/recipes-kernel/linux/linux-qoriq_3.12.bb
index 4e9c50b..b3e3a41 100644
--- a/recipes-kernel/linux/linux-qoriq_3.12.bb
+++ b/recipes-kernel/linux/linux-qoriq_3.12.bb
@@ -3,6 +3,7 @@ require recipes-kernel/linux/linux-qoriq.inc
 SRC_URI = "git://git.freescale.com/ppc/sdk/linux.git;nobranch=1 \
     file://powerpc-Fix-64-bit-builds-with-binutils-2.24.patch \
     file://Fix-for-CVE-2014-5045-fs-umount-on-symlink-leak.patch \
+    file://Fix-CVE-2014-5471_CVE-2014-5472.patch \
 "
 SRCREV = "c29fe1a733308cbe592b3af054a97be1b91cf2dd"
 
-- 
1.9.1



More information about the meta-freescale mailing list