diff options
author | Alex Elder <elder@inktank.com> | 2013-05-13 21:35:37 -0400 |
---|---|---|
committer | Alex Elder <elder@inktank.com> | 2013-05-17 13:50:10 -0400 |
commit | 3abef3b3585bbc67d56fdc9c67761a900fb4b69d (patch) | |
tree | d94c9555797c77e4c92f2fea22049a962af48de9 | |
parent | 7262cfca430a1a0e0707149af29ae86bc0ded230 (diff) |
rbd: fix cleanup in rbd_add()
Bjorn Helgaas pointed out that a recent commit introduced a
use-after-free condition in an error path for rbd_add().
He correctly stated:
I think b536f69a3a5 "rbd: set up devices only for mapped images"
introduced a use-after-free error in rbd_add():
...
If rbd_dev_device_setup() returns an error, we call
rbd_dev_image_release(), which ultimately kfrees rbd_dev.
Then we call rbd_dev_destroy(), which references fields in
the already-freed rbd_dev struct before kfreeing it again.
The simple fix is to return the error code after the call to
rbd_dev_image_release().
Closer examination revealed that there's no need to clean up
rbd_opts in that function, so fix that too.
Update some other comments that have also become out of date.
Reported-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
-rw-r--r-- | drivers/block/rbd.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 5f64ba77bc7f..3a897a531e9c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -4700,8 +4700,10 @@ out: | |||
4700 | return ret; | 4700 | return ret; |
4701 | } | 4701 | } |
4702 | 4702 | ||
4703 | /* Undo whatever state changes are made by v1 or v2 image probe */ | 4703 | /* |
4704 | 4704 | * Undo whatever state changes are made by v1 or v2 header info | |
4705 | * call. | ||
4706 | */ | ||
4705 | static void rbd_dev_unprobe(struct rbd_device *rbd_dev) | 4707 | static void rbd_dev_unprobe(struct rbd_device *rbd_dev) |
4706 | { | 4708 | { |
4707 | struct rbd_image_header *header; | 4709 | struct rbd_image_header *header; |
@@ -4905,9 +4907,10 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) | |||
4905 | int tmp; | 4907 | int tmp; |
4906 | 4908 | ||
4907 | /* | 4909 | /* |
4908 | * Get the id from the image id object. If it's not a | 4910 | * Get the id from the image id object. Unless there's an |
4909 | * format 2 image, we'll get ENOENT back, and we'll assume | 4911 | * error, rbd_dev->spec->image_id will be filled in with |
4910 | * it's a format 1 image. | 4912 | * a dynamically-allocated string, and rbd_dev->image_format |
4913 | * will be set to either 1 or 2. | ||
4911 | */ | 4914 | */ |
4912 | ret = rbd_dev_image_id(rbd_dev); | 4915 | ret = rbd_dev_image_id(rbd_dev); |
4913 | if (ret) | 4916 | if (ret) |
@@ -5029,16 +5032,18 @@ static ssize_t rbd_add(struct bus_type *bus, | |||
5029 | rbd_dev->mapping.read_only = read_only; | 5032 | rbd_dev->mapping.read_only = read_only; |
5030 | 5033 | ||
5031 | rc = rbd_dev_device_setup(rbd_dev); | 5034 | rc = rbd_dev_device_setup(rbd_dev); |
5032 | if (!rc) | 5035 | if (rc) { |
5033 | return count; | 5036 | rbd_dev_image_release(rbd_dev); |
5037 | goto err_out_module; | ||
5038 | } | ||
5039 | |||
5040 | return count; | ||
5034 | 5041 | ||
5035 | rbd_dev_image_release(rbd_dev); | ||
5036 | err_out_rbd_dev: | 5042 | err_out_rbd_dev: |
5037 | rbd_dev_destroy(rbd_dev); | 5043 | rbd_dev_destroy(rbd_dev); |
5038 | err_out_client: | 5044 | err_out_client: |
5039 | rbd_put_client(rbdc); | 5045 | rbd_put_client(rbdc); |
5040 | err_out_args: | 5046 | err_out_args: |
5041 | kfree(rbd_opts); | ||
5042 | rbd_spec_put(spec); | 5047 | rbd_spec_put(spec); |
5043 | err_out_module: | 5048 | err_out_module: |
5044 | module_put(THIS_MODULE); | 5049 | module_put(THIS_MODULE); |