Ignore:
Timestamp:
02/15/09 18:36:20 (15 years ago)
Author:
tim
Message:

decoupled value parsing from key parsing

moved linking of value records and data records up to the load layer

rewrote key/value/data linking algorithm in reglookup-recover which improved recovery results

fixed a NULL pointer dereference in range_list.c

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/reglookup-recover.c

    r143 r145  
    416416
    417417
     418int extractVKs(REGFI_FILE* f,
     419               range_list* unalloc_cells,
     420               range_list* unalloc_values)
     421{
     422  const range_list_element* cur_elem;
     423  REGFI_VK_REC* vk;
     424  uint32 i, j;
     425
     426  for(i=0; i < range_list_size(unalloc_cells); i++)
     427  {
     428    printMsgs(f);
     429    cur_elem = range_list_get(unalloc_cells, i);
     430    for(j=0; j <= cur_elem->length; j+=8)
     431    {
     432      vk = regfi_parse_vk(f, cur_elem->offset+j,
     433                           cur_elem->length-j, false);
     434      printMsgs(f);
     435
     436      if(vk != NULL)
     437      {
     438        if(!range_list_add(unalloc_values, vk->offset,
     439                           vk->cell_size, vk))
     440        {
     441          fprintf(stderr, "ERROR: Couldn't add value to unalloc_values.\n");
     442          return 20;
     443        }
     444        j+=vk->cell_size-8;
     445      }
     446    }
     447  }
     448
     449  /* Remove value ranges from the unalloc_cells before we continue. */
     450  for(i=0; i<range_list_size(unalloc_values); i++)
     451  {
     452    cur_elem = range_list_get(unalloc_values, i);
     453    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
     454      return 30;
     455  }
     456
     457  return 0;
     458}
     459
     460
     461int extractDataCells(REGFI_FILE* f,
     462                     range_list* unalloc_cells,
     463                     range_list* unalloc_values)
     464{
     465  const range_list_element* cur_elem;
     466  REGFI_VK_REC* vk;
     467  REGFI_HBIN* hbin;
     468  uint32 i, off, data_offset, data_maxsize;
     469
     470  for(i=0; i<range_list_size(unalloc_values); i++)
     471  {
     472    cur_elem = range_list_get(unalloc_values, i);
     473    vk = (REGFI_VK_REC*)cur_elem->data;
     474    if(vk == NULL)
     475      return 40;
     476
     477    if(vk->data_size == 0)
     478      vk->data = NULL;
     479    else
     480    {
     481      off = vk->data_off+REGFI_REGF_SIZE;
     482
     483      if(vk->data_in_offset)
     484      {
     485        vk->data = regfi_parse_data(f, vk->type, vk->data_off,
     486                                    vk->data_size, 4,
     487                                    vk->data_in_offset, false);
     488      }
     489      else if(range_list_has_range(unalloc_cells, off, vk->data_size))
     490      {
     491        hbin = regfi_lookup_hbin(f, vk->data_off);
     492        if(hbin)
     493        {
     494          data_offset = vk->data_off+REGFI_REGF_SIZE;
     495          data_maxsize = hbin->block_size + hbin->file_off - data_offset;
     496          vk->data = regfi_parse_data(f, vk->type, data_offset,
     497                                      vk->data_size, data_maxsize,
     498                                      vk->data_in_offset, false);
     499          if(vk->data != NULL)
     500          {
     501            /* XXX: This strict checking prevents partial recovery of data
     502             *      cells.  Also, see code for regfi_parse_data and note that
     503             *      lengths indicated in VK records are sometimes just plain
     504             *      wrong.  Need a feedback mechanism to be more fuzzy with
     505             *      data cell lengths and the ranges removed.
     506             */
     507            /* A data record was recovered. Remove from unalloc_cells. */
     508            if(!removeRange(unalloc_cells, off, vk->data_size))
     509              return 50;
     510          }
     511        }
     512        else
     513          vk->data = NULL;
     514      }
     515    }
     516  }
     517
     518  return 0;
     519}
     520
     521
    418522/* NOTE: unalloc_keys should be an empty range_list. */
    419523int extractKeys(REGFI_FILE* f,
     
    459563}
    460564
    461 
    462565int extractValueLists(REGFI_FILE* f,
    463566                      range_list* unalloc_cells,
    464                       range_list* unalloc_keys)
     567                      range_list* unalloc_keys,
     568                      range_list* unalloc_linked_values)
    465569{
    466570  REGFI_NK_REC* nk;
     571  REGFI_VK_REC* vk;
    467572  REGFI_HBIN* hbin;
    468573  const range_list_element* cur_elem;
     
    485590        off = nk->values_off + REGFI_REGF_SIZE;
    486591        max_length = hbin->block_size + hbin->file_off - off;
    487         /* XXX: This is a hack.  We parse all value-lists, VK records,
    488          *      and data records without regard for current allocation status. 
    489          *      On the off chance that such a record correctly parsed but is
    490          *      actually a reallocated structure used by something else, we
    491          *      simply prune it after the fact.  Would be faster to check this
    492          *      up front somehow.
    493          */
    494         nk->values = regfi_load_valuelist(f, off, nk->num_values, max_length,
    495                                           false);
    496         values_length = (nk->num_values+1)*sizeof(uint32);
    497         if(values_length != (values_length & 0xFFFFFFF8))
    498           values_length = (values_length & 0xFFFFFFF8) + 8;
    499 
    500         if(nk->values != NULL)
     592        nk->values = regfi_load_valuelist(f, off, nk->num_values,
     593                                          max_length, false);
     594        if(nk->values != NULL && nk->values->elements != NULL)
    501595        {
     596          /* Number of elements in the value list may be shorter than advertised
     597           * by NK record due to cell truncation.  We'll consider this valid and
     598           * only throw out the whole value list if it bleeds into an already
     599           * parsed structure.
     600           */
     601          values_length = (nk->values->num_values+1)*sizeof(uint32);
     602          if(values_length != (values_length & 0xFFFFFFF8))
     603            values_length = (values_length & 0xFFFFFFF8) + 8;
     604
    502605          if(!range_list_has_range(unalloc_cells, off, values_length))
    503606          { /* We've parsed a values-list which isn't in the unallocated list,
    504              * so prune it. 
     607             * so prune it.
    505608             */
    506             for(j=0; j<nk->num_values; j++)
    507             {
    508               if(nk->values[j] != NULL)
    509               {
    510                 if(nk->values[j]->data != NULL)
    511                   free(nk->values[j]->data);
    512                 free(nk->values[j]);
    513               }
    514             }
     609            free(nk->values->elements);
    515610            free(nk->values);
    516611            nk->values = NULL;
     
    523618              return 20;
    524619
    525             for(j=0; j < nk->num_values; j++)
     620            for(j=0; j < nk->values->num_values; j++)
    526621            {
    527               if(nk->values[j] != NULL)
     622              /* Don't bother to restrict cell length here, since we'll
     623               * check our unalloc_cells range_list later.
     624               */
     625              vk = regfi_parse_vk(f, nk->values->elements[j]+REGFI_REGF_SIZE,
     626                                  0x7FFFFFFF, false);
     627              printMsgs(f);
     628             
     629              if(vk != NULL)
    528630              {
    529                 if(!range_list_has_range(unalloc_cells, nk->values[j]->offset,
    530                                          nk->values[j]->cell_size))
    531                 { /* We've parsed a value which isn't in the unallocated list,
    532                    * so prune it.
    533                    */
    534                   if(nk->values[j]->data != NULL)
    535                     free(nk->values[j]->data);
    536                   free(nk->values[j]);
    537                   nk->values[j] = NULL;
     631                if(range_list_has_range(unalloc_cells,
     632                                        vk->offset, vk->cell_size))
     633                {
     634                  if(!range_list_add(unalloc_linked_values, vk->offset,
     635                                     vk->cell_size, vk))
     636                  {
     637                    free(vk);
     638                    return 30;
     639                  }
     640
     641                  if(!removeRange(unalloc_cells, vk->offset, vk->cell_size))
     642                    return 40;
    538643                }
    539644                else
    540                 {
    541                   /* A VK record was recovered.  Remove from unalloc_cells
    542                    * and inspect data.
    543                    */
    544                   if(!removeRange(unalloc_cells, nk->values[j]->offset,
    545                                   nk->values[j]->cell_size))
    546                     return 21;
    547 
    548                   /* Don't bother pruning or removing from unalloc_cells if
    549                    * there is no data, or it is stored in the offset.
    550                    */
    551                   if(nk->values[j]->data != NULL && !nk->values[j]->data_in_offset)
    552                   {
    553                     off = nk->values[j]->data_off+REGFI_REGF_SIZE;
    554                     if(!range_list_has_range(unalloc_cells, off,
    555                                              nk->values[j]->data_size))
    556                     { /* We've parsed a data cell which isn't in the unallocated
    557                        * list, so prune it.
    558                        */
    559                       free(nk->values[j]->data);
    560                       nk->values[j]->data = NULL;
    561                     }
    562                     else
    563                     { /*A data record was recovered. Remove from unalloc_cells.*/
    564                       if(!removeRange(unalloc_cells, off,
    565                                       nk->values[j]->data_size))
    566                         return 22;
    567                     }
    568                   }
    569                 }
     645                  free(vk);
    570646              }
    571647            }
     
    579655}
    580656
    581 
    582 /* NOTE: unalloc_values should be an empty range_list. */
    583 int extractValues(REGFI_FILE* f,
    584                   range_list* unalloc_cells,
    585                   range_list* unalloc_values)
    586 {
    587   const range_list_element* cur_elem;
    588   REGFI_VK_REC* vk;
    589   uint32 i, j, off;
    590 
    591   for(i=0; i < range_list_size(unalloc_cells); i++)
    592   {
    593     printMsgs(f);
    594     cur_elem = range_list_get(unalloc_cells, i);
    595     for(j=0; j <= cur_elem->length; j+=8)
    596     {
    597       vk = regfi_parse_vk(f, cur_elem->offset+j,
    598                            cur_elem->length-j, false);
    599       printMsgs(f);
    600 
    601       if(vk != NULL)
    602       {
    603         if(!range_list_add(unalloc_values, vk->offset,
    604                            vk->cell_size, vk))
    605         {
    606           fprintf(stderr, "ERROR: Couldn't add value to unalloc_values.\n");
    607           return 20;
    608         }
    609         j+=vk->cell_size-8;
    610       }
    611     }
    612   }
    613  
    614   /* Remove value ranges from the unalloc_cells before we continue. */
    615   for(i=0; i<range_list_size(unalloc_values); i++)
    616   {
    617     cur_elem = range_list_get(unalloc_values, i);
    618     if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
    619       return 30;
    620   }
    621 
    622   /* Now see if the data associated with each value is intact */
    623   for(i=0; i<range_list_size(unalloc_values); i++)
    624   {
    625     cur_elem = range_list_get(unalloc_values, i);
    626     vk = (REGFI_VK_REC*)cur_elem->data;
    627     if(vk == NULL)
    628       return 40;
    629 
    630     if(vk->data != NULL && !vk->data_in_offset)
    631     {
    632       off = vk->data_off+REGFI_REGF_SIZE;
    633       if(!range_list_has_range(unalloc_cells, off, vk->data_size))
    634       { /* We've parsed a data cell which isn't in the unallocated
    635          * list, so prune it.
    636          */
    637         free(vk->data);
    638         vk->data = NULL;
    639       }
    640       else
    641       { /*A data record was recovered. Remove from unalloc_cells.*/
    642         if(!removeRange(unalloc_cells, off, vk->data_size))
    643           return 50;
    644       }
    645     }
    646   }
    647 
    648   return 0;
    649 }
    650657
    651658
     
    699706  range_list* unalloc_cells;
    700707  range_list* unalloc_keys;
     708  range_list* unalloc_linked_values;
    701709  range_list* unalloc_values;
    702710  range_list* unalloc_sks;
     
    707715  REGFI_VK_REC* tmp_value;
    708716  uint32 argi, arge, i, j, ret, num_unalloc_keys;
    709   /* uint32 test_offset;*/
    710717 
    711718  /* Process command line arguments */
     
    772779    return 10;
    773780
     781  unalloc_linked_values = range_list_new();
     782  if(unalloc_linked_values == NULL)
     783    return 10;
     784
    774785  unalloc_values = range_list_new();
    775786  if(unalloc_values == NULL)
     
    787798  }
    788799
    789   ret = extractValueLists(f, unalloc_cells, unalloc_keys);
     800  ret = extractValueLists(f, unalloc_cells, unalloc_keys,unalloc_linked_values);
    790801  if(ret != 0)
    791802  {
     
    794805  }
    795806
    796   /* Carve any orphan values and associated data */
    797   ret = extractValues(f, unalloc_cells, unalloc_values);
     807  /* Carve any orphan values */
     808  ret = extractVKs(f, unalloc_cells, unalloc_values);
    798809  if(ret != 0)
    799810  {
    800     fprintf(stderr, "ERROR: extractValues() failed with %d.\n", ret);
     811    fprintf(stderr, "ERROR: extractVKs() failed with %d.\n", ret);
    801812    return ret;
    802813  }
    803814
     815  /* Carve any data associated with VK records */
     816  ret = extractDataCells(f, unalloc_cells, unalloc_linked_values);
     817  if(ret != 0)
     818  {
     819    fprintf(stderr, "ERROR: extractDataCells() failed with %d.\n", ret);
     820    return ret;
     821  }
     822  ret = extractDataCells(f, unalloc_cells, unalloc_values);
     823  if(ret != 0)
     824  {
     825    fprintf(stderr, "ERROR: extractDataCells() failed with %d.\n", ret);
     826    return ret;
     827  }
     828 
    804829  /* Carve any SK records */
    805830  ret = extractSKs(f, unalloc_cells, unalloc_sks);
     
    832857 
    833858  /* Now start the output */
    834 
    835859  for(i=0; i < num_unalloc_keys; i++)
    836860  {
     
    850874
    851875      sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
    852       for(j=0; j < tmp_key->num_values; j++)
     876      for(j=0; j < tmp_key->values->num_values; j++)
    853877      {
    854         tmp_value = tmp_key->values[j];
     878        tmp_value =
     879          (REGFI_VK_REC*)range_list_find_data(unalloc_linked_values,
     880                                              tmp_key->values->elements[j]
     881                                              + REGFI_REGF_SIZE);
    855882        if(tmp_value != NULL)
    856883          printValue(f, tmp_value, tmp_path);
Note: See TracChangeset for help on using the changeset viewer.