diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c index 0b9e766..ddb5312 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 a7c2028..6cc4fb5 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 38be2a3..7390667 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; }