From: Dan Carpenter <dan.carpenter@oracle.com>
To: dsterba@suse.com
Cc: linux-btrfs@vger.kernel.org
Subject: [bug report] btrfs: do an allocation earlier during snapshot creation
Date: Thu, 17 Dec 2020 17:12:14 +0300 [thread overview]
Message-ID: <X9tnPl6nZfusgfre@mwanda> (raw)
[ 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
reply other threads:[~2020-12-17 14:13 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=X9tnPl6nZfusgfre@mwanda \
--to=dan.carpenter@oracle.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox