From: Greg Kroah-Hartman Date: Tue, 10 Jul 2018 12:49:38 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v3.18.115~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a028e3ff2cb0cb7d1ae98059a5c6258e08ee0dec;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: cifs-fix-infinite-loop-when-using-hard-mount-option.patch ext4-add-more-mount-time-checks-of-the-superblock.patch ext4-clear-i_data-in-ext4_inode_info-when-removing-inline-data.patch ext4-make-sure-bitmaps-and-the-inode-table-don-t-overlap-with-bg-descriptors.patch --- diff --git a/queue-3.18/cifs-fix-infinite-loop-when-using-hard-mount-option.patch b/queue-3.18/cifs-fix-infinite-loop-when-using-hard-mount-option.patch new file mode 100644 index 00000000000..db559e092ae --- /dev/null +++ b/queue-3.18/cifs-fix-infinite-loop-when-using-hard-mount-option.patch @@ -0,0 +1,129 @@ +From 7ffbe65578b44fafdef577a360eb0583929f7c6e Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Thu, 5 Jul 2018 13:46:34 -0300 +Subject: cifs: Fix infinite loop when using hard mount option + +From: Paulo Alcantara + +commit 7ffbe65578b44fafdef577a360eb0583929f7c6e upstream. + +For every request we send, whether it is SMB1 or SMB2+, we attempt to +reconnect tcon (cifs_reconnect_tcon or smb2_reconnect) before carrying +out the request. + +So, while server->tcpStatus != CifsNeedReconnect, we wait for the +reconnection to succeed on wait_event_interruptible_timeout(). If it +returns, that means that either the condition was evaluated to true, or +timeout elapsed, or it was interrupted by a signal. + +Since we're not handling the case where the process woke up due to a +received signal (-ERESTARTSYS), the next call to +wait_event_interruptible_timeout() will _always_ fail and we end up +looping forever inside either cifs_reconnect_tcon() or smb2_reconnect(). + +Here's an example of how to trigger that: + +$ mount.cifs //foo/share /mnt/test -o +username=foo,password=foo,vers=1.0,hard + +(break connection to server before executing bellow cmd) +$ stat -f /mnt/test & sleep 140 +[1] 2511 + +$ ps -aux -q 2511 +USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND +root 2511 0.0 0.0 12892 1008 pts/0 S 12:24 0:00 stat -f +/mnt/test + +$ kill -9 2511 + +(wait for a while; process is stuck in the kernel) +$ ps -aux -q 2511 +USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND +root 2511 83.2 0.0 12892 1008 pts/0 R 12:24 30:01 stat -f +/mnt/test + +By using 'hard' mount point means that cifs.ko will keep retrying +indefinitely, however we must allow the process to be killed otherwise +it would hang the system. + +Signed-off-by: Paulo Alcantara +Cc: stable@vger.kernel.org +Reviewed-by: Aurelien Aptel +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/cifssmb.c | 10 ++++++++-- + fs/cifs/smb2pdu.c | 18 ++++++++++++------ + 2 files changed, 20 insertions(+), 8 deletions(-) + +--- a/fs/cifs/cifssmb.c ++++ b/fs/cifs/cifssmb.c +@@ -150,8 +150,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tc + * greater than cifs socket timeout which is 7 seconds + */ + while (server->tcpStatus == CifsNeedReconnect) { +- wait_event_interruptible_timeout(server->response_q, +- (server->tcpStatus != CifsNeedReconnect), 10 * HZ); ++ rc = wait_event_interruptible_timeout(server->response_q, ++ (server->tcpStatus != CifsNeedReconnect), ++ 10 * HZ); ++ if (rc < 0) { ++ cifs_dbg(FYI, "%s: aborting reconnect due to a received" ++ " signal by the process\n", __func__); ++ return -ERESTARTSYS; ++ } + + /* are we still trying to reconnect? */ + if (server->tcpStatus != CifsNeedReconnect) +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -144,7 +144,7 @@ out: + static int + smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) + { +- int rc = 0; ++ int rc; + struct nls_table *nls_codepage; + struct cifs_ses *ses; + struct TCP_Server_Info *server; +@@ -155,10 +155,10 @@ smb2_reconnect(__le16 smb2_command, stru + * for those three - in the calling routine. + */ + if (tcon == NULL) +- return rc; ++ return 0; + + if (smb2_command == SMB2_TREE_CONNECT) +- return rc; ++ return 0; + + if (tcon->tidStatus == CifsExiting) { + /* +@@ -201,8 +201,14 @@ smb2_reconnect(__le16 smb2_command, stru + return -EAGAIN; + } + +- wait_event_interruptible_timeout(server->response_q, +- (server->tcpStatus != CifsNeedReconnect), 10 * HZ); ++ rc = wait_event_interruptible_timeout(server->response_q, ++ (server->tcpStatus != CifsNeedReconnect), ++ 10 * HZ); ++ if (rc < 0) { ++ cifs_dbg(FYI, "%s: aborting reconnect due to a received" ++ " signal by the process\n", __func__); ++ return -ERESTARTSYS; ++ } + + /* are we still trying to reconnect? */ + if (server->tcpStatus != CifsNeedReconnect) +@@ -220,7 +226,7 @@ smb2_reconnect(__le16 smb2_command, stru + } + + if (!tcon->ses->need_reconnect && !tcon->need_reconnect) +- return rc; ++ return 0; + + nls_codepage = load_nls_default(); + diff --git a/queue-3.18/ext4-add-more-mount-time-checks-of-the-superblock.patch b/queue-3.18/ext4-add-more-mount-time-checks-of-the-superblock.patch new file mode 100644 index 00000000000..63d72df3168 --- /dev/null +++ b/queue-3.18/ext4-add-more-mount-time-checks-of-the-superblock.patch @@ -0,0 +1,99 @@ +From bfe0a5f47ada40d7984de67e59a7d3390b9b9ecc Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sun, 17 Jun 2018 18:11:20 -0400 +Subject: ext4: add more mount time checks of the superblock + +From: Theodore Ts'o + +commit bfe0a5f47ada40d7984de67e59a7d3390b9b9ecc upstream. + +The kernel's ext4 mount-time checks were more permissive than +e2fsprogs's libext2fs checks when opening a file system. The +superblock is considered too insane for debugfs or e2fsck to operate +on it, the kernel has no business trying to mount it. + +This will make file system fuzzing tools work harder, but the failure +cases that they find will be more useful and be easier to evaluate. + +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/super.c | 37 ++++++++++++++++++++++++++----------- + 1 file changed, 26 insertions(+), 11 deletions(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3738,6 +3738,13 @@ static int ext4_fill_super(struct super_ + le32_to_cpu(es->s_log_block_size)); + goto failed_mount; + } ++ if (le32_to_cpu(es->s_log_cluster_size) > ++ (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { ++ ext4_msg(sb, KERN_ERR, ++ "Invalid log cluster size: %u", ++ le32_to_cpu(es->s_log_cluster_size)); ++ goto failed_mount; ++ } + + if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { + ext4_msg(sb, KERN_ERR, +@@ -3861,13 +3868,6 @@ static int ext4_fill_super(struct super_ + "block size (%d)", clustersize, blocksize); + goto failed_mount; + } +- if (le32_to_cpu(es->s_log_cluster_size) > +- (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { +- ext4_msg(sb, KERN_ERR, +- "Invalid log cluster size: %u", +- le32_to_cpu(es->s_log_cluster_size)); +- goto failed_mount; +- } + sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - + le32_to_cpu(es->s_log_block_size); + sbi->s_clusters_per_group = +@@ -3888,10 +3888,10 @@ static int ext4_fill_super(struct super_ + } + } else { + if (clustersize != blocksize) { +- ext4_warning(sb, "fragment/cluster size (%d) != " +- "block size (%d)", clustersize, +- blocksize); +- clustersize = blocksize; ++ ext4_msg(sb, KERN_ERR, ++ "fragment/cluster size (%d) != " ++ "block size (%d)", clustersize, blocksize); ++ goto failed_mount; + } + if (sbi->s_blocks_per_group > blocksize * 8) { + ext4_msg(sb, KERN_ERR, +@@ -3945,6 +3945,13 @@ static int ext4_fill_super(struct super_ + ext4_blocks_count(es)); + goto failed_mount; + } ++ if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) && ++ (sbi->s_cluster_ratio == 1)) { ++ ext4_msg(sb, KERN_WARNING, "bad geometry: first data " ++ "block is 0 with a 1k block and cluster size"); ++ goto failed_mount; ++ } ++ + blocks_count = (ext4_blocks_count(es) - + le32_to_cpu(es->s_first_data_block) + + EXT4_BLOCKS_PER_GROUP(sb) - 1); +@@ -3980,6 +3987,14 @@ static int ext4_fill_super(struct super_ + ret = -ENOMEM; + goto failed_mount; + } ++ if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) != ++ le32_to_cpu(es->s_inodes_count)) { ++ ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu", ++ le32_to_cpu(es->s_inodes_count), ++ ((u64)sbi->s_groups_count * sbi->s_inodes_per_group)); ++ ret = -EINVAL; ++ goto failed_mount; ++ } + + if (ext4_proc_root) + sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); diff --git a/queue-3.18/ext4-clear-i_data-in-ext4_inode_info-when-removing-inline-data.patch b/queue-3.18/ext4-clear-i_data-in-ext4_inode_info-when-removing-inline-data.patch new file mode 100644 index 00000000000..aec23c82c74 --- /dev/null +++ b/queue-3.18/ext4-clear-i_data-in-ext4_inode_info-when-removing-inline-data.patch @@ -0,0 +1,48 @@ +From 6e8ab72a812396996035a37e5ca4b3b99b5d214b Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Fri, 15 Jun 2018 12:28:16 -0400 +Subject: ext4: clear i_data in ext4_inode_info when removing inline data + +From: Theodore Ts'o + +commit 6e8ab72a812396996035a37e5ca4b3b99b5d214b upstream. + +When converting from an inode from storing the data in-line to a data +block, ext4_destroy_inline_data_nolock() was only clearing the on-disk +copy of the i_blocks[] array. It was not clearing copy of the +i_blocks[] in ext4_inode_info, in i_data[], which is the copy actually +used by ext4_map_blocks(). + +This didn't matter much if we are using extents, since the extents +header would be invalid and thus the extents could would re-initialize +the extents tree. But if we are using indirect blocks, the previous +contents of the i_blocks array will be treated as block numbers, with +potentially catastrophic results to the file system integrity and/or +user data. + +This gets worse if the file system is using a 1k block size and +s_first_data is zero, but even without this, the file system can get +quite badly corrupted. + +This addresses CVE-2018-10881. + +https://bugzilla.kernel.org/show_bug.cgi?id=200015 + +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/inline.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ext4/inline.c ++++ b/fs/ext4/inline.c +@@ -432,6 +432,7 @@ static int ext4_destroy_inline_data_nolo + + memset((void *)ext4_raw_inode(&is.iloc)->i_block, + 0, EXT4_MIN_INLINE_DATA_SIZE); ++ memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE); + + if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb, + EXT4_FEATURE_INCOMPAT_EXTENTS)) { diff --git a/queue-3.18/ext4-make-sure-bitmaps-and-the-inode-table-don-t-overlap-with-bg-descriptors.patch b/queue-3.18/ext4-make-sure-bitmaps-and-the-inode-table-don-t-overlap-with-bg-descriptors.patch new file mode 100644 index 00000000000..b98c05855ff --- /dev/null +++ b/queue-3.18/ext4-make-sure-bitmaps-and-the-inode-table-don-t-overlap-with-bg-descriptors.patch @@ -0,0 +1,79 @@ +From 77260807d1170a8cf35dbb06e07461a655f67eee Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Wed, 13 Jun 2018 23:08:26 -0400 +Subject: ext4: make sure bitmaps and the inode table don't overlap with bg descriptors + +From: Theodore Ts'o + +commit 77260807d1170a8cf35dbb06e07461a655f67eee upstream. + +It's really bad when the allocation bitmaps and the inode table +overlap with the block group descriptors, since it causes random +corruption of the bg descriptors. So we really want to head those off +at the pass. + +https://bugzilla.kernel.org/show_bug.cgi?id=199865 + +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/super.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -2064,6 +2064,7 @@ static int ext4_check_descriptors(struct + struct ext4_sb_info *sbi = EXT4_SB(sb); + ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); + ext4_fsblk_t last_block; ++ ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0) + 1; + ext4_fsblk_t block_bitmap; + ext4_fsblk_t inode_bitmap; + ext4_fsblk_t inode_table; +@@ -2096,6 +2097,14 @@ static int ext4_check_descriptors(struct + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } ++ if (block_bitmap >= sb_block + 1 && ++ block_bitmap <= last_bg_block) { ++ ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " ++ "Block bitmap for group %u overlaps " ++ "block group descriptors", i); ++ if (!(sb->s_flags & MS_RDONLY)) ++ return 0; ++ } + if (block_bitmap < first_block || block_bitmap > last_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Block bitmap for group %u not in group " +@@ -2110,6 +2119,14 @@ static int ext4_check_descriptors(struct + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } ++ if (inode_bitmap >= sb_block + 1 && ++ inode_bitmap <= last_bg_block) { ++ ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " ++ "Inode bitmap for group %u overlaps " ++ "block group descriptors", i); ++ if (!(sb->s_flags & MS_RDONLY)) ++ return 0; ++ } + if (inode_bitmap < first_block || inode_bitmap > last_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Inode bitmap for group %u not in group " +@@ -2124,6 +2141,14 @@ static int ext4_check_descriptors(struct + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } ++ if (inode_table >= sb_block + 1 && ++ inode_table <= last_bg_block) { ++ ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " ++ "Inode table for group %u overlaps " ++ "block group descriptors", i); ++ if (!(sb->s_flags & MS_RDONLY)) ++ return 0; ++ } + if (inode_table < first_block || + inode_table + sbi->s_itb_per_group - 1 > last_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " diff --git a/queue-3.18/series b/queue-3.18/series index d7adbe76058..353e2618dbc 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -7,3 +7,7 @@ atm-zatm-fix-memcmp-casting.patch net-qmi_wwan-add-netgear-aircard-779s.patch net-sonic-use-dma_mapping_error.patch scsi-sg-mitigate-read-write-abuse.patch +cifs-fix-infinite-loop-when-using-hard-mount-option.patch +ext4-make-sure-bitmaps-and-the-inode-table-don-t-overlap-with-bg-descriptors.patch +ext4-clear-i_data-in-ext4_inode_info-when-removing-inline-data.patch +ext4-add-more-mount-time-checks-of-the-superblock.patch