diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makemodule.am | 6 | ||||
-rw-r--r-- | lib/sqfs/xattr_reader.c | 293 | ||||
-rw-r--r-- | lib/sqfshelper/deserialize_fstree.c | 1 | ||||
-rw-r--r-- | lib/sqfshelper/xattr_reader.c | 299 |
4 files changed, 306 insertions, 293 deletions
diff --git a/lib/Makemodule.am b/lib/Makemodule.am index 180833e..a5db913 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -27,12 +27,12 @@ libsqfshelper_a_SOURCES += lib/sqfshelper/sqfs_reader.c libsqfshelper_a_SOURCES += lib/sqfshelper/write_dir.c libsqfshelper_a_SOURCES += lib/sqfshelper/write_inode.c libsqfshelper_a_SOURCES += lib/sqfshelper/write_export_table.c -libsqfshelper_a_SOURCES += lib/sqfshelper/xattr_reader.c libsqfshelper_a_SOURCES += lib/sqfshelper/print_version.c +libsqfshelper_a_SOURCES += lib/sqfshelper/xattr_reader.c libsqfshelper_a_SOURCES += lib/sqfshelper/compress.c lib/sqfshelper/comp_opt.c libsqfshelper_a_SOURCES += include/data_reader.h lib/sqfshelper/data_reader.c libsqfshelper_a_SOURCES += include/data_writer.h lib/sqfshelper/data_writer.c -libsqfshelper_a_SOURCES += include/xattr_reader.h lib/sqfshelper/write_xattr.c +libsqfshelper_a_SOURCES += lib/sqfshelper/write_xattr.c libutil_la_SOURCES = lib/util/write_data.c libutil_la_SOURCES += lib/util/read_data.c include/util.h @@ -55,7 +55,7 @@ libsquashfs_la_SOURCES += lib/sqfs/write_table.c include/highlevel.h libsquashfs_la_SOURCES += lib/sqfs/read_super.c lib/sqfs/meta_reader.c libsquashfs_la_SOURCES += lib/sqfs/read_inode.c libsquashfs_la_SOURCES += lib/sqfs/readdir.c -libsquashfs_la_SOURCES += lib/sqfs/xattr.c +libsquashfs_la_SOURCES += lib/sqfs/xattr.c lib/sqfs/xattr_reader.c libsquashfs_la_SOURCES += lib/sqfs/read_table.c libsquashfs_la_SOURCES += lib/sqfs/comp/compressor.c lib/sqfs/comp/internal.h libsquashfs_la_SOURCES += lib/sqfs/comp/create_block.c diff --git a/lib/sqfs/xattr_reader.c b/lib/sqfs/xattr_reader.c new file mode 100644 index 0000000..862f4af --- /dev/null +++ b/lib/sqfs/xattr_reader.c @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * xattr_reader.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "config.h" + +#include "sqfs/meta_reader.h" +#include "sqfs/xattr.h" +#include "util.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +struct xattr_reader_t { + uint64_t xattr_start; + + size_t num_id_blocks; + size_t num_ids; + + uint64_t *id_block_starts; + + meta_reader_t *idrd; + meta_reader_t *kvrd; + sqfs_super_t *super; +}; + +static int get_id_block_locations(xattr_reader_t *xr, int sqfsfd, + sqfs_super_t *super) +{ + sqfs_xattr_id_table_t idtbl; + size_t i; + + if (super->xattr_id_table_start >= super->bytes_used) { + fputs("xattr ID location table is after end of filesystem\n", + stderr); + return -1; + } + + if (read_data_at("reading xattr ID location table", + super->xattr_id_table_start, + sqfsfd, &idtbl, sizeof(idtbl))) { + return -1; + } + + xr->xattr_start = le64toh(idtbl.xattr_table_start); + xr->num_ids = le32toh(idtbl.xattr_ids); + xr->num_id_blocks = + (xr->num_ids * sizeof(sqfs_xattr_id_t)) / SQFS_META_BLOCK_SIZE; + + if ((xr->num_ids * sizeof(sqfs_xattr_id_t)) % SQFS_META_BLOCK_SIZE) + xr->num_id_blocks += 1; + + xr->id_block_starts = alloc_array(sizeof(uint64_t), xr->num_id_blocks); + if (xr->id_block_starts == NULL) { + perror("allocating xattr ID location table"); + return -1; + } + + if (read_data_at("reading xattr ID block locations", + super->xattr_id_table_start + sizeof(idtbl), + sqfsfd, xr->id_block_starts, + sizeof(uint64_t) * xr->num_id_blocks)) { + goto fail; + } + + for (i = 0; i < xr->num_id_blocks; ++i) { + xr->id_block_starts[i] = le64toh(xr->id_block_starts[i]); + + if (xr->id_block_starts[i] > super->bytes_used) { + fputs("found xattr ID block that is past " + "end of filesystem\n", stderr); + goto fail; + } + } + + return 0; +fail: + free(xr->id_block_starts); + xr->id_block_starts = NULL; + return -1; +} + +sqfs_xattr_entry_t *xattr_reader_read_key(xattr_reader_t *xr) +{ + sqfs_xattr_entry_t key, *out; + const char *prefix; + size_t plen, total; + + if (meta_reader_read(xr->kvrd, &key, sizeof(key))) + return NULL; + + key.type = le16toh(key.type); + key.size = le16toh(key.size); + + prefix = sqfs_get_xattr_prefix(key.type & SQUASHFS_XATTR_PREFIX_MASK); + if (prefix == NULL) { + fprintf(stderr, "found unknown xattr type %u\n", + key.type & SQUASHFS_XATTR_PREFIX_MASK); + return NULL; + } + + plen = strlen(prefix); + + if (SZ_ADD_OV(plen, key.size, &total) || SZ_ADD_OV(total, 1, &total) || + SZ_ADD_OV(sizeof(*out), total, &total)) { + errno = EOVERFLOW; + goto fail_alloc; + } + + out = calloc(1, total); + if (out == NULL) { + goto fail_alloc; + } + + *out = key; + memcpy(out->key, prefix, plen); + + if (meta_reader_read(xr->kvrd, out->key + plen, key.size)) { + free(out); + return NULL; + } + + return out; +fail_alloc: + perror("allocating xattr key"); + return NULL; +} + +sqfs_xattr_value_t *xattr_reader_read_value(xattr_reader_t *xr, + const sqfs_xattr_entry_t *key) +{ + size_t offset, new_offset, size; + sqfs_xattr_value_t value, *out; + uint64_t ref, start, new_start; + + if (meta_reader_read(xr->kvrd, &value, sizeof(value))) + return NULL; + + if (key->type & SQUASHFS_XATTR_FLAG_OOL) { + if (meta_reader_read(xr->kvrd, &ref, sizeof(ref))) + return NULL; + + meta_reader_get_position(xr->kvrd, &start, &offset); + + new_start = xr->xattr_start + (ref >> 16); + new_offset = ref & 0xFFFF; + + if (new_start > xr->super->bytes_used) { + fputs("OOL xattr reference points past end of " + "filesystem\n", stderr); + return NULL; + } + + if (new_offset >= SQFS_META_BLOCK_SIZE) { + fputs("OOL xattr reference points outside " + "metadata block\n", stderr); + return NULL; + } + + if (meta_reader_seek(xr->kvrd, new_start, new_offset)) + return NULL; + } + + value.size = le32toh(value.size); + + if (SZ_ADD_OV(sizeof(*out), value.size, &size) || + SZ_ADD_OV(size, 1, &size)) { + errno = EOVERFLOW; + goto fail_alloc; + } + + out = calloc(1, size); + if (out == NULL) + goto fail_alloc; + + *out = value; + + if (meta_reader_read(xr->kvrd, out->value, value.size)) + goto fail; + + if (key->type & SQUASHFS_XATTR_FLAG_OOL) { + if (meta_reader_seek(xr->kvrd, start, offset)) + goto fail; + } + + return out; +fail_alloc: + perror("allocating xattr value"); + return NULL; +fail: + free(out); + return NULL; +} + +int xattr_reader_seek_kv(xattr_reader_t *xr, const sqfs_xattr_id_t *desc) +{ + uint32_t offset = desc->xattr & 0xFFFF; + uint64_t block = xr->xattr_start + (desc->xattr >> 16); + + return meta_reader_seek(xr->kvrd, block, offset); +} + +int xattr_reader_get_desc(xattr_reader_t *xr, uint32_t idx, + sqfs_xattr_id_t *desc) +{ + size_t block, offset; + + memset(desc, 0, sizeof(*desc)); + + if (idx == 0xFFFFFFFF) + return 0; + + if (xr->kvrd == NULL || xr->idrd == NULL) { + if (idx != 0) + goto fail_bounds; + return 0; + } + + if (idx >= xr->num_ids) + goto fail_bounds; + + offset = (idx * sizeof(*desc)) % SQFS_META_BLOCK_SIZE; + block = (idx * sizeof(*desc)) / SQFS_META_BLOCK_SIZE; + + if (meta_reader_seek(xr->idrd, xr->id_block_starts[block], offset)) + return -1; + + if (meta_reader_read(xr->idrd, desc, sizeof(*desc))) + return -1; + + desc->xattr = le64toh(desc->xattr); + desc->count = le32toh(desc->count); + desc->size = le32toh(desc->size); + return 0; +fail_bounds: + fprintf(stderr, "Tried to access out of bounds " + "xattr index: 0x%08X\n", idx); + return -1; +} + +void xattr_reader_destroy(xattr_reader_t *xr) +{ + if (xr->kvrd != NULL) + meta_reader_destroy(xr->kvrd); + + if (xr->idrd != NULL) + meta_reader_destroy(xr->idrd); + + free(xr->id_block_starts); + free(xr); +} + +xattr_reader_t *xattr_reader_create(int sqfsfd, sqfs_super_t *super, + compressor_t *cmp) +{ + xattr_reader_t *xr = calloc(1, sizeof(*xr)); + + if (xr == NULL) { + perror("creating xattr reader"); + return NULL; + } + + if (super->flags & SQFS_FLAG_NO_XATTRS) + return xr; + + if (super->xattr_id_table_start == 0xFFFFFFFFFFFFFFFF) + return xr; + + if (get_id_block_locations(xr, sqfsfd, super)) + goto fail; + + xr->idrd = meta_reader_create(sqfsfd, cmp, + super->id_table_start, + super->bytes_used); + if (xr->idrd == NULL) + goto fail; + + xr->kvrd = meta_reader_create(sqfsfd, cmp, + super->id_table_start, + super->bytes_used); + if (xr->kvrd == NULL) + goto fail; + + xr->super = super; + return xr; +fail: + xattr_reader_destroy(xr); + return NULL; +} diff --git a/lib/sqfshelper/deserialize_fstree.c b/lib/sqfshelper/deserialize_fstree.c index c418b16..98c59fb 100644 --- a/lib/sqfshelper/deserialize_fstree.c +++ b/lib/sqfshelper/deserialize_fstree.c @@ -9,7 +9,6 @@ #include "sqfs/meta_reader.h" #include "sqfs/dir.h" -#include "xattr_reader.h" #include "highlevel.h" #include <stdlib.h> diff --git a/lib/sqfshelper/xattr_reader.c b/lib/sqfshelper/xattr_reader.c index c13358d..2cf1114 100644 --- a/lib/sqfshelper/xattr_reader.c +++ b/lib/sqfshelper/xattr_reader.c @@ -6,9 +6,7 @@ */ #include "config.h" -#include "sqfs/meta_reader.h" -#include "sqfs/xattr.h" -#include "xattr_reader.h" +#include "highlevel.h" #include "util.h" #include <assert.h> @@ -17,226 +15,6 @@ #include <stdio.h> #include <errno.h> -struct xattr_reader_t { - uint64_t xattr_start; - - size_t num_id_blocks; - size_t num_ids; - - uint64_t *id_block_starts; - - meta_reader_t *idrd; - meta_reader_t *kvrd; - sqfs_super_t *super; -}; - -static int get_id_block_locations(xattr_reader_t *xr, int sqfsfd, - sqfs_super_t *super) -{ - sqfs_xattr_id_table_t idtbl; - size_t i; - - if (super->xattr_id_table_start >= super->bytes_used) { - fputs("xattr ID location table is after end of filesystem\n", - stderr); - return -1; - } - - if (read_data_at("reading xattr ID location table", - super->xattr_id_table_start, - sqfsfd, &idtbl, sizeof(idtbl))) { - return -1; - } - - xr->xattr_start = le64toh(idtbl.xattr_table_start); - xr->num_ids = le32toh(idtbl.xattr_ids); - xr->num_id_blocks = - (xr->num_ids * sizeof(sqfs_xattr_id_t)) / SQFS_META_BLOCK_SIZE; - - if ((xr->num_ids * sizeof(sqfs_xattr_id_t)) % SQFS_META_BLOCK_SIZE) - xr->num_id_blocks += 1; - - xr->id_block_starts = alloc_array(sizeof(uint64_t), xr->num_id_blocks); - if (xr->id_block_starts == NULL) { - perror("allocating xattr ID location table"); - return -1; - } - - if (read_data_at("reading xattr ID block locations", - super->xattr_id_table_start + sizeof(idtbl), - sqfsfd, xr->id_block_starts, - sizeof(uint64_t) * xr->num_id_blocks)) { - goto fail; - } - - for (i = 0; i < xr->num_id_blocks; ++i) { - xr->id_block_starts[i] = le64toh(xr->id_block_starts[i]); - - if (xr->id_block_starts[i] > super->bytes_used) { - fputs("found xattr ID block that is past " - "end of filesystem\n", stderr); - goto fail; - } - } - - return 0; -fail: - free(xr->id_block_starts); - xr->id_block_starts = NULL; - return -1; -} - -static int get_xattr_desc(xattr_reader_t *xr, uint32_t idx, - sqfs_xattr_id_t *desc) -{ - size_t block, offset; - - if (idx >= xr->num_ids) { - fprintf(stderr, "Tried to access out of bounds " - "xattr index: 0x%08X\n", idx); - return -1; - } - - offset = (idx * sizeof(*desc)) % SQFS_META_BLOCK_SIZE; - block = (idx * sizeof(*desc)) / SQFS_META_BLOCK_SIZE; - - if (meta_reader_seek(xr->idrd, xr->id_block_starts[block], offset)) - return -1; - - if (meta_reader_read(xr->idrd, desc, sizeof(*desc))) - return -1; - - desc->xattr = le64toh(desc->xattr); - desc->count = le32toh(desc->count); - desc->size = le32toh(desc->size); - - if ((desc->xattr & 0xFFFF) >= SQFS_META_BLOCK_SIZE) { - fputs("Found xattr ID record pointing outside " - "metadata block\n", stderr); - return -1; - } - - if ((xr->xattr_start + (desc->xattr >> 16)) >= xr->super->bytes_used) { - fputs("Found xattr ID record pointing past " - "end of filesystem\n", stderr); - return -1; - } - - return 0; -} - -static sqfs_xattr_entry_t *read_key(xattr_reader_t *xr) -{ - sqfs_xattr_entry_t key, *out; - const char *prefix; - size_t plen, total; - - if (meta_reader_read(xr->kvrd, &key, sizeof(key))) - return NULL; - - key.type = le16toh(key.type); - key.size = le16toh(key.size); - - prefix = sqfs_get_xattr_prefix(key.type & SQUASHFS_XATTR_PREFIX_MASK); - if (prefix == NULL) { - fprintf(stderr, "found unknown xattr type %u\n", - key.type & SQUASHFS_XATTR_PREFIX_MASK); - return NULL; - } - - plen = strlen(prefix); - - if (SZ_ADD_OV(plen, key.size, &total) || SZ_ADD_OV(total, 1, &total) || - SZ_ADD_OV(sizeof(*out), total, &total)) { - errno = EOVERFLOW; - goto fail_alloc; - } - - out = calloc(1, total); - if (out == NULL) { - goto fail_alloc; - } - - *out = key; - memcpy(out->key, prefix, plen); - - if (meta_reader_read(xr->kvrd, out->key + plen, key.size)) { - free(out); - return NULL; - } - - return out; -fail_alloc: - perror("allocating xattr key"); - return NULL; -} - -static sqfs_xattr_value_t *read_value(xattr_reader_t *xr, - const sqfs_xattr_entry_t *key) -{ - size_t offset, new_offset, size; - sqfs_xattr_value_t value, *out; - uint64_t ref, start, new_start; - - if (meta_reader_read(xr->kvrd, &value, sizeof(value))) - return NULL; - - if (key->type & SQUASHFS_XATTR_FLAG_OOL) { - if (meta_reader_read(xr->kvrd, &ref, sizeof(ref))) - return NULL; - - meta_reader_get_position(xr->kvrd, &start, &offset); - - new_start = xr->xattr_start + (ref >> 16); - new_offset = ref & 0xFFFF; - - if (new_start > xr->super->bytes_used) { - fputs("OOL xattr reference points past end of " - "filesystem\n", stderr); - return NULL; - } - - if (new_offset >= SQFS_META_BLOCK_SIZE) { - fputs("OOL xattr reference points outside " - "metadata block\n", stderr); - return NULL; - } - - if (meta_reader_seek(xr->kvrd, new_start, new_offset)) - return NULL; - } - - value.size = le32toh(value.size); - - if (SZ_ADD_OV(sizeof(*out), value.size, &size) || - SZ_ADD_OV(size, 1, &size)) { - errno = EOVERFLOW; - goto fail_alloc; - } - - out = calloc(1, size); - if (out == NULL) - goto fail_alloc; - - *out = value; - - if (meta_reader_read(xr->kvrd, out->value, value.size)) - goto fail; - - if (key->type & SQUASHFS_XATTR_FLAG_OOL) { - if (meta_reader_seek(xr->kvrd, start, offset)) - goto fail; - } - - return out; -fail_alloc: - perror("allocating xattr value"); - return NULL; -fail: - free(out); - return NULL; -} - static int restore_kv_pairs(xattr_reader_t *xr, fstree_t *fs, tree_node_t *node) { @@ -245,17 +23,12 @@ static int restore_kv_pairs(xattr_reader_t *xr, fstree_t *fs, sqfs_xattr_value_t *val; int ret; - if (meta_reader_seek(xr->kvrd, node->xattr->block, - node->xattr->offset)) { - return -1; - } - for (i = 0; i < node->xattr->num_attr; ++i) { - key = read_key(xr); + key = xattr_reader_read_key(xr); if (key == NULL) return -1; - val = read_value(xr, key); + val = xattr_reader_read_value(xr, key); if (val == NULL) goto fail_key; @@ -302,12 +75,6 @@ int xattr_reader_restore_node(xattr_reader_t *xr, fstree_t *fs, sqfs_xattr_id_t desc; tree_xattr_t *it; - if (xr->kvrd == NULL || xr->idrd == NULL) - return 0; - - if (xattr == 0xFFFFFFFF) - return 0; - for (it = fs->xattr; it != NULL; it = it->next) { if (it->index == xattr) { node->xattr = it; @@ -315,9 +82,12 @@ int xattr_reader_restore_node(xattr_reader_t *xr, fstree_t *fs, } } - if (get_xattr_desc(xr, xattr, &desc)) + if (xattr_reader_get_desc(xr, xattr, &desc)) return -1; + if (desc.count == 0 || desc.size == 0) + return 0; + node->xattr = alloc_flex(sizeof(*node->xattr), sizeof(node->xattr->attr[0]), desc.count); if (node->xattr == NULL) { @@ -327,12 +97,13 @@ int xattr_reader_restore_node(xattr_reader_t *xr, fstree_t *fs, node->xattr->num_attr = desc.count; node->xattr->max_attr = desc.count; - node->xattr->block = xr->xattr_start + (desc.xattr >> 16); - node->xattr->offset = desc.xattr & 0xFFFF; node->xattr->size = desc.size; node->xattr->index = xattr; node->xattr->owner = node; + if (xattr_reader_seek_kv(xr, &desc)) + return -1; + if (restore_kv_pairs(xr, fs, node)) { free(node->xattr); return -1; @@ -342,53 +113,3 @@ int xattr_reader_restore_node(xattr_reader_t *xr, fstree_t *fs, fs->xattr = node->xattr; return 0; } - -void xattr_reader_destroy(xattr_reader_t *xr) -{ - if (xr->kvrd != NULL) - meta_reader_destroy(xr->kvrd); - - if (xr->idrd != NULL) - meta_reader_destroy(xr->idrd); - - free(xr->id_block_starts); - free(xr); -} - -xattr_reader_t *xattr_reader_create(int sqfsfd, sqfs_super_t *super, - compressor_t *cmp) -{ - xattr_reader_t *xr = calloc(1, sizeof(*xr)); - - if (xr == NULL) { - perror("creating xattr reader"); - return NULL; - } - - if (super->flags & SQFS_FLAG_NO_XATTRS) - return xr; - - if (super->xattr_id_table_start == 0xFFFFFFFFFFFFFFFF) - return xr; - - if (get_id_block_locations(xr, sqfsfd, super)) - goto fail; - - xr->idrd = meta_reader_create(sqfsfd, cmp, - super->id_table_start, - super->bytes_used); - if (xr->idrd == NULL) - goto fail; - - xr->kvrd = meta_reader_create(sqfsfd, cmp, - super->id_table_start, - super->bytes_used); - if (xr->kvrd == NULL) - goto fail; - - xr->super = super; - return xr; -fail: - xattr_reader_destroy(xr); - return NULL; -} |