mirror of
https://github.com/kdave/btrfs-progs
synced 2024-12-26 16:12:34 +00:00
libbtrfsutil: use safe access to potentially unaligned data
There's a lot of places with unsafe access to data that come from a search buffer, which is packed and the structures there are not guaranteed to be aligned, also accessing the on-disk format structures. - search header - this is an in-memory buffer with a series of on-disk structures, no alignment must be assumed - anything that's not a byte buffer must be accessed as an unaligned buffer (the exceptions are name-like buffers) Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
9a01491042
commit
94e058d8b2
@ -220,12 +220,12 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_path_fd(int fd, uint64_t id,
|
||||
header = (struct btrfs_ioctl_search_header *)search.buf;
|
||||
ref = (struct btrfs_root_ref *)(header + 1);
|
||||
name = (char *)(ref + 1);
|
||||
name_len = le16_to_cpu(ref->name_len);
|
||||
name_len = get_unaligned_le16(&ref->name_len);
|
||||
|
||||
id = header->offset;
|
||||
id = btrfs_search_header_offset(header);
|
||||
|
||||
lookup.treeid = id;
|
||||
lookup.objectid = le64_to_cpu(ref->dirid);
|
||||
lookup.objectid = get_unaligned_le64(&ref->dirid);
|
||||
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &lookup);
|
||||
if (ret == -1) {
|
||||
free(path);
|
||||
@ -268,27 +268,27 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_path_fd(int fd, uint64_t id,
|
||||
PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_path_fd(int fd, uint64_t id, char **path_ret)
|
||||
LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_path_fd);
|
||||
|
||||
/* The @timespec could be from a raw buffer, do not assume any alignment. */
|
||||
static void copy_timespec(struct timespec *timespec,
|
||||
const struct btrfs_timespec *btrfs_timespec)
|
||||
{
|
||||
timespec->tv_sec = le64_to_cpu(btrfs_timespec->sec);
|
||||
timespec->tv_nsec = le32_to_cpu(btrfs_timespec->nsec);
|
||||
timespec->tv_sec = get_unaligned_le64(&btrfs_timespec->sec);
|
||||
timespec->tv_nsec = get_unaligned_le32(&btrfs_timespec->nsec);
|
||||
}
|
||||
|
||||
/* The @root could be from a raw search buffer, do not assume any alignment. */
|
||||
static void copy_root_item(struct btrfs_util_subvolume_info *subvol,
|
||||
const struct btrfs_root_item *root)
|
||||
{
|
||||
subvol->flags = le64_to_cpu(root->flags);
|
||||
subvol->flags = get_unaligned_le64(&root->flags);
|
||||
memcpy(subvol->uuid, root->uuid, sizeof(subvol->uuid));
|
||||
memcpy(subvol->parent_uuid, root->parent_uuid,
|
||||
sizeof(subvol->parent_uuid));
|
||||
memcpy(subvol->received_uuid, root->received_uuid,
|
||||
sizeof(subvol->received_uuid));
|
||||
subvol->generation = le64_to_cpu(root->generation);
|
||||
subvol->ctransid = le64_to_cpu(root->ctransid);
|
||||
subvol->otransid = le64_to_cpu(root->otransid);
|
||||
subvol->stransid = le64_to_cpu(root->stransid);
|
||||
subvol->rtransid = le64_to_cpu(root->rtransid);
|
||||
memcpy(subvol->parent_uuid, root->parent_uuid, sizeof(subvol->parent_uuid));
|
||||
memcpy(subvol->received_uuid, root->received_uuid, sizeof(subvol->received_uuid));
|
||||
subvol->generation = get_unaligned_le64(&root->generation);
|
||||
subvol->ctransid = get_unaligned_le64(&root->ctransid);
|
||||
subvol->otransid = get_unaligned_le64(&root->otransid);
|
||||
subvol->stransid = get_unaligned_le64(&root->stransid);
|
||||
subvol->rtransid = get_unaligned_le64(&root->rtransid);
|
||||
copy_timespec(&subvol->ctime, &root->ctime);
|
||||
copy_timespec(&subvol->otime, &root->otime);
|
||||
copy_timespec(&subvol->stime, &root->stime);
|
||||
@ -389,7 +389,7 @@ static enum btrfs_util_error get_subvolume_info_privileged(int fd, uint64_t id,
|
||||
|
||||
ref = (const struct btrfs_root_ref *)(header + 1);
|
||||
subvol->parent_id = btrfs_search_header_offset(header);
|
||||
subvol->dir_id = le64_to_cpu(ref->dirid);
|
||||
subvol->dir_id = get_unaligned_le64(&ref->dirid);
|
||||
}
|
||||
need_root_backref = false;
|
||||
search.key.min_type = UINT32_MAX;
|
||||
@ -600,23 +600,23 @@ PUBLIC enum btrfs_util_error btrfs_util_get_default_subvolume_fd(int fd,
|
||||
}
|
||||
|
||||
header = (struct btrfs_ioctl_search_header *)(search.buf + buf_off);
|
||||
if (header->type == BTRFS_DIR_ITEM_KEY) {
|
||||
if (btrfs_search_header_type(header) == BTRFS_DIR_ITEM_KEY) {
|
||||
const struct btrfs_dir_item *dir;
|
||||
const char *name;
|
||||
uint16_t name_len;
|
||||
|
||||
dir = (struct btrfs_dir_item *)(header + 1);
|
||||
name = (const char *)(dir + 1);
|
||||
name_len = le16_to_cpu(dir->name_len);
|
||||
name_len = get_unaligned_le16(&dir->name_len);
|
||||
if (strncmp(name, "default", name_len) == 0) {
|
||||
*id_ret = le64_to_cpu(dir->location.objectid);
|
||||
*id_ret = get_unaligned_le64(&dir->location.objectid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
items_pos++;
|
||||
buf_off += sizeof(*header) + header->len;
|
||||
search.key.min_offset = header->offset + 1;
|
||||
buf_off += sizeof(*header) + btrfs_search_header_len(header);
|
||||
search.key.min_offset = btrfs_search_header_offset(header) + 1;
|
||||
}
|
||||
|
||||
return BTRFS_UTIL_OK;
|
||||
@ -1442,6 +1442,9 @@ static enum btrfs_util_error build_subvol_path(struct btrfs_util_subvolume_itera
|
||||
return BTRFS_UTIL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The @ref could be from raw search buffer, do not assume any alignment
|
||||
*/
|
||||
static enum btrfs_util_error build_subvol_path_privileged(struct btrfs_util_subvolume_iterator *iter,
|
||||
const struct btrfs_ioctl_search_header *header,
|
||||
const struct btrfs_root_ref *ref,
|
||||
@ -1450,7 +1453,7 @@ static enum btrfs_util_error build_subvol_path_privileged(struct btrfs_util_subv
|
||||
{
|
||||
struct btrfs_ioctl_ino_lookup_args lookup = {
|
||||
.treeid = btrfs_search_header_objectid(header),
|
||||
.objectid = le64_to_cpu(ref->dirid),
|
||||
.objectid = get_unaligned_le64(&ref->dirid),
|
||||
};
|
||||
int ret;
|
||||
|
||||
@ -1458,7 +1461,7 @@ static enum btrfs_util_error build_subvol_path_privileged(struct btrfs_util_subv
|
||||
if (ret == -1)
|
||||
return BTRFS_UTIL_ERROR_INO_LOOKUP_FAILED;
|
||||
|
||||
return build_subvol_path(iter, name, le16_to_cpu(ref->name_len),
|
||||
return build_subvol_path(iter, name, get_unaligned_le16(&ref->name_len),
|
||||
lookup.name, strlen(lookup.name),
|
||||
path_len_ret);
|
||||
}
|
||||
@ -1761,7 +1764,7 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd,
|
||||
* The orphan item might be for a free space cache inode, so
|
||||
* check if there's a matching root item.
|
||||
*/
|
||||
err = btrfs_util_subvolume_info_fd(fd, header->offset, &subvol);
|
||||
err = btrfs_util_subvolume_info_fd(fd, btrfs_search_header_offset(header), &subvol);
|
||||
if (!err) {
|
||||
if (*n >= capacity) {
|
||||
size_t new_capacity;
|
||||
@ -1778,14 +1781,14 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd,
|
||||
*ids = new_ids;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
(*ids)[(*n)++] = header->offset;
|
||||
(*ids)[(*n)++] = btrfs_search_header_offset(header);
|
||||
} else if (err != BTRFS_UTIL_ERROR_SUBVOLUME_NOT_FOUND) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
items_pos++;
|
||||
buf_off += sizeof(*header) + header->len;
|
||||
search.key.min_offset = header->offset + 1;
|
||||
buf_off += sizeof(*header) + btrfs_search_header_len(header);
|
||||
search.key.min_offset = btrfs_search_header_offset(header) + 1;
|
||||
}
|
||||
|
||||
err = BTRFS_UTIL_OK;
|
||||
|
Loading…
Reference in New Issue
Block a user