[Libguestfs] [PATCH] Add read support for "big data" blocks to hivex

Richard W.M. Jones rjones at redhat.com
Tue Jun 25 16:48:50 UTC 2013


On Sun, Jun 23, 2013 at 08:52:05PM +0200, Hilko Bengen wrote:
> ---
>  lib/hivex.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 66 insertions(+), 15 deletions(-)
> 
> diff --git a/lib/hivex.c b/lib/hivex.c
> index efc27f8..e3c1e05 100644
> --- a/lib/hivex.c
> +++ b/lib/hivex.c
> @@ -208,6 +208,19 @@ struct ntreg_sk_record {
>    char sec_desc[1];             /* security info follows */
>  } __attribute__((__packed__));
>  
> +struct ntreg_db_record {
> +  int32_t seg_len;              /* length (always -ve because used) */
> +  char id[2];                   /* "db" */
> +  uint16_t nr_blocks;
> +  uint32_t blocklist_offset;
> +  uint32_t unknown1;
> +} __attribute__((__packed__));
> +
> +struct ntreg_db_block {
> +  int32_t seg_len;
> +  char data[1];
> +} __attribute__((__packed__));
> +
>  static uint32_t
>  header_checksum (const hive_h *h)
>  {
> @@ -1418,22 +1431,60 @@ hivex_value_value (hive_h *h, hive_value_h value,
>     * instead.
>     */
>    size_t blen = block_len (h, data_offset, NULL);
> -  if (len > blen - 4 /* subtract 4 for block header */) {
> -    if (h->msglvl >= 2)
> -      fprintf (stderr, "hivex_value_value: warning: declared data length "
> -               "is longer than the block it is in "
> -               "(data 0x%zx, data len %zu, block len %zu)\n",
> -               data_offset, len, blen);
> -    len = blen - 4;
> -
> -    /* Return the smaller length to the caller too. */
> -    if (len_rtn)
> -      *len_rtn = len;
> +  if (len <= blen - 4 /* subtract 4 for block header */) {
> +    char *data = (char *) h->addr + data_offset + 4;
> +    memcpy (ret, data, len);
> +    return ret;
> +  } else {
> +    if (!IS_VALID_BLOCK (h, data_offset) || !BLOCK_ID_EQ (h, data_offset, "db")) {
> +      if (h->msglvl >= 2)
> +        fprintf (stderr, "hivex_value_value: warning: declared data length "
> +                 "is longer than the amount of data found in big-data blocks "
> +                 "(data 0x%zx, data len %zu)\n",
> +                 data_offset, len);
> +      errno = EINVAL;
> +      free (ret);
> +      return NULL;
> +    }
> +    struct ntreg_db_record *db =
> +      (struct ntreg_db_record *) ((char *) h->addr + data_offset);
> +    size_t blocklist_offset = le32toh (db->blocklist_offset);
> +    blocklist_offset += 0x1000;
> +    size_t nr_blocks = le16toh (db->nr_blocks);
> +    if (!IS_VALID_BLOCK (h, blocklist_offset)) {
> +      if (h->msglvl >= 2)
> +        fprintf (stderr, "hivex_value_value: warning: blocklist is not a "
> +                 "valid block "
> +                 "(db block 0x%zx, blocklist 0x%zx)\n",
> +                 data_offset, blocklist_offset);
> +      errno = EINVAL;
> +      free (ret);
> +      return NULL;
> +    }
> +    struct ntreg_value_list *bl =
> +      (struct ntreg_value_list *) ((char *) h->addr + blocklist_offset);
> +    size_t i, off;
> +    for (i=off=0; i < nr_blocks; ++i) {
> +      uint32_t subblock_offset = le32toh (bl->offset[i]);
> +      subblock_offset += 0x1000;
> +      if (!IS_VALID_BLOCK (h, subblock_offset)) {
> +        if (h->msglvl >= 2)
> +          fprintf (stderr, "hivex_value_value: warning: big data block is not "
> +                   "valid (db block 0x%zx, block list 0x%zx, data block 0x%zx)\n",
> +                   data_offset, blocklist_offset, subblock_offset);
> +      }
> +      int32_t seg_len = block_len(h, subblock_offset, NULL);
> +      struct ntreg_db_block *subblock =
> +        (struct ntreg_db_block *) ((char *) h->addr + subblock_offset);
> +      int32_t sz = seg_len - 8; /* don't copy the last 4 bytes */
> +      if (off + sz > len) {
> +        sz = len - off;
> +      }
> +      memcpy (ret + off, subblock->data, sz);
> +      off += sz;
> +    }
> +    return ret;
>    }
> -
> -  char *data = (char *) h->addr + data_offset + 4;
> -  memcpy (ret, data, len);
> -  return ret;
>  }
>  
>  static char *
> -- 
> 1.8.3.1

You need to add something like this:

diff --git a/lib/hivex.c b/lib/hivex.c
index e3c1e05..9351ac5 100644
--- a/lib/hivex.c
+++ b/lib/hivex.c
@@ -1471,7 +1471,7 @@ hivex_value_value (hive_h *h, hive_value_h value,
         if (h->msglvl >= 2)
           fprintf (stderr, "hivex_value_value: warning: big data block is not "
                    "valid (db block 0x%zx, block list 0x%zx, data block 0x%zx)\
-                   data_offset, blocklist_offset, subblock_offset);
+                   data_offset, blocklist_offset, (size_t) subblock_offset);
       }
       int32_t seg_len = block_len(h, subblock_offset, NULL);
       struct ntreg_db_block *subblock =

to make it compile without warnings.

With that addition, * ACK *.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines.  Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v




More information about the Libguestfs mailing list