CVE-2014-{5471,5472} isofs: Fix unbounded recursion when processing relocated directories
This commit is contained in:
parent
a3696887c0
commit
0d360df2cd
@ -0,0 +1,199 @@
|
|||||||
|
commit 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4
|
||||||
|
Author: Jan Kara <jack@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@vger.kernel.org
|
||||||
|
Reported-by: Chris Evans <cevans@google.com>
|
||||||
|
Signed-off-by: Jan Kara <jack@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;
|
||||||
|
}
|
10
kernel.spec
10
kernel.spec
@ -652,6 +652,9 @@ Patch25122: nfs3_list_one_acl-check-get_acl-result-with-IS_ERR_O.patch
|
|||||||
#rhbz 1132666
|
#rhbz 1132666
|
||||||
Patch26016: xhci-Disable-streams-on-Via-XHCI-with-device-id-0x34.patch
|
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
|
||||||
|
|
||||||
# git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel
|
# git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel
|
||||||
Patch30000: kernel-arm64.patch
|
Patch30000: kernel-arm64.patch
|
||||||
|
|
||||||
@ -1388,6 +1391,9 @@ ApplyPatch nfs3_list_one_acl-check-get_acl-result-with-IS_ERR_O.patch
|
|||||||
#rhbz 1132666
|
#rhbz 1132666
|
||||||
ApplyPatch xhci-Disable-streams-on-Via-XHCI-with-device-id-0x34.patch
|
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
|
||||||
|
|
||||||
%if 0%{?aarch64patches}
|
%if 0%{?aarch64patches}
|
||||||
ApplyPatch kernel-arm64.patch
|
ApplyPatch kernel-arm64.patch
|
||||||
%ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does.
|
%ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does.
|
||||||
@ -2270,6 +2276,10 @@ fi
|
|||||||
# ||----w |
|
# ||----w |
|
||||||
# || ||
|
# || ||
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Aug 27 2014 Justin M. Forbes <jforbes@fedoraproject.org>
|
||||||
|
- CVE-2014-{5471,5472} isofs: Fix unbounded recursion when processing relocated
|
||||||
|
directories (rhbz 1134099 1134101)
|
||||||
|
|
||||||
* Wed Aug 27 2014 Josh Boyer <jwboyer@fedoraproject.org>
|
* Wed Aug 27 2014 Josh Boyer <jwboyer@fedoraproject.org>
|
||||||
- Disable streams on via XHCI (rhbz 1132666)
|
- Disable streams on via XHCI (rhbz 1132666)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user