* [bug report] btrfs: do an allocation earlier during snapshot creation
@ 2020-12-17 14:12 Dan Carpenter
0 siblings, 0 replies; only message in thread
From: Dan Carpenter @ 2020-12-17 14:12 UTC (permalink / raw)
To: dsterba; +Cc: linux-btrfs
[ Sorry David, the complain script uses git blame and it just picked
you. And then I decided to keep the address because your email is
still active and you seem like an expert. -dan ]
Hello David Sterba,
The patch a1ee73626844: "btrfs: do an allocation earlier during
snapshot creation" from Nov 10, 2015, leads to the following static
checker warning:
fs/btrfs/ioctl.c:890 create_snapshot()
warn: 'pending_snapshot' not removed from list
fs/btrfs/ioctl.c
809
810 pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_KERNEL);
^^^^^^^^^^^^^^^^
Allocated here.
811 if (!pending_snapshot)
812 return -ENOMEM;
813
814 ret = get_anon_bdev(&pending_snapshot->anon_dev);
815 if (ret < 0)
816 goto free_pending;
817 pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item),
818 GFP_KERNEL);
819 pending_snapshot->path = btrfs_alloc_path();
820 if (!pending_snapshot->root_item || !pending_snapshot->path) {
821 ret = -ENOMEM;
822 goto free_pending;
823 }
824
825 btrfs_init_block_rsv(&pending_snapshot->block_rsv,
826 BTRFS_BLOCK_RSV_TEMP);
827 /*
828 * 1 - parent dir inode
829 * 2 - dir entries
830 * 1 - root item
831 * 2 - root ref/backref
832 * 1 - root of snapshot
833 * 1 - UUID item
834 */
835 ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
836 &pending_snapshot->block_rsv, 8,
837 false);
838 if (ret)
839 goto free_pending;
840
841 pending_snapshot->dentry = dentry;
842 pending_snapshot->root = root;
843 pending_snapshot->readonly = readonly;
844 pending_snapshot->dir = dir;
845 pending_snapshot->inherit = inherit;
846
847 trans = btrfs_start_transaction(root, 0);
848 if (IS_ERR(trans)) {
849 ret = PTR_ERR(trans);
850 goto fail;
851 }
852
853 spin_lock(&fs_info->trans_lock);
854 list_add(&pending_snapshot->list,
855 &trans->transaction->pending_snapshots);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Added to the list here.
856 spin_unlock(&fs_info->trans_lock);
857
858 ret = btrfs_commit_transaction(trans);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This will clean empty the ->pending_snapshots list when we call
create_pending_snapshots() but it's possible to fail before that
happens.
Possibly one fix would be to clear out the ->pending_snapshots list in
the __btrfs_end_transaction() function.
859 if (ret)
860 goto fail;
861
862 ret = pending_snapshot->error;
863 if (ret)
864 goto fail;
865
866 ret = btrfs_orphan_cleanup(pending_snapshot->snap);
867 if (ret)
868 goto fail;
869
870 inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry);
871 if (IS_ERR(inode)) {
872 ret = PTR_ERR(inode);
873 goto fail;
874 }
875
876 d_instantiate(dentry, inode);
877 ret = 0;
878 pending_snapshot->anon_dev = 0;
879 fail:
880 /* Prevent double freeing of anon_dev */
881 if (ret && pending_snapshot->snap)
882 pending_snapshot->snap->anon_dev = 0;
883 btrfs_put_root(pending_snapshot->snap);
884 btrfs_subvolume_release_metadata(root, &pending_snapshot->block_rsv);
885 free_pending:
886 if (pending_snapshot->anon_dev)
887 free_anon_bdev(pending_snapshot->anon_dev);
888 kfree(pending_snapshot->root_item);
889 btrfs_free_path(pending_snapshot->path);
890 kfree(pending_snapshot);
^^^^^^^^^^^^^^^^^^^^^^^
If btrfs_commit_transaction() fails too early then this is freed but
it's still in the ->pending_snapshots list leading to a use after free.
891
892 return ret;
893 }
regards,
dan carpenter
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-12-17 14:13 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-12-17 14:12 [bug report] btrfs: do an allocation earlier during snapshot creation Dan Carpenter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.