diff --git a/e2fsprogs.changes b/e2fsprogs.changes index 3a71caf..1ab6a7c 100644 --- a/e2fsprogs.changes +++ b/e2fsprogs.changes @@ -1,3 +1,15 @@ +------------------------------------------------------------------- +Mon Sep 30 15:07:58 UTC 2019 - Jan Kara + +- libsupport-add-checks-to-prevent-buffer-overrun-bugs.patch: add checks to + prevent buffer overrun bugs in quota code (bsc#1152101, CVE-2019-5094) + +------------------------------------------------------------------- +Wed Aug 28 16:00:08 UTC 2019 - Jan Kara + +- libext2fs-call-fsync-2-to-clear-stale-errors-for-a-n.patch: libext2fs: call + fsync(2) to clear stale errors for a new a unix I/O channel (bsc#1145716) + ------------------------------------------------------------------- Thu May 16 15:18:23 UTC 2019 - Jan Kara diff --git a/e2fsprogs.spec b/e2fsprogs.spec index 94fc6b8..7569e2c 100644 --- a/e2fsprogs.spec +++ b/e2fsprogs.spec @@ -83,6 +83,8 @@ Patch4: e2fsprogs-1.42-implicit_fortify_decl.patch Patch5: e2fsprogs-1.42-ext2fsh_implicit.patch Patch6: libext2fs-Fix-fsync-2-detection.patch Patch7: e2fsck-check-and-fix-tails-of-all-bitmaps.patch +Patch8: libext2fs-call-fsync-2-to-clear-stale-errors-for-a-n.patch +Patch9: libsupport-add-checks-to-prevent-buffer-overrun-bugs.patch # Do not suppress make commands BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -229,6 +231,8 @@ Development files for the com_err error message display library. Static librarie %patch5 %patch6 -p1 %patch7 -p1 +%patch8 -p1 +%patch9 -p1 cp %{SOURCE2} . %build diff --git a/libext2fs-call-fsync-2-to-clear-stale-errors-for-a-n.patch b/libext2fs-call-fsync-2-to-clear-stale-errors-for-a-n.patch new file mode 100644 index 0000000..3a191ae --- /dev/null +++ b/libext2fs-call-fsync-2-to-clear-stale-errors-for-a-n.patch @@ -0,0 +1,43 @@ +From e8236b49d0fb056847da5fb95b2709e63e6be7c6 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Wed, 4 Jul 2018 00:23:10 -0400 +Subject: [PATCH] libext2fs: call fsync(2) to clear stale errors for a new a + unix I/O channel +References: bsc#1145716 + +Newer versions of Linux will retain errors and allow them to be +returned by fsync() or close(), even if the error happened before the +file descriptor was opened. This was to accomodate Postgres's +"interesting" method of error collection. + +Unfortunately, for e2fsck, we never want to see stale errors, as this +can cause xfstests (such generic/347) to fail with a false positive. + +Signed-off-by: Theodore Ts'o +Acked-by: Jan Kara +--- + lib/ext2fs/unix_io.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c +index 53fbd28bf803..18a2e5f75c07 100644 +--- a/lib/ext2fs/unix_io.c ++++ b/lib/ext2fs/unix_io.c +@@ -569,6 +569,14 @@ static errcode_t unix_open_channel(const char *name, int fd, + if (safe_getenv("UNIX_IO_FORCE_BOUNCE")) + flags |= IO_FLAG_FORCE_BOUNCE; + ++#ifdef __linux__ ++ /* ++ * We need to make sure any previous errors in the block ++ * device are thrown away, sigh. ++ */ ++ (void) fsync(fd); ++#endif ++ + retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); + if (retval) + goto cleanup; +-- +2.16.4 + diff --git a/libsupport-add-checks-to-prevent-buffer-overrun-bugs.patch b/libsupport-add-checks-to-prevent-buffer-overrun-bugs.patch new file mode 100644 index 0000000..4933e54 --- /dev/null +++ b/libsupport-add-checks-to-prevent-buffer-overrun-bugs.patch @@ -0,0 +1,214 @@ +From 8dbe7b475ec5e91ed767239f0e85880f416fc384 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sun, 1 Sep 2019 00:59:16 -0400 +Subject: [PATCH] libsupport: add checks to prevent buffer overrun bugs in + quota code +References: bsc#1152101 CVE-2019-5094 + +A maliciously corrupted file systems can trigger buffer overruns in +the quota code used by e2fsck. To fix this, add sanity checks to the +quota header fields as well as to block number references in the quota +tree. + +Addresses: CVE-2019-5094 +Addresses: TALOS-2019-0887 +Signed-off-by: Theodore Ts'o +Acked-by: Jan Kara +--- + lib/support/mkquota.c | 1 + + lib/support/quotaio_tree.c | 71 ++++++++++++++++++++++++++++++---------------- + lib/support/quotaio_v2.c | 28 ++++++++++++++++++ + 3 files changed, 76 insertions(+), 24 deletions(-) + +diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c +index 0b9e76659118..ddb531247819 100644 +--- a/lib/support/mkquota.c ++++ b/lib/support/mkquota.c +@@ -671,6 +671,7 @@ errcode_t quota_compare_and_update(quota_ctx_t qctx, enum quota_type qtype, + err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); + if (err) { + log_debug("Error scanning dquots"); ++ *usage_inconsistent = 1; + goto out_close_qh; + } + +diff --git a/lib/support/quotaio_tree.c b/lib/support/quotaio_tree.c +index a7c2028c1dc7..6cc4fb5b2c10 100644 +--- a/lib/support/quotaio_tree.c ++++ b/lib/support/quotaio_tree.c +@@ -540,6 +540,17 @@ struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) + return dquot; + } + ++static int check_reference(struct quota_handle *h, unsigned int blk) ++{ ++ if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) { ++ log_err("Illegal reference (%u >= %u) in %s quota file", ++ blk, h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, ++ quota_type2name(h->qh_type)); ++ return -1; ++ } ++ return 0; ++} ++ + /* + * Scan all dquots in file and call callback on each + */ +@@ -558,7 +569,7 @@ static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, + int entries, i; + + if (!buf) +- return 0; ++ return -1; + + set_bit(bitmap, blk); + read_blk(dquot->dq_h, blk, buf); +@@ -580,23 +591,12 @@ static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, + return entries; + } + +-static void check_reference(struct quota_handle *h, unsigned int blk) +-{ +- if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) +- log_err("Illegal reference (%u >= %u) in %s quota file. " +- "Quota file is probably corrupted.\n" +- "Please run e2fsck (8) to fix it.", +- blk, +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, +- quota_type2name(h->qh_type)); +-} +- + static int report_tree(struct dquot *dquot, unsigned int blk, int depth, + char *bitmap, + int (*process_dquot) (struct dquot *, void *), + void *data) + { +- int entries = 0, i; ++ int entries = 0, ret, i; + dqbuf_t buf = getdqbuf(); + __le32 *ref = (__le32 *) buf; + +@@ -607,22 +607,40 @@ static int report_tree(struct dquot *dquot, unsigned int blk, int depth, + if (depth == QT_TREEDEPTH - 1) { + for (i = 0; i < QT_BLKSIZE >> 2; i++) { + blk = ext2fs_le32_to_cpu(ref[i]); +- check_reference(dquot->dq_h, blk); +- if (blk && !get_bit(bitmap, blk)) +- entries += report_block(dquot, blk, bitmap, +- process_dquot, data); ++ if (check_reference(dquot->dq_h, blk)) { ++ entries = -1; ++ goto errout; ++ } ++ if (blk && !get_bit(bitmap, blk)) { ++ ret = report_block(dquot, blk, bitmap, ++ process_dquot, data); ++ if (ret < 0) { ++ entries = ret; ++ goto errout; ++ } ++ entries += ret; ++ } + } + } else { + for (i = 0; i < QT_BLKSIZE >> 2; i++) { + blk = ext2fs_le32_to_cpu(ref[i]); + if (blk) { +- check_reference(dquot->dq_h, blk); +- entries += report_tree(dquot, blk, depth + 1, +- bitmap, process_dquot, +- data); ++ if (check_reference(dquot->dq_h, blk)) { ++ entries = -1; ++ goto errout; ++ } ++ ret = report_tree(dquot, blk, depth + 1, ++ bitmap, process_dquot, ++ data); ++ if (ret < 0) { ++ entries = ret; ++ goto errout; ++ } ++ entries += ret; + } + } + } ++errout: + freedqbuf(buf); + return entries; + } +@@ -642,6 +660,7 @@ int qtree_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), + void *data) + { ++ int ret; + char *bitmap; + struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; + struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; +@@ -655,10 +674,14 @@ int qtree_scan_dquots(struct quota_handle *h, + ext2fs_free_mem(&dquot); + return -1; + } +- v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, +- process_dquot, data); ++ ret = report_tree(dquot, QT_TREEOFF, 0, bitmap, process_dquot, data); ++ if (ret < 0) ++ goto errout; ++ v2info->dqi_used_entries = ret; + v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); ++ ret = 0; ++errout: + ext2fs_free_mem(&bitmap); + ext2fs_free_mem(&dquot); +- return 0; ++ return ret; + } +diff --git a/lib/support/quotaio_v2.c b/lib/support/quotaio_v2.c +index 38be2a34ffae..739066761022 100644 +--- a/lib/support/quotaio_v2.c ++++ b/lib/support/quotaio_v2.c +@@ -175,6 +175,8 @@ static int v2_check_file(struct quota_handle *h, int type, int fmt) + static int v2_init_io(struct quota_handle *h) + { + struct v2_disk_dqinfo ddqinfo; ++ struct v2_mem_dqinfo *info; ++ __u64 filesize; + + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = + sizeof(struct v2r1_disk_dqblk); +@@ -185,6 +187,32 @@ static int v2_init_io(struct quota_handle *h) + sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + v2_disk2memdqinfo(&h->qh_info, &ddqinfo); ++ ++ /* Check to make sure quota file info is sane */ ++ info = &h->qh_info.u.v2_mdqi; ++ if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &filesize)) ++ return -1; ++ if ((filesize > (1U << 31)) || ++ (info->dqi_qtree.dqi_blocks > ++ (filesize + QT_BLKSIZE - 1) >> QT_BLKSIZE_BITS)) { ++ log_err("Quota inode %u corrupted: file size %llu; " ++ "dqi_blocks %u", h->qh_qf.ino, ++ filesize, info->dqi_qtree.dqi_blocks); ++ return -1; ++ } ++ if (info->dqi_qtree.dqi_free_blk >= info->dqi_qtree.dqi_blocks) { ++ log_err("Quota inode %u corrupted: free_blk %u; dqi_blocks %u", ++ h->qh_qf.ino, info->dqi_qtree.dqi_free_blk, ++ info->dqi_qtree.dqi_blocks); ++ return -1; ++ } ++ if (info->dqi_qtree.dqi_free_entry >= info->dqi_qtree.dqi_blocks) { ++ log_err("Quota inode %u corrupted: free_entry %u; " ++ "dqi_blocks %u", h->qh_qf.ino, ++ info->dqi_qtree.dqi_free_entry, ++ info->dqi_qtree.dqi_blocks); ++ return -1; ++ } + return 0; + } + +-- +2.16.4 +