Vulnerability: The __udf_read_inode function in fs/udf/inode.c in the Linux kernel through 3.16.3 does not restrict the amount of ICB indirection, which allows physically proximate attackers to cause a denial of service (infinite loop or stack consumption) via a UDF filesystem with a crafted inode.
Vulnerability ID: CVE-2014-6410
CWE: CWE-399
Severity score: 6.9
Project: https://github.com/torvalds/linux
Published: 2014-09-28
File: fs/udf/inode.c
Commit message: udf: Avoid infinite loop when processing indirect ICBs

We did not implement any bound on number of indirect ICBs we follow when
loading inode. Thus corrupted medium could cause kernel to go into an
infinite loop, possibly causing a stack overflow.

Fix the possible stack overflow by removing recursion from
__udf_read_inode() and limit number of indirect ICBs we follow to avoid
infinite loops.

Signed-off-by: Jan Kara <jack@suse.cz>
Commit author: Jan Kara

Vulnerable version (before fix):
 int udf_setsize(struct inode *inode, loff_t newsize) 	return 0; }  static void __udf_read_inode(struct inode *inode) { 	struct buffer_head *bh = NULL; static void __udf_read_inode(struct inode *inode) 	struct udf_inode_info *iinfo = UDF_I(inode); 	struct udf_sb_info *sbi = UDF_SB(inode->i_sb); 	unsigned int link_count;  	/* 	 * Set defaults, but the inode is still incomplete! 	 * Note: get_new_inode() sets the following on a new inode: static void __udf_read_inode(struct inode *inode) 		ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1, 					&ident); 		if (ident == TAG_IDENT_IE && ibh) { 			struct buffer_head *nbh = NULL; 			struct kernel_lb_addr loc; 			struct indirectEntry *ie;  			ie = (struct indirectEntry *)ibh->b_data; 			loc = lelb_to_cpu(ie->indirectICB.extLocation);  			if (ie->indirectICB.extLength && 				(nbh = udf_read_ptagged(inode->i_sb, &loc, 0, 							&ident))) { 				if (ident == TAG_IDENT_FE || 					ident == TAG_IDENT_EFE) { 					memcpy(&iinfo->i_location, 						&loc, 						sizeof(struct kernel_lb_addr)); 					brelse(bh); 					brelse(ibh); 					brelse(nbh); 					__udf_read_inode(inode); 					return; 				} 				brelse(nbh); 			} 		} 		brelse(ibh);

Fixed version (after fix):
 int udf_setsize(struct inode *inode, loff_t newsize) 	return 0; }  /*  * Maximum length of linked list formed by ICB hierarchy. The chosen number is  * arbitrary - just that we hopefully don't limit any real use of rewritten  * inode on write-once media but avoid looping for too long on corrupted media.  */ #define UDF_MAX_ICB_NESTING 1024  static void __udf_read_inode(struct inode *inode) { 	struct buffer_head *bh = NULL; static void __udf_read_inode(struct inode *inode) 	struct udf_inode_info *iinfo = UDF_I(inode); 	struct udf_sb_info *sbi = UDF_SB(inode->i_sb); 	unsigned int link_count; 	unsigned int indirections = 0;  reread: 	/* 	 * Set defaults, but the inode is still incomplete! 	 * Note: get_new_inode() sets the following on a new inode: static void __udf_read_inode(struct inode *inode) 		ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1, 					&ident); 		if (ident == TAG_IDENT_IE && ibh) { 			struct kernel_lb_addr loc; 			struct indirectEntry *ie;  			ie = (struct indirectEntry *)ibh->b_data; 			loc = lelb_to_cpu(ie->indirectICB.extLocation);  			if (ie->indirectICB.extLength) { 				brelse(bh); 				brelse(ibh); 				memcpy(&iinfo->i_location, &loc, 				       sizeof(struct kernel_lb_addr)); 				if (++indirections > UDF_MAX_ICB_NESTING) { 					udf_err(inode->i_sb, 						"too many ICBs in ICB hierarchy" 						" (max %d supported)\n", 						UDF_MAX_ICB_NESTING); 					make_bad_inode(inode); 					return; 				} 				goto reread; 			} 		} 		brelse(ibh);

Patch:
patch: @@ -1270,6 +1270,13 @@ int udf_setsize(struct inode *inode, loff_t newsize)
 	return 0;
 }
 
+/*
+ * Maximum length of linked list formed by ICB hierarchy. The chosen number is
+ * arbitrary - just that we hopefully don't limit any real use of rewritten
+ * inode on write-once media but avoid looping for too long on corrupted media.
+ */
+#define UDF_MAX_ICB_NESTING 1024
+
 static void __udf_read_inode(struct inode *inode)
 {
 	struct buffer_head *bh = NULL;
@@ -1279,7 +1286,9 @@ static void __udf_read_inode(struct inode *inode)
 	struct udf_inode_info *iinfo = UDF_I(inode);
 	struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
 	unsigned int link_count;
+	unsigned int indirections = 0;
 
+reread:
 	/*
 	 * Set defaults, but the inode is still incomplete!
 	 * Note: get_new_inode() sets the following on a new inode:
@@ -1317,28 +1326,26 @@ static void __udf_read_inode(struct inode *inode)
 		ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1,
 					&ident);
 		if (ident == TAG_IDENT_IE && ibh) {
-			struct buffer_head *nbh = NULL;
 			struct kernel_lb_addr loc;
 			struct indirectEntry *ie;
 
 			ie = (struct indirectEntry *)ibh->b_data;
 			loc = lelb_to_cpu(ie->indirectICB.extLocation);
 
-			if (ie->indirectICB.extLength &&
-				(nbh = udf_read_ptagged(inode->i_sb, &loc, 0,
-							&ident))) {
-				if (ident == TAG_IDENT_FE ||
-					ident == TAG_IDENT_EFE) {
-					memcpy(&iinfo->i_location,
-						&loc,
-						sizeof(struct kernel_lb_addr));
-					brelse(bh);
-					brelse(ibh);
-					brelse(nbh);
-					__udf_read_inode(inode);
+			if (ie->indirectICB.extLength) {
+				brelse(bh);
+				brelse(ibh);
+				memcpy(&iinfo->i_location, &loc,
+				       sizeof(struct kernel_lb_addr));
+				if (++indirections > UDF_MAX_ICB_NESTING) {
+					udf_err(inode->i_sb,
+						"too many ICBs in ICB hierarchy"
+						" (max %d supported)\n",
+						UDF_MAX_ICB_NESTING);
+					make_bad_inode(inode);
 					return;
 				}
-				brelse(nbh);
+				goto reread;
 			}
 		}
 		brelse(ibh);
path: fs/udf/inode.c