subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1595579 - in /subversion/trunk/subversion/libsvn_fs_x: ./ index.c
Date Sun, 18 May 2014 09:08:09 GMT
Author: stefan2
Date: Sun May 18 09:08:09 2014
New Revision: 1595579

URL: http://svn.apache.org/r1595579
Log:
Sync'ing FSX with FSFS:
Merge r1559870,1575628,1576801 from /subversion/libsvn_fs_fs into
subversion/libsvn_fs_x.  Conflicts were due structural differences
between FSX and FSFS.

This ports index file bounds checking patches.

Modified:
    subversion/trunk/subversion/libsvn_fs_x/   (props changed)
    subversion/trunk/subversion/libsvn_fs_x/index.c

Propchange: subversion/trunk/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/libsvn_fs_fs:r1559870,1575628,1576801

Modified: subversion/trunk/subversion/libsvn_fs_x/index.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/index.c?rev=1595579&r1=1595578&r2=1595579&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/index.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/index.c Sun May 18 09:08:09 2014
@@ -71,7 +71,7 @@ typedef struct l2p_header_t
   apr_size_t revision_count;
 
   /* (max) number of entries per page */
-  apr_size_t page_size;
+  apr_uint32_t page_size;
 
   /* indexes into PAGE_TABLE that mark the first page of the respective
    * revision.  PAGE_TABLE_INDEX[REVISION_COUNT] points to the end of
@@ -706,6 +706,14 @@ svn_fs_x__l2p_index_create(svn_fs_t *fs,
   svn_spillbuf_t *buffer
     = svn_spillbuf__create(0x10000, 0x1000000, local_pool);
 
+  /* Paranoia check that makes later casting to int32 safe.
+   * The current implementation is limited to 2G entries per page. */
+  if (ffd->l2p_page_size > APR_INT32_MAX)
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                            _("L2P index page size  %" APR_UINT64_T_FMT
+                              " exceeds current limit of 2G entries"),
+                            ffd->l2p_page_size);
+
   /* start at the beginning of the source file */
   SVN_ERR(svn_io_file_open(&proto_index, proto_file_name,
                            APR_READ | APR_CREATE | APR_BUFFERED,
@@ -733,16 +741,18 @@ svn_fs_x__l2p_index_create(svn_fs_t *fs,
             {
               /* 1 page with up to 8k entries */
               apr_size_t last_buffer_size = svn_spillbuf__get_size(buffer);
-              entry_count = MIN(entries->nelts - i, ffd->l2p_page_size);
 
+              svn_pool_clear(iterpool);
+
+              entry_count = ffd->l2p_page_size < entries->nelts - i
+                          ? (int)ffd->l2p_page_size
+                          : entries->nelts - i;
               SVN_ERR(encode_l2p_page(entries, i, i + entry_count,
                                       buffer, iterpool));
 
               APR_ARRAY_PUSH(entry_counts, apr_uint64_t) = entry_count;
               APR_ARRAY_PUSH(page_sizes, apr_uint64_t)
                 = svn_spillbuf__get_size(buffer) - last_buffer_size;
-
-              svn_pool_clear(iterpool);
             }
 
           apr_array_clear(entries);
@@ -755,10 +765,20 @@ svn_fs_x__l2p_index_create(svn_fs_t *fs,
         }
       else
         {
+          int idx;
+
           /* store the mapping in our array */
           l2p_page_entry_t page_entry = { 0 };
-          int idx = (apr_size_t)proto_entry.item_index;
-          
+
+          if (proto_entry.item_index > APR_INT32_MAX)
+            return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                                    _("Item index %" APR_UINT64_T_FMT
+                                      " too large in l2p proto index for"
+                                      " revision %ld"),
+                                    proto_entry.item_index,
+                                    revision + page_counts->nelts);
+
+          idx = (int)proto_entry.item_index;
           while (idx >= entries->nelts)
             APR_ARRAY_PUSH(entries, l2p_page_entry_t) = page_entry;
 
@@ -774,6 +794,14 @@ svn_fs_x__l2p_index_create(svn_fs_t *fs,
   /* create the target file */
   SVN_ERR(index_create(&index_file, file_name, local_pool));
 
+  /* Paranoia check that makes later casting to int32 safe.
+   * The current implementation is limited to 2G pages per index. */
+  if (page_counts->nelts > APR_INT32_MAX)
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                            _("L2P index page count  %d"
+                              " exceeds current limit of 2G pages"),
+                            page_counts->nelts);
+
   /* write header info */
   SVN_ERR(svn_io_file_write_full(index_file, encoded,
                                  encode_uint(encoded, revision),
@@ -852,7 +880,7 @@ typedef struct l2p_page_info_baton_t
   l2p_page_table_entry_t entry;
 
   /* page number within the pages for REVISION (not l2p index global!) */
-  apr_size_t page_no;
+  apr_uint32_t page_no;
 
   /* offset of ITEM_INDEX within that page */
   apr_uint32_t page_offset;
@@ -883,7 +911,7 @@ l2p_header_copy(l2p_page_info_baton_t *b
   if (baton->item_index < header->page_size)
     {
       /* most revs fit well into a single page */
-      baton->page_offset = (apr_size_t)baton->item_index;
+      baton->page_offset = (apr_uint32_t)baton->item_index;
       baton->page_no = 0;
       baton->entry = page_table[page_table_index[rel_revision]];
     }
@@ -891,29 +919,29 @@ l2p_header_copy(l2p_page_info_baton_t *b
     {
       const l2p_page_table_entry_t *first_entry;
       const l2p_page_table_entry_t *last_entry;
-      
-      /* all pages are of the same size and full, except for the last one */
-      baton->page_offset = (apr_size_t)(baton->item_index % header->page_size);
-      baton->page_no = (apr_uint32_t)(baton->item_index / header->page_size);
+      apr_uint64_t max_item_index;
 
       /* range of pages for this rev */
       first_entry = page_table + page_table_index[rel_revision];
       last_entry = page_table + page_table_index[rel_revision + 1];
 
-      if (last_entry - first_entry > baton->page_no)
-        {
-          baton->entry = first_entry[baton->page_no];
-        }
-      else
-        {
-          /* limit page index to the valid range */
-          baton->entry = last_entry[-1];
+      /* do we hit a valid index page? */
+      max_item_index =   (apr_uint64_t)header->page_size
+                       * (last_entry - first_entry);
+      if (baton->item_index >= max_item_index)
+        return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                                _("Item index %" APR_UINT64_T_FMT
+                                  " exceeds l2p limit of %" APR_UINT64_T_FMT
+                                  " for revision %ld"),
+                                baton->item_index, max_item_index,
+                                baton->revision);
 
-          /* cause index overflow further down the road */
-          baton->page_offset = header->page_size + 1;
-        }
+      /* all pages are of the same size and full, except for the last one */
+      baton->page_offset = (apr_uint32_t)(baton->item_index % header->page_size);
+      baton->page_no = (apr_uint32_t)(baton->item_index / header->page_size);
+      baton->entry = first_entry[baton->page_no];
     }
-    
+
   baton->first_revision = header->first_revision;
 
   return SVN_NO_ERROR;
@@ -1019,10 +1047,17 @@ get_l2p_header_body(l2p_header_t **heade
   SVN_ERR(packed_stream_get(&value, *stream));
   result->revision_count = (int)value;
   SVN_ERR(packed_stream_get(&value, *stream));
-  result->page_size = (apr_size_t)value;
+  result->page_size = (apr_uint32_t)value;
   SVN_ERR(packed_stream_get(&value, *stream));
   page_count = (apr_size_t)value;
 
+  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"),
+                      revision, result->first_revision,
+                      result->first_revision + result->revision_count);
+
   /* allocate the page tables */
   result->page_table
     = apr_pcalloc(pool, page_count * sizeof(*result->page_table));



Mime
View raw message