aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2021-06-24 14:47:41 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2021-06-25 17:37:56 +0200
commit9ba4d7a122dfc4e3e03d0112ad03115b3065a238 (patch)
tree98f8c6a62809c975e4a210adce1202f1e65037b9
parentcca5b4d50c8324144a882ebb589d5ed020c80143 (diff)
libfstree: guard against link count and inode number overflow
If the hard link counter or the inode number counter overflow the maximum representable value (for SquashFS 16 bit and 32 bit respecitively), abort with an error message. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--lib/fstree/hardlink.c7
-rw-r--r--lib/fstree/mknode.c13
-rw-r--r--lib/fstree/post_process.c51
3 files changed, 59 insertions, 12 deletions
diff --git a/lib/fstree/hardlink.c b/lib/fstree/hardlink.c
index e71670a..11ab566 100644
--- a/lib/fstree/hardlink.c
+++ b/lib/fstree/hardlink.c
@@ -62,9 +62,14 @@ int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node)
return -1;
}
+ if (node->link_count == 0x0FFFF) {
+ errno = EMLINK;
+ return -1;
+ }
+
start->mode = FSTREE_MODE_HARD_LINK_RESOLVED;
start->data.target_node = node;
- node->link_count += 1;
+ node->link_count++;
return 0;
}
diff --git a/lib/fstree/mknode.c b/lib/fstree/mknode.c
index 4353b74..f836c67 100644
--- a/lib/fstree/mknode.c
+++ b/lib/fstree/mknode.c
@@ -70,10 +70,19 @@ tree_node_t *fstree_mknode(tree_node_t *parent, const char *name,
case S_IFDIR:
n->link_count = 2;
break;
+ default:
+ break;
}
- if (parent != NULL)
- parent->link_count += 1;
+ if (parent != NULL) {
+ if (parent->link_count == 0x0FFFF) {
+ free(n);
+ errno = EMLINK;
+ return NULL;
+ }
+
+ parent->link_count++;
+ }
return n;
}
diff --git a/lib/fstree/post_process.c b/lib/fstree/post_process.c
index 52af958..87b3d4c 100644
--- a/lib/fstree/post_process.c
+++ b/lib/fstree/post_process.c
@@ -12,10 +12,11 @@
#include <stdio.h>
#include <errno.h>
-static void alloc_inode_num_dfs(fstree_t *fs, tree_node_t *root)
+static int alloc_inode_num_dfs(fstree_t *fs, tree_node_t *root)
{
bool has_subdirs = false;
tree_node_t *it;
+ size_t inum;
for (it = root->data.dir.children; it != NULL; it = it->next) {
if (S_ISDIR(it->mode)) {
@@ -26,17 +27,32 @@ static void alloc_inode_num_dfs(fstree_t *fs, tree_node_t *root)
if (has_subdirs) {
for (it = root->data.dir.children; it != NULL; it = it->next) {
- if (S_ISDIR(it->mode))
- alloc_inode_num_dfs(fs, it);
+ if (S_ISDIR(it->mode)) {
+ if (alloc_inode_num_dfs(fs, it))
+ return -1;
+ }
}
}
for (it = root->data.dir.children; it != NULL; it = it->next) {
if (it->mode != FSTREE_MODE_HARD_LINK_RESOLVED) {
- it->inode_num = fs->unique_inode_count + 1;
- fs->unique_inode_count += 1;
+ if (SZ_ADD_OV(fs->unique_inode_count, 1, &inum))
+ goto fail_ov;
+
+ if ((sizeof(size_t) > sizeof(sqfs_u32)) &&
+ inum > 0x0FFFFFFFFUL) {
+ goto fail_ov;
+ }
+
+ it->inode_num = (sqfs_u32)inum;
+ fs->unique_inode_count = inum;
}
}
+
+ return 0;
+fail_ov:
+ fputs("Too many inodes.\n", stderr);
+ return -1;
}
static int resolve_hard_links_dfs(fstree_t *fs, tree_node_t *n)
@@ -167,7 +183,10 @@ static void reorder_hard_links(fstree_t *fs)
}
fs->inodes[i] = tgt;
- tgt->inode_num = i + 1;
+
+ /* XXX: the possible overflow is checked for
+ during allocation */
+ tgt->inode_num = (sqfs_u32)(i + 1);
++i;
}
}
@@ -175,15 +194,26 @@ static void reorder_hard_links(fstree_t *fs)
int fstree_post_process(fstree_t *fs)
{
+ size_t inum;
+
sort_recursive(fs->root);
if (resolve_hard_links_dfs(fs, fs->root))
return -1;
fs->unique_inode_count = 0;
- alloc_inode_num_dfs(fs, fs->root);
- fs->root->inode_num = fs->unique_inode_count + 1;
- fs->unique_inode_count += 1;
+
+ if (alloc_inode_num_dfs(fs, fs->root))
+ return -1;
+
+ if (SZ_ADD_OV(fs->unique_inode_count, 1, &inum))
+ goto fail_root_ov;
+
+ if ((sizeof(size_t) > sizeof(sqfs_u32)) && inum > 0x0FFFFFFFFUL)
+ goto fail_root_ov;
+
+ fs->root->inode_num = (sqfs_u32)inum;
+ fs->unique_inode_count = inum;
fs->inodes = calloc(sizeof(fs->inodes[0]), fs->unique_inode_count);
if (fs->inodes == NULL) {
@@ -196,4 +226,7 @@ int fstree_post_process(fstree_t *fs)
fs->files = file_list_dfs(fs->root);
return 0;
+fail_root_ov:
+ fputs("Too many inodes, cannot allocate number for root.\n", stderr);
+ return -1;
}