aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2022-07-05 12:16:36 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2022-07-08 19:17:35 +0200
commit75063b2e14dacc13fcbeeba24e580198a7c1c638 (patch)
treef58b8c85ed5472523a5596be3434f7488dbfe465 /lib
parent3946cf086183f8dd4d5d115f52ba1b87560b7ce4 (diff)
Make sqfs_tree_node_get_path more robust
Test against various invariants: - Every non-root node must have a name - The root node muts not have a name - The name must not be ".." or "." - The name must not contain '/' - The loop that chases parent pointers must terminate, i.e. we must never reach the starting state again (link loop). Furthermore, make sure the sum of all path components plus separators does not overflow. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
-rw-r--r--lib/common/hardlink.c10
-rw-r--r--lib/sqfs/dir_reader/get_path.c73
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;
}