Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

btrfs: fix leak of path in btrfs_find_item

If btrfs_find_item is called with NULL path it allocates one locally but
does not free it. Affected paths are inserting an orphan item for a file
and for a subvol root.

Move the path allocation to the callers.

CC: <stable@vger.kernel.org> # 3.14+
Fixes: 3f870c289900 ("btrfs: expand btrfs_find_item() to include find_orphan_item functionality")
Signed-off-by: David Sterba <dsterba@suse.cz>

+22 -15
+4 -13
fs/btrfs/ctree.c
··· 2609 2609 return 0; 2610 2610 } 2611 2611 2612 - int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path, 2612 + int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path, 2613 2613 u64 iobjectid, u64 ioff, u8 key_type, 2614 2614 struct btrfs_key *found_key) 2615 2615 { 2616 2616 int ret; 2617 2617 struct btrfs_key key; 2618 2618 struct extent_buffer *eb; 2619 - struct btrfs_path *path; 2619 + 2620 + ASSERT(path); 2620 2621 2621 2622 key.type = key_type; 2622 2623 key.objectid = iobjectid; 2623 2624 key.offset = ioff; 2624 2625 2625 - if (found_path == NULL) { 2626 - path = btrfs_alloc_path(); 2627 - if (!path) 2628 - return -ENOMEM; 2629 - } else 2630 - path = found_path; 2631 - 2632 2626 ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); 2633 - if ((ret < 0) || (found_key == NULL)) { 2634 - if (path != found_path) 2635 - btrfs_free_path(path); 2627 + if ((ret < 0) || (found_key == NULL)) 2636 2628 return ret; 2637 - } 2638 2629 2639 2630 eb = path->nodes[0]; 2640 2631 if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
+8 -1
fs/btrfs/disk-io.c
··· 1630 1630 bool check_ref) 1631 1631 { 1632 1632 struct btrfs_root *root; 1633 + struct btrfs_path *path; 1633 1634 int ret; 1634 1635 1635 1636 if (location->objectid == BTRFS_ROOT_TREE_OBJECTID) ··· 1670 1669 if (ret) 1671 1670 goto fail; 1672 1671 1673 - ret = btrfs_find_item(fs_info->tree_root, NULL, BTRFS_ORPHAN_OBJECTID, 1672 + path = btrfs_alloc_path(); 1673 + if (!path) { 1674 + ret = -ENOMEM; 1675 + goto fail; 1676 + } 1677 + ret = btrfs_find_item(fs_info->tree_root, path, BTRFS_ORPHAN_OBJECTID, 1674 1678 location->objectid, BTRFS_ORPHAN_ITEM_KEY, NULL); 1679 + btrfs_free_path(path); 1675 1680 if (ret < 0) 1676 1681 goto fail; 1677 1682 if (ret == 0)
+10 -1
fs/btrfs/tree-log.c
··· 1257 1257 struct btrfs_root *root, u64 offset) 1258 1258 { 1259 1259 int ret; 1260 - ret = btrfs_find_item(root, NULL, BTRFS_ORPHAN_OBJECTID, 1260 + struct btrfs_path *path; 1261 + 1262 + path = btrfs_alloc_path(); 1263 + if (!path) 1264 + return -ENOMEM; 1265 + 1266 + ret = btrfs_find_item(root, path, BTRFS_ORPHAN_OBJECTID, 1261 1267 offset, BTRFS_ORPHAN_ITEM_KEY, NULL); 1262 1268 if (ret > 0) 1263 1269 ret = btrfs_insert_orphan_item(trans, root, offset); 1270 + 1271 + btrfs_free_path(path); 1272 + 1264 1273 return ret; 1265 1274 } 1266 1275