]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.14.57/rbd-prevent-kernel-stack-blow-up-on-rbd-map.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.14.57 / rbd-prevent-kernel-stack-blow-up-on-rbd-map.patch
CommitLineData
b75945de
GKH
1From 6d69bb536bac0d403d83db1ca841444981b280cd Mon Sep 17 00:00:00 2001
2From: Ilya Dryomov <idryomov@gmail.com>
3Date: Sun, 11 Oct 2015 19:38:00 +0200
4Subject: rbd: prevent kernel stack blow up on rbd map
5
6From: Ilya Dryomov <idryomov@gmail.com>
7
8commit 6d69bb536bac0d403d83db1ca841444981b280cd upstream.
9
10Mapping an image with a long parent chain (e.g. image foo, whose parent
11is bar, whose parent is baz, etc) currently leads to a kernel stack
12overflow, due to the following recursion in the reply path:
13
14 rbd_osd_req_callback()
15 rbd_obj_request_complete()
16 rbd_img_obj_callback()
17 rbd_img_parent_read_callback()
18 rbd_obj_request_complete()
19 ...
20
21Limit the parent chain to 16 images, which is ~5K worth of stack. When
22the above recursion is eliminated, this limit can be lifted.
23
24Fixes: http://tracker.ceph.com/issues/12538
25
26Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
27Reviewed-by: Josh Durgin <jdurgin@redhat.com>
28[idryomov@gmail.com: backport to 3.14: rbd_dev->opts, context]
29Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
30
31---
32 drivers/block/rbd.c | 29 +++++++++++++++++++++--------
33 1 file changed, 21 insertions(+), 8 deletions(-)
34
35--- a/drivers/block/rbd.c
36+++ b/drivers/block/rbd.c
37@@ -94,6 +94,8 @@ static int atomic_dec_return_safe(atomic
38 #define RBD_MINORS_PER_MAJOR 256
39 #define RBD_SINGLE_MAJOR_PART_SHIFT 4
40
41+#define RBD_MAX_PARENT_CHAIN_LEN 16
42+
43 #define RBD_SNAP_DEV_NAME_PREFIX "snap_"
44 #define RBD_MAX_SNAP_NAME_LEN \
45 (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1))
46@@ -411,7 +413,7 @@ static ssize_t rbd_add_single_major(stru
47 size_t count);
48 static ssize_t rbd_remove_single_major(struct bus_type *bus, const char *buf,
49 size_t count);
50-static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping);
51+static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth);
52 static void rbd_spec_put(struct rbd_spec *spec);
53
54 static int rbd_dev_id_to_minor(int dev_id)
55@@ -4822,7 +4824,12 @@ out_err:
56 return ret;
57 }
58
59-static int rbd_dev_probe_parent(struct rbd_device *rbd_dev)
60+/*
61+ * @depth is rbd_dev_image_probe() -> rbd_dev_probe_parent() ->
62+ * rbd_dev_image_probe() recursion depth, which means it's also the
63+ * length of the already discovered part of the parent chain.
64+ */
65+static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
66 {
67 struct rbd_device *parent = NULL;
68 int ret;
69@@ -4830,6 +4837,12 @@ static int rbd_dev_probe_parent(struct r
70 if (!rbd_dev->parent_spec)
71 return 0;
72
73+ if (++depth > RBD_MAX_PARENT_CHAIN_LEN) {
74+ pr_info("parent chain is too long (%d)\n", depth);
75+ ret = -EINVAL;
76+ goto out_err;
77+ }
78+
79 parent = rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
80 if (!parent) {
81 ret = -ENOMEM;
82@@ -4843,7 +4856,7 @@ static int rbd_dev_probe_parent(struct r
83 __rbd_get_client(rbd_dev->rbd_client);
84 rbd_spec_get(rbd_dev->parent_spec);
85
86- ret = rbd_dev_image_probe(parent, false);
87+ ret = rbd_dev_image_probe(parent, depth);
88 if (ret < 0)
89 goto out_err;
90
91@@ -4970,7 +4983,7 @@ static void rbd_dev_image_release(struct
92 * parent), initiate a watch on its header object before using that
93 * object to get detailed information about the rbd image.
94 */
95-static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
96+static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
97 {
98 int ret;
99
100@@ -4990,7 +5003,7 @@ static int rbd_dev_image_probe(struct rb
101 if (ret)
102 goto err_out_format;
103
104- if (mapping) {
105+ if (!depth) {
106 ret = rbd_dev_header_watch_sync(rbd_dev);
107 if (ret)
108 goto out_header_name;
109@@ -5007,7 +5020,7 @@ static int rbd_dev_image_probe(struct rb
110 if (ret)
111 goto err_out_probe;
112
113- ret = rbd_dev_probe_parent(rbd_dev);
114+ ret = rbd_dev_probe_parent(rbd_dev, depth);
115 if (ret)
116 goto err_out_probe;
117
118@@ -5018,7 +5031,7 @@ static int rbd_dev_image_probe(struct rb
119 err_out_probe:
120 rbd_dev_unprobe(rbd_dev);
121 err_out_watch:
122- if (mapping)
123+ if (!depth)
124 rbd_dev_header_unwatch_sync(rbd_dev);
125 out_header_name:
126 kfree(rbd_dev->header_name);
127@@ -5085,7 +5098,7 @@ static ssize_t do_rbd_add(struct bus_typ
128 rbdc = NULL; /* rbd_dev now owns this */
129 spec = NULL; /* rbd_dev now owns this */
130
131- rc = rbd_dev_image_probe(rbd_dev, true);
132+ rc = rbd_dev_image_probe(rbd_dev, 0);
133 if (rc < 0)
134 goto err_out_rbd_dev;
135