You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2014/09/07 00:38:27 UTC
svn commit: r1622959 - /subversion/trunk/subversion/libsvn_fs_fs/index.c
Author: stefan2
Date: Sat Sep 6 22:38:26 2014
New Revision: 1622959
URL: http://svn.apache.org/r1622959
Log:
Harden FSFS f7 index reader against corruption. The idea is to compare
header information to rev / pack file sizes etc. and error out when
they don't match. This e.g. prevents OOM due to corrupt table sizes.
* subversion/libsvn_fs_fs/index.c
(get_l2p_header_body,
get_p2l_header): Add lots of data checking code.
Modified:
subversion/trunk/subversion/libsvn_fs_fs/index.c
Modified: subversion/trunk/subversion/libsvn_fs_fs/index.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/index.c?rev=1622959&r1=1622958&r2=1622959&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/index.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/index.c Sat Sep 6 22:38:26 2014
@@ -766,17 +766,37 @@ get_l2p_header_body(l2p_header_t **heade
SVN_ERR(auto_open_l2p_index(rev_file, fs, revision));
packed_stream_seek(rev_file->l2p_stream, 0);
- /* read the table sizes */
+ /* Read the table sizes. Check the data for plausibility and
+ * consistency with other bits. */
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
result->first_revision = (svn_revnum_t)value;
+ if (result->first_revision != rev_file->start_revision)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Index rev / pack file revision numbers do not match"));
+
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
result->page_size = (apr_uint32_t)value;
+ if (!result->page_size)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("L2P page size must not be 0"));
+
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
result->revision_count = (int)value;
+ if ( result->revision_count != 1
+ && result->revision_count != ffd->max_files_per_dir)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Invalid number of revisions in L2P index"));
+
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
page_count = (apr_size_t)value;
+ if (page_count < result->revision_count)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Fewer L2P index pages than revisions"));
+ if (page_count > (rev_file->p2l_offset - rev_file->l2p_offset) / 2)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("L2P index page count implausibly large"));
- if (result->first_revision > revision
+ if ( result->first_revision > revision
|| result->first_revision + result->revision_count <= revision)
return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
_("Corrupt L2P index for r%ld only covers r%ld:%ld"),
@@ -797,16 +817,36 @@ get_l2p_header_body(l2p_header_t **heade
for (i = 0; i < result->revision_count; ++i)
{
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+ if (value == 0)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Revision with no L2P index pages"));
+
page_table_index += (apr_size_t)value;
+ if (page_table_index > page_count)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("L2P page table exceeded"));
+
result->page_table_index[i+1] = page_table_index;
}
+ if (page_table_index != page_count)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Revisions do not cover the full L2P index page table"));
+
/* read actual page tables */
for (page = 0; page < page_count; ++page)
{
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+ if (value == 0)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Empty L2P index page"));
+
result->page_table[page].size = (apr_uint32_t)value;
SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+ if (value > result->page_size)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Page exceeds L2P index page size"));
+
result->page_table[page].entry_count = (apr_uint32_t)value;
}
@@ -1818,15 +1858,31 @@ get_p2l_header(p2l_header_t **header,
/* allocate result data structure */
result = apr_pcalloc(pool, sizeof(*result));
- /* read table sizes and allocate page array */
+ /* Read table sizes, check them for plausibility and allocate page array. */
SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
result->first_revision = (svn_revnum_t)value;
+ if (result->first_revision != rev_file->start_revision)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Index rev / pack file revision numbers do not match"));
+
SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
result->file_size = value;
+ if (result->file_size != rev_file->l2p_offset)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("Index offset and rev / pack file size do not match"));
+
SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
result->page_size = value;
+ if (!result->page_size || (result->page_size & (result->page_size - 1)))
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("P2L index page size is not a power of two"));
+
SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
result->page_count = (apr_size_t)value;
+ if (result->page_count != (result->file_size - 1) / result->page_size + 1)
+ return svn_error_create(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+ _("P2L page count does not match rev / pack file size"));
+
result->offsets
= apr_pcalloc(pool, (result->page_count + 1) * sizeof(*result->offsets));