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;
|
header = (struct btrfs_ioctl_search_header *)search.buf;
|
||||||
ref = (struct btrfs_root_ref *)(header + 1);
|
ref = (struct btrfs_root_ref *)(header + 1);
|
||||||
name = (char *)(ref + 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.treeid = id;
|
||||||
lookup.objectid = le64_to_cpu(ref->dirid);
|
lookup.objectid = get_unaligned_le64(&ref->dirid);
|
||||||
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &lookup);
|
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &lookup);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
free(path);
|
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)
|
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);
|
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,
|
static void copy_timespec(struct timespec *timespec,
|
||||||
const struct btrfs_timespec *btrfs_timespec)
|
const struct btrfs_timespec *btrfs_timespec)
|
||||||
{
|
{
|
||||||
timespec->tv_sec = le64_to_cpu(btrfs_timespec->sec);
|
timespec->tv_sec = get_unaligned_le64(&btrfs_timespec->sec);
|
||||||
timespec->tv_nsec = le32_to_cpu(btrfs_timespec->nsec);
|
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,
|
static void copy_root_item(struct btrfs_util_subvolume_info *subvol,
|
||||||
const struct btrfs_root_item *root)
|
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->uuid, root->uuid, sizeof(subvol->uuid));
|
||||||
memcpy(subvol->parent_uuid, root->parent_uuid,
|
memcpy(subvol->parent_uuid, root->parent_uuid, sizeof(subvol->parent_uuid));
|
||||||
sizeof(subvol->parent_uuid));
|
memcpy(subvol->received_uuid, root->received_uuid, sizeof(subvol->received_uuid));
|
||||||
memcpy(subvol->received_uuid, root->received_uuid,
|
subvol->generation = get_unaligned_le64(&root->generation);
|
||||||
sizeof(subvol->received_uuid));
|
subvol->ctransid = get_unaligned_le64(&root->ctransid);
|
||||||
subvol->generation = le64_to_cpu(root->generation);
|
subvol->otransid = get_unaligned_le64(&root->otransid);
|
||||||
subvol->ctransid = le64_to_cpu(root->ctransid);
|
subvol->stransid = get_unaligned_le64(&root->stransid);
|
||||||
subvol->otransid = le64_to_cpu(root->otransid);
|
subvol->rtransid = get_unaligned_le64(&root->rtransid);
|
||||||
subvol->stransid = le64_to_cpu(root->stransid);
|
|
||||||
subvol->rtransid = le64_to_cpu(root->rtransid);
|
|
||||||
copy_timespec(&subvol->ctime, &root->ctime);
|
copy_timespec(&subvol->ctime, &root->ctime);
|
||||||
copy_timespec(&subvol->otime, &root->otime);
|
copy_timespec(&subvol->otime, &root->otime);
|
||||||
copy_timespec(&subvol->stime, &root->stime);
|
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);
|
ref = (const struct btrfs_root_ref *)(header + 1);
|
||||||
subvol->parent_id = btrfs_search_header_offset(header);
|
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;
|
need_root_backref = false;
|
||||||
search.key.min_type = UINT32_MAX;
|
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);
|
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 struct btrfs_dir_item *dir;
|
||||||
const char *name;
|
const char *name;
|
||||||
uint16_t name_len;
|
uint16_t name_len;
|
||||||
|
|
||||||
dir = (struct btrfs_dir_item *)(header + 1);
|
dir = (struct btrfs_dir_item *)(header + 1);
|
||||||
name = (const char *)(dir + 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) {
|
if (strncmp(name, "default", name_len) == 0) {
|
||||||
*id_ret = le64_to_cpu(dir->location.objectid);
|
*id_ret = get_unaligned_le64(&dir->location.objectid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items_pos++;
|
items_pos++;
|
||||||
buf_off += sizeof(*header) + header->len;
|
buf_off += sizeof(*header) + btrfs_search_header_len(header);
|
||||||
search.key.min_offset = header->offset + 1;
|
search.key.min_offset = btrfs_search_header_offset(header) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BTRFS_UTIL_OK;
|
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;
|
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,
|
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_ioctl_search_header *header,
|
||||||
const struct btrfs_root_ref *ref,
|
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 = {
|
struct btrfs_ioctl_ino_lookup_args lookup = {
|
||||||
.treeid = btrfs_search_header_objectid(header),
|
.treeid = btrfs_search_header_objectid(header),
|
||||||
.objectid = le64_to_cpu(ref->dirid),
|
.objectid = get_unaligned_le64(&ref->dirid),
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1458,7 +1461,7 @@ static enum btrfs_util_error build_subvol_path_privileged(struct btrfs_util_subv
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return BTRFS_UTIL_ERROR_INO_LOOKUP_FAILED;
|
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),
|
lookup.name, strlen(lookup.name),
|
||||||
path_len_ret);
|
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
|
* The orphan item might be for a free space cache inode, so
|
||||||
* check if there's a matching root item.
|
* 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 (!err) {
|
||||||
if (*n >= capacity) {
|
if (*n >= capacity) {
|
||||||
size_t new_capacity;
|
size_t new_capacity;
|
||||||
|
@ -1778,14 +1781,14 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd,
|
||||||
*ids = new_ids;
|
*ids = new_ids;
|
||||||
capacity = new_capacity;
|
capacity = new_capacity;
|
||||||
}
|
}
|
||||||
(*ids)[(*n)++] = header->offset;
|
(*ids)[(*n)++] = btrfs_search_header_offset(header);
|
||||||
} else if (err != BTRFS_UTIL_ERROR_SUBVOLUME_NOT_FOUND) {
|
} else if (err != BTRFS_UTIL_ERROR_SUBVOLUME_NOT_FOUND) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
items_pos++;
|
items_pos++;
|
||||||
buf_off += sizeof(*header) + header->len;
|
buf_off += sizeof(*header) + btrfs_search_header_len(header);
|
||||||
search.key.min_offset = header->offset + 1;
|
search.key.min_offset = btrfs_search_header_offset(header) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = BTRFS_UTIL_OK;
|
err = BTRFS_UTIL_OK;
|
||||||
|
|
Loading…
Reference in a new issue