diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/fstree/hardlink.c | 7 | ||||
| -rw-r--r-- | lib/fstree/mknode.c | 13 | ||||
| -rw-r--r-- | lib/fstree/post_process.c | 51 | 
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;  } | 
