summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZach Brown <zab@redhat.com>2013-10-07 14:42:58 -0700
committerChris Mason <chris.mason@fusionio.com>2013-10-16 08:23:13 -0400
commit538897923e05f9c32e58f41cf023c1da45f0d3ab (patch)
tree8413869d761c79e2ff76f83379a466dcfb1704f8
parent69dc09a3ce7e914111c1cf9da93021d9b5d51762 (diff)
downloadbtrfs-progs-538897923e05f9c32e58f41cf023c1da45f0d3ab.tar.gz
btrfs-progs-538897923e05f9c32e58f41cf023c1da45f0d3ab.tar.bz2
btrfs-progs-538897923e05f9c32e58f41cf023c1da45f0d3ab.zip
btrfs-progs: check link_subvol name base
In principle, link_subvol() can be given an abitrary string as the name of the saved subvolume. It copies it into a fixed-size stack buffer and then uses it as dirent names without testing its length. This limits its length to BTRFS_NAME_LEN. This was found by static analsys. Signed-off-by: Zach Brown <zab@redhat.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r--btrfs-convert.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/btrfs-convert.c b/btrfs-convert.c
index 221dd45d..edef1bd7 100644
--- a/btrfs-convert.c
+++ b/btrfs-convert.c
@@ -1428,10 +1428,15 @@ static struct btrfs_root * link_subvol(struct btrfs_root *root,
struct btrfs_key key;
u64 dirid = btrfs_root_dirid(&root->root_item);
u64 index = 2;
- char buf[64];
+ char buf[BTRFS_NAME_LEN + 1]; /* for snprintf null */
+ int len;
int i;
int ret;
+ len = strlen(base);
+ if (len < 1 || len > BTRFS_NAME_LEN)
+ return NULL;
+
path = btrfs_alloc_path();
BUG_ON(!path);
@@ -1467,18 +1472,22 @@ static struct btrfs_root * link_subvol(struct btrfs_root *root,
key.offset = (u64)-1;
key.type = BTRFS_ROOT_ITEM_KEY;
- strcpy(buf, base);
+ memcpy(buf, base, len);
for (i = 0; i < 1024; i++) {
- ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf),
+ ret = btrfs_insert_dir_item(trans, root, buf, len,
dirid, &key, BTRFS_FT_DIR, index);
if (ret != -EEXIST)
break;
- sprintf(buf, "%s%d", base, i);
+ len = snprintf(buf, ARRAY_SIZE(buf), "%s%d", base, i);
+ if (len < 1 || len > BTRFS_NAME_LEN) {
+ ret = -EINVAL;
+ break;
+ }
}
if (ret)
goto fail;
- btrfs_set_inode_size(leaf, inode_item, strlen(buf) * 2 +
+ btrfs_set_inode_size(leaf, inode_item, len * 2 +
btrfs_inode_size(leaf, inode_item));
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
@@ -1487,13 +1496,13 @@ static struct btrfs_root * link_subvol(struct btrfs_root *root,
ret = btrfs_add_root_ref(trans, tree_root, root_objectid,
BTRFS_ROOT_BACKREF_KEY,
root->root_key.objectid,
- dirid, index, buf, strlen(buf));
+ dirid, index, buf, len);
BUG_ON(ret);
/* now add the forward ref */
ret = btrfs_add_root_ref(trans, tree_root, root->root_key.objectid,
BTRFS_ROOT_REF_KEY, root_objectid,
- dirid, index, buf, strlen(buf));
+ dirid, index, buf, len);
ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);