diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/common/hardlink.c | 10 | ||||
-rw-r--r-- | lib/sqfs/dir_reader/get_path.c | 73 |
2 files changed, 63 insertions, 20 deletions
diff --git a/lib/common/hardlink.c b/lib/common/hardlink.c index 031724b..f8d4d4a 100644 --- a/lib/common/hardlink.c +++ b/lib/common/hardlink.c @@ -49,9 +49,9 @@ static int map_nodes(rbtree_t *inumtree, sqfs_hard_link_t **out, goto fail_oom; lnk->inode_number = idx; - lnk->target = sqfs_tree_node_get_path(target); - if (lnk->target == NULL) - goto fail_oom; + ret = sqfs_tree_node_get_path(target, &lnk->target); + if (ret != 0) + goto fail_path; if (canonicalize_name(lnk->target) == 0) { lnk->next = (*out); @@ -61,6 +61,10 @@ static int map_nodes(rbtree_t *inumtree, sqfs_hard_link_t **out, free(lnk); } return 0; +fail_path: + sqfs_perror(NULL, "re-constructing hard link path", ret); + free(lnk); + return -1; fail_oom: fputs("detecting hard links in file system tree: out of memory\n", stderr); diff --git a/lib/sqfs/dir_reader/get_path.c b/lib/sqfs/dir_reader/get_path.c index bdd8317..847bfd3 100644 --- a/lib/sqfs/dir_reader/get_path.c +++ b/lib/sqfs/dir_reader/get_path.c @@ -10,33 +10,72 @@ #include <string.h> #include <stdlib.h> -char *sqfs_tree_node_get_path(const sqfs_tree_node_t *node) +int sqfs_tree_node_get_path(const sqfs_tree_node_t *node, char **out) { const sqfs_tree_node_t *it; + size_t clen, len = 0; char *str, *ptr; - size_t len = 0; - if (node->parent == NULL) - return strdup("/"); + *out = NULL; - for (it = node; it != NULL && it->parent != NULL; it = it->parent) { - len += strlen((const char *)it->name) + 1; + if (node == NULL) + return SQFS_ERROR_ARG_INVALID; + + for (it = node; it->parent != NULL; it = it->parent) { + if (it->parent == node) + return SQFS_ERROR_LINK_LOOP; + + /* non-root nodes must have a valid name */ + clen = strlen((const char *)it->name); + + if (clen == 0) + return SQFS_ERROR_CORRUPTED; + + if (strchr((const char *)it->name, '/') != NULL) + return SQFS_ERROR_CORRUPTED; + + if (it->name[0] == '.') { + if (clen == 1 || (clen == 2 && it->name[1] == '.')) + return SQFS_ERROR_CORRUPTED; + } + + /* compute total path length */ + if (SZ_ADD_OV(clen, 1, &clen)) + return SQFS_ERROR_OVERFLOW; + + if (SZ_ADD_OV(len, clen, &len)) + return SQFS_ERROR_OVERFLOW; } - str = malloc(len + 1); - if (str == NULL) - return NULL; + /* root node must not have a name */ + if (it->name[0] != '\0') + return SQFS_ERROR_ARG_INVALID; + + /* generate the path */ + if (node->parent == NULL) { + str = strdup("/"); + if (str == NULL) + return SQFS_ERROR_ALLOC; + } else { + if (SZ_ADD_OV(len, 1, &len)) + return SQFS_ERROR_OVERFLOW; + + str = malloc(len); + if (str == NULL) + return SQFS_ERROR_ALLOC; - ptr = str + len; - *ptr = '\0'; + ptr = str + len - 1; + *ptr = '\0'; - for (it = node; it != NULL && it->parent != NULL; it = it->parent) { - len = strlen((const char *)it->name); - ptr -= len; + for (it = node; it->parent != NULL; it = it->parent) { + len = strlen((const char *)it->name); + ptr -= len; - memcpy(ptr, (const char *)it->name, len); - *(--ptr) = '/'; + memcpy(ptr, (const char *)it->name, len); + *(--ptr) = '/'; + } } - return str; + *out = str; + return 0; } |