]> code.ossystems Code Review - meta-freescale.git/commitdiff
linux: sofs - CVE-2014-5471, CVE-2014-5472
authorSona Sarmadi <sona.sarmadi@enea.com>
Fri, 26 Sep 2014 07:18:31 +0000 (15:18 +0800)
committerZhenhua Luo <zhenhua.luo@freescale.com>
Fri, 26 Sep 2014 07:18:31 +0000 (15:18 +0800)
Fix unbounded recursion when processing relocated directories

Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
Signed-off-by: Zhenhua Luo <zhenhua.luo@freescale.com>
meta-fsl-ppc/recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch [new file with mode: 0644]
meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb

diff --git a/meta-fsl-ppc/recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch b/meta-fsl-ppc/recipes-kernel/linux/files/Fix-CVE-2014-5471_CVE-2014-5472.patch
new file mode 100644 (file)
index 0000000..65107d6
--- /dev/null
@@ -0,0 +1,212 @@
+From 4488e1f5ef40441c9846b1d0a29152c208a05e66 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@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@google.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Sona Sarmadi <sona.sarmadi@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
+
index 93a0bba74a8c0556ccd128f14756ac529a5dd363..39270d4819f9ec92e5e151210d457156bac74836 100644 (file)
@@ -4,6 +4,7 @@ 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-5077-sctp-inherit-auth-capable-on-INIT-collisions.patch \
+    file://Fix-CVE-2014-5471_CVE-2014-5472.patch \
 "
 SRCREV = "c29fe1a733308cbe592b3af054a97be1b91cf2dd"