Example #1
0
/* Callback from hivex_node_delete_child which is called to delete a
 * node AFTER its subnodes have been visited.  The subnodes have been
 * deleted but we still have to delete any lf/lh/li/ri records and the
 * value list block and values, followed by deleting the node itself.
 */
static int
delete_node (hive_h *h, void *opaque, hive_node_h node, const char *name)
{
  /* Get the intermediate blocks.  The subkeys have already been
   * deleted by this point, so tell get_children() not to check for
   * validity of the nk-records.
   */
  hive_node_h *unused;
  size_t *blocks;
  if (_hivex_get_children (h, node,
                           &unused, &blocks, GET_CHILDREN_NO_CHECK_NK) == -1)
    return -1;
  free (unused);

  /* We don't care what's in these intermediate blocks, so we can just
   * delete them unconditionally.
   */
  size_t i;
  for (i = 0; blocks[i] != 0; ++i)
    mark_block_unused (h, blocks[i]);

  free (blocks);

  /* Delete the values in the node. */
  if (delete_values (h, node) == -1)
    return -1;

  struct ntreg_nk_record *nk =
    (struct ntreg_nk_record *) ((char *) h->addr + node);

  /* If the NK references an SK, delete it. */
  size_t sk_offs = le32toh (nk->sk);
  if (sk_offs != 0xffffffff) {
    sk_offs += 0x1000;
    if (delete_sk (h, sk_offs) == -1)
      return -1;
    nk->sk = htole32 (0xffffffff);
  }

  /* If the NK references a classname, delete it. */
  size_t cl_offs = le32toh (nk->classname);
  if (cl_offs != 0xffffffff) {
    cl_offs += 0x1000;
    mark_block_unused (h, cl_offs);
    nk->classname = htole32 (0xffffffff);
  }

  /* Delete the node itself. */
  mark_block_unused (h, node);

  return 0;
}
Example #2
0
/* Insert node into existing lf/lh-record at position.
 * This allocates a new record and marks the old one as unused.
 */
static size_t
insert_lf_record (hive_h *h, size_t old_offs, size_t posn,
                  const char *name, hive_node_h node)
{
  assert (IS_VALID_BLOCK (h, old_offs));

  /* Work around C stupidity.
   * http://www.redhat.com/archives/libguestfs/2010-February/msg00056.html
   */
  int test = block_id_eq (h, old_offs, "lf") || block_id_eq (h, old_offs, "lh");
  assert (test);

  struct ntreg_lf_record *old_lf =
    (struct ntreg_lf_record *) ((char *) h->addr + old_offs);
  size_t nr_keys = le16toh (old_lf->nr_keys);

  if (nr_keys == UINT16_MAX) {
    SET_ERRNO (EOVERFLOW,
               "cannot extend record because it already contains the maximum number of subkeys (%zu)",
               nr_keys);
    return 0;
  }
  nr_keys++; /* in new record ... */

  size_t seg_len = sizeof (struct ntreg_lf_record) + (nr_keys-1) * 8;

  /* Copy the old_lf->id in case it moves during allocate_block. */
  char id[2];
  memcpy (id, old_lf->id, sizeof id);

  size_t new_offs = allocate_block (h, seg_len, id);
  if (new_offs == 0)
    return 0;

  /* old_lf could have been invalidated by allocate_block. */
  old_lf = (struct ntreg_lf_record *) ((char *) h->addr + old_offs);

  struct ntreg_lf_record *new_lf =
    (struct ntreg_lf_record *) ((char *) h->addr + new_offs);
  new_lf->nr_keys = htole16 (nr_keys);

  /* Copy the keys until we reach posn, insert the new key there, then
   * copy the remaining keys.
   */
  size_t i;
  for (i = 0; i < posn; ++i)
    new_lf->keys[i] = old_lf->keys[i];

  new_lf->keys[i].offset = htole32 (node - 0x1000);
  calc_hash (new_lf->id, name, new_lf->keys[i].hash);

  for (i = posn+1; i < nr_keys; ++i)
    new_lf->keys[i] = old_lf->keys[i-1];

  /* Old block is unused, return new block. */
  mark_block_unused (h, old_offs);
  return new_offs;
}
Example #3
0
/* Delete all existing values at this node. */
static int
delete_values (hive_h *h, hive_node_h node)
{
  assert (h->writable);

  hive_value_h *values;
  size_t *blocks;
  if (_hivex_get_values (h, node, &values, &blocks) == -1)
    return -1;

  size_t i;
  for (i = 0; blocks[i] != 0; ++i)
    mark_block_unused (h, blocks[i]);

  free (blocks);

  for (i = 0; values[i] != 0; ++i) {
    struct ntreg_vk_record *vk =
      (struct ntreg_vk_record *) ((char *) h->addr + values[i]);

    size_t len;
    int is_inline;
    len = le32toh (vk->data_len);
    is_inline = !!(len & 0x80000000); /* top bit indicates is inline */

    if (!is_inline) {           /* non-inline, so remove data block */
      size_t data_offset = le32toh (vk->data_offset);
      data_offset += 0x1000;
      mark_block_unused (h, data_offset);
    }

    /* remove vk record */
    mark_block_unused (h, values[i]);
  }

  free (values);

  struct ntreg_nk_record *nk =
    (struct ntreg_nk_record *) ((char *) h->addr + node);
  nk->nr_values = htole32 (0);
  nk->vallist = htole32 (0xffffffff);

  return 0;
}
Example #4
0
/* Insert node into existing li-record at position.  Pretty much the
 * same as insert_lf_record above, but the record layout is a bit
 * different.
 */
static size_t
insert_li_record (hive_h *h, size_t old_offs, size_t posn,
                  const char *name, hive_node_h node)
{
  assert (IS_VALID_BLOCK (h, old_offs));
  assert (block_id_eq (h, old_offs, "li"));

  struct ntreg_ri_record *old_li =
    (struct ntreg_ri_record *) ((char *) h->addr + old_offs);
  size_t nr_offsets = le16toh (old_li->nr_offsets);

  if (nr_offsets == UINT16_MAX) {
    SET_ERRNO (EOVERFLOW,
               "cannot extend record because it already contains the maximum number of subkeys (%zu)",
               nr_offsets);
    return 0;
  }
  nr_offsets++; /* in new record ... */

  size_t seg_len = sizeof (struct ntreg_ri_record) + (nr_offsets-1) * 4;

  /* Copy the old_li->id in case it moves during allocate_block. */
  char id[2];
  memcpy (id, old_li->id, sizeof id);

  size_t new_offs = allocate_block (h, seg_len, id);
  if (new_offs == 0)
    return 0;

  /* old_li could have been invalidated by allocate_block. */
  old_li = (struct ntreg_ri_record *) ((char *) h->addr + old_offs);

  struct ntreg_ri_record *new_li =
    (struct ntreg_ri_record *) ((char *) h->addr + new_offs);
  new_li->nr_offsets = htole16 (nr_offsets);

  /* Copy the offsets until we reach posn, insert the new offset
   * there, then copy the remaining offsets.
   */
  size_t i;
  for (i = 0; i < posn; ++i)
    new_li->offset[i] = old_li->offset[i];

  new_li->offset[i] = htole32 (node - 0x1000);

  for (i = posn+1; i < nr_offsets; ++i)
    new_li->offset[i] = old_li->offset[i-1];

  /* Old block is unused, return new block. */
  mark_block_unused (h, old_offs);
  return new_offs;
}
Example #5
0
	__forceinline bool stack_allocator::deallocate(void * vP){
			int* P = (int*)vP;
			if(is_block_used(P) != true){
			    perror("Deallocation failed: bad pointer\n");fflush(stdout);
			    abort();
			};
			//mark for detetion
			mark_block_unused(P);
			if(_beg+overhead == P){//this is the top block of this allocator
				//delete it
				_beg = _beg+overhead+block_size(_beg+overhead);
				if(empty() || is_block_unused(_beg+overhead)){//buffer is empty or more unused blocks
					//triger cascade deallocation
					return true;
				};
			};
			return false;
	};
Example #6
0
/* Decrement the refcount of an sk-record, and if it reaches zero,
 * unlink it from the chain and delete it.
 */
static int
delete_sk (hive_h *h, size_t sk_offset)
{
  if (!IS_VALID_BLOCK (h, sk_offset) || !block_id_eq (h, sk_offset, "sk")) {
    SET_ERRNO (EFAULT, "not an sk record: 0x%zx", sk_offset);
    return -1;
  }

  struct ntreg_sk_record *sk =
    (struct ntreg_sk_record *) ((char *) h->addr + sk_offset);

  if (sk->refcount == 0) {
    SET_ERRNO (EINVAL, "sk record already has refcount 0: 0x%zx", sk_offset);
    return -1;
  }

  sk->refcount--;

  if (sk->refcount == 0) {
    size_t sk_prev_offset = sk->sk_prev;
    sk_prev_offset += 0x1000;

    size_t sk_next_offset = sk->sk_next;
    sk_next_offset += 0x1000;

    /* Update sk_prev/sk_next SKs, unless they both point back to this
     * cell in which case we are deleting the last SK.
     */
    if (sk_prev_offset != sk_offset && sk_next_offset != sk_offset) {
      struct ntreg_sk_record *sk_prev =
        (struct ntreg_sk_record *) ((char *) h->addr + sk_prev_offset);
      struct ntreg_sk_record *sk_next =
        (struct ntreg_sk_record *) ((char *) h->addr + sk_next_offset);

      sk_prev->sk_next = htole32 (sk_next_offset - 0x1000);
      sk_next->sk_prev = htole32 (sk_prev_offset - 0x1000);
    }

    /* Refcount is zero so really delete this block. */
    mark_block_unused (h, sk_offset);
  }

  return 0;
}
Example #7
0
hive_node_h
hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name)
{
  CHECK_WRITABLE (0);

  if (!IS_VALID_BLOCK (h, parent) || !block_id_eq (h, parent, "nk")) {
    SET_ERRNO (EINVAL, "invalid block or not an 'nk' block");
    return 0;
  }

  if (name == NULL || strlen (name) == 0) {
    SET_ERRNO (EINVAL, "name is NULL or zero length");
    return 0;
  }

  if (hivex_node_get_child (h, parent, name) != 0) {
    SET_ERRNO (EEXIST, "a child with that name exists already");
    return 0;
  }

  size_t recoded_name_len;
  int use_utf16 = 0;
  char *recoded_name =
    _hivex_encode_string (h, name, &recoded_name_len, &use_utf16);
  if (recoded_name == NULL) {
    SET_ERRNO (EINVAL, "malformed name");
    return 0;
  }

  /* Create the new nk-record. */
  static const char nk_id[2] = { 'n', 'k' };
  size_t seg_len = sizeof (struct ntreg_nk_record) + recoded_name_len;
  hive_node_h nkoffset = allocate_block (h, seg_len, nk_id);
  if (nkoffset == 0) {
    free (recoded_name);
    return 0;
  }

  DEBUG (2, "allocated new nk-record for child at 0x%zx", nkoffset);

  struct ntreg_nk_record *nk =
    (struct ntreg_nk_record *) ((char *) h->addr + nkoffset);
  if (use_utf16)
    nk->flags = htole16 (0x0000);
  else
    nk->flags = htole16 (0x0020);
  nk->parent = htole32 (parent - 0x1000);
  nk->subkey_lf = htole32 (0xffffffff);
  nk->subkey_lf_volatile = htole32 (0xffffffff);
  nk->vallist = htole32 (0xffffffff);
  nk->classname = htole32 (0xffffffff);
  nk->name_len = htole16 (recoded_name_len);
  memcpy (nk->name, recoded_name, recoded_name_len);
  free (recoded_name);

  /* Inherit parent sk. */
  struct ntreg_nk_record *parent_nk =
    (struct ntreg_nk_record *) ((char *) h->addr + parent);
  size_t parent_sk_offset = le32toh (parent_nk->sk);
  parent_sk_offset += 0x1000;
  if (!IS_VALID_BLOCK (h, parent_sk_offset) ||
      !block_id_eq (h, parent_sk_offset, "sk")) {
    SET_ERRNO (EFAULT,
               "parent sk is not a valid block (%zu)", parent_sk_offset);
    return 0;
  }
  struct ntreg_sk_record *sk =
    (struct ntreg_sk_record *) ((char *) h->addr + parent_sk_offset);
  sk->refcount = htole32 (le32toh (sk->refcount) + 1);
  nk->sk = htole32 (parent_sk_offset - 0x1000);

  /* Inherit parent timestamp. */
  nk->timestamp = parent_nk->timestamp;

  /* What I found out the hard way (not documented anywhere): the
   * subkeys in lh-records must be kept sorted.  If you just add a
   * subkey in a non-sorted position (eg. just add it at the end) then
   * Windows won't see the subkey _and_ Windows will corrupt the hive
   * itself when it modifies or saves it.
   *
   * So use get_children() to get a list of intermediate records.
   * get_children() returns these in reading order (which is sorted),
   * so we look for the lf/lh/li-records in sequence until we find the
   * key name just after the one we are inserting, and we insert the
   * subkey just before it.
   *
   * The only other case is the no-subkeys case, where we have to
   * create a brand new lh-record.
   */
  hive_node_h *unused;
  size_t *blocks;

  if (_hivex_get_children (h, parent, &unused, &blocks, 0) == -1)
    return 0;
  free (unused);

  size_t i;
  size_t nr_subkeys_in_parent_nk = le32toh (parent_nk->nr_subkeys);

  if (nr_subkeys_in_parent_nk == UINT32_MAX) {
    free (blocks);
    SET_ERRNO (EOVERFLOW,
               "too many subkeys (%zu)", nr_subkeys_in_parent_nk);
    return 0;
  }

  if (nr_subkeys_in_parent_nk == 0) { /* No subkeys case. */
    /* Free up any existing intermediate blocks. */
    for (i = 0; blocks[i] != 0; ++i)
      mark_block_unused (h, blocks[i]);
    size_t lh_offs = new_lh_record (h, name, nkoffset);
    if (lh_offs == 0) {
      free (blocks);
      return 0;
    }

    /* Recalculate pointers that could have been invalidated by
     * previous call to allocate_block (via new_lh_record).
     */
    /* nk could be invalid here */
    parent_nk = (struct ntreg_nk_record *) ((char *) h->addr + parent);

    DEBUG (2, "no keys, allocated new lh-record at 0x%zx", lh_offs);

    parent_nk->subkey_lf = htole32 (lh_offs - 0x1000);
  }
  else {                        /* Insert subkeys case. */
    if (insert_subkey (h, name, parent, nkoffset, blocks) == -1) {
      free (blocks);
      return 0;
    }

    /* Recalculate pointers that could have been invalidated by
     * previous call to allocate_block (via new_lh_record).
     */
    /* nk could be invalid here */
    parent_nk = (struct ntreg_nk_record *) ((char *) h->addr + parent);
  }

  free (blocks);

  /* Update nr_subkeys in parent nk. */
  nr_subkeys_in_parent_nk++;
  parent_nk->nr_subkeys = htole32 (nr_subkeys_in_parent_nk);

  /* Update max_subkey_name_len in parent nk. */
  size_t utf16_len = use_utf16 ? recoded_name_len : recoded_name_len * 2;
  if (le16toh (parent_nk->max_subkey_name_len) < utf16_len)
    parent_nk->max_subkey_name_len = htole16 (utf16_len);

  return nkoffset;
}