1
From 13069a4017d36a549576a21ca3ec5b15c411effc Mon Sep 17 00:00:00 2001
2
From: Zhi Yan Liu <zhiyanl@cn.ibm.com>
3
Date: Sat, 29 Mar 2014 03:35:35 +0800
4
Subject: [PATCH 23/23] To prevent remote code injection on Sheepdog store
6
Change-Id: Iae92eaf9eb023f36a1bab7c20ea41c985f2bf51b
7
Signed-off-by: Zhi Yan Liu <zhiyanl@cn.ibm.com>
8
diff -Naurp glance-2013.2.3.orig/glance/store/sheepdog.py glance-2013.2.3/glance/store/sheepdog.py
9
--- glance-2013.2.3.orig/glance/store/sheepdog.py 2014-04-03 14:43:55.000000000 -0400
10
+++ glance-2013.2.3/glance/store/sheepdog.py 2014-04-11 10:15:46.137975403 -0400
11
@@ -25,6 +25,7 @@ from glance.common import exception
12
from glance.openstack.common import excutils
13
import glance.openstack.common.log as logging
14
from glance.openstack.common import processutils
15
+from glance.openstack.common import uuidutils
17
import glance.store.base
18
import glance.store.location
19
@@ -32,7 +33,7 @@ import glance.store.location
21
LOG = logging.getLogger(__name__)
23
-DEFAULT_ADDR = 'localhost'
24
+DEFAULT_ADDR = '127.0.0.1'
26
DEFAULT_CHUNKSIZE = 64 # in MiB
28
@@ -63,18 +64,14 @@ class SheepdogImage:
29
self.chunk_size = chunk_size
31
def _run_command(self, command, data, *params):
32
- cmd = ("collie vdi %(command)s -a %(addr)s -p %(port)s %(name)s "
34
- {"command": command,
38
- "params": " ".join(map(str, params))})
39
+ cmd = ["collie", "vdi"]
41
+ cmd.extend(["-a", self.addr, "-p", self.port, self.name])
45
- return processutils.execute(
46
- cmd, process_input=data, shell=True)[0]
47
- except processutils.ProcessExecutionError as exc:
48
+ return processutils.execute(*cmd, process_input=data)[0]
49
+ except (processutils.ProcessExecutionError, OSError) as exc:
51
raise glance.store.BackendException(exc)
53
@@ -84,7 +81,7 @@ class SheepdogImage:
55
Sheepdog Usage: collie vdi list -r -a address -p port image
57
- out = self._run_command("list -r", None)
58
+ out = self._run_command(["list", "-r"], None)
59
return long(out.split(' ')[3])
61
def read(self, offset, count):
62
@@ -94,7 +91,7 @@ class SheepdogImage:
64
Sheepdog Usage: collie vdi read -a address -p port image offset len
66
- return self._run_command("read", None, str(offset), str(count))
67
+ return self._run_command(["read"], None, str(offset), str(count))
69
def write(self, data, offset, count):
71
@@ -103,7 +100,7 @@ class SheepdogImage:
73
Sheepdog Usage: collie vdi write -a address -p port image offset len
75
- self._run_command("write", data, str(offset), str(count))
76
+ self._run_command(["write"], data, str(offset), str(count))
78
def create(self, size):
80
@@ -111,7 +108,7 @@ class SheepdogImage:
82
Sheepdog Usage: collie vdi create -a address -p port image size
84
- self._run_command("create", None, str(size))
85
+ self._run_command(["create"], None, str(size))
89
@@ -119,7 +116,7 @@ class SheepdogImage:
91
Sheepdog Usage: collie vdi delete -a address -p port image
93
- self._run_command("delete", None)
94
+ self._run_command(["delete"], None)
98
@@ -127,7 +124,7 @@ class SheepdogImage:
100
Sheepdog Usage: collie vdi list -r -a address -p port image
102
- out = self._run_command("list -r", None)
103
+ out = self._run_command(["list", "-r"], None)
107
@@ -138,7 +135,7 @@ class StoreLocation(glance.store.locatio
109
Class describing a Sheepdog URI. This is of the form:
112
+ sheepdog://image-id
116
@@ -149,10 +146,14 @@ class StoreLocation(glance.store.locatio
117
return "sheepdog://%s" % self.image
119
def parse_uri(self, uri):
120
- if not uri.startswith('sheepdog://'):
121
- raise exception.BadStoreUri(uri, "URI must start with %s://" %
123
- self.image = uri[11:]
124
+ valid_schema = 'sheepdog://'
125
+ if not uri.startswith(valid_schema):
126
+ raise exception.BadStoreUri(_("URI must start with %s://") %
128
+ self.image = uri[len(valid_schema):]
129
+ if not uuidutils.is_uuid_like(self.image):
130
+ raise exception.BadStoreUri(_("URI must contains well-formated "
134
class ImageIterator(object):
135
@@ -192,7 +193,7 @@ class Store(glance.store.base.Store):
138
self.chunk_size = CONF.sheepdog_store_chunk_size * 1024 * 1024
139
- self.addr = CONF.sheepdog_store_address
140
+ self.addr = CONF.sheepdog_store_address.strip()
141
self.port = CONF.sheepdog_store_port
142
except cfg.ConfigFileValueError as e:
143
reason = _("Error in store configuration: %s") % e
144
@@ -200,10 +201,18 @@ class Store(glance.store.base.Store):
145
raise exception.BadStoreConfiguration(store_name='sheepdog',
148
+ if ' ' in self.addr:
149
+ reason = (_("Invalid address configuration of sheepdog store: %s")
152
+ raise exception.BadStoreConfiguration(store_name='sheepdog',
156
- processutils.execute("collie", shell=True)
157
- except processutils.ProcessExecutionError as exc:
158
- reason = _("Error in store configuration: %s") % exc
159
+ cmd = ["collie", "vdi", "list", "-a", self.addr, "-p", self.port]
160
+ processutils.execute(*cmd)
161
+ except Exception as e:
162
+ reason = _("Error in store configuration: %s") % e
164
raise exception.BadStoreConfiguration(store_name='sheepdog',
166
diff -Naurp glance-2013.2.3.orig/glance/tests/unit/test_sheepdog_store.py glance-2013.2.3/glance/tests/unit/test_sheepdog_store.py
167
--- glance-2013.2.3.orig/glance/tests/unit/test_sheepdog_store.py 2014-04-03 14:43:55.000000000 -0400
168
+++ glance-2013.2.3/glance/tests/unit/test_sheepdog_store.py 2014-04-11 10:15:46.137975403 -0400
169
@@ -57,4 +57,5 @@ class TestStore(base.StoreClearingUnitTe
171
utils.LimitingReader(StringIO.StringIO('xx'), 1),
173
- self.assertEqual(called_commands, ['list -r', 'create', 'delete'])
174
+ self.assertEqual([['list', '-r'], ['create'], ['delete']],
176
diff -Naurp glance-2013.2.3.orig/glance/tests/unit/test_store_location.py glance-2013.2.3/glance/tests/unit/test_store_location.py
177
--- glance-2013.2.3.orig/glance/tests/unit/test_store_location.py 2014-04-03 14:43:55.000000000 -0400
178
+++ glance-2013.2.3/glance/tests/unit/test_store_location.py 2014-04-11 10:15:46.141975403 -0400
179
@@ -52,7 +52,7 @@ class TestStoreLocation(base.StoreCleari
181
'rbd://fsid/pool/image/snap',
182
'rbd://%2F/%2F/%2F/%2F',
183
- 'sheepdog://imagename',
184
+ 'sheepdog://244e75f1-9c69-4167-9db7-1aa7d1973f6c',
185
'cinder://12345678-9012-3455-6789-012345678901',
188
@@ -367,15 +367,18 @@ class TestStoreLocation(base.StoreCleari
190
Test the specific StoreLocation for the Sheepdog store
192
- uri = 'sheepdog://imagename'
193
+ uri = 'sheepdog://244e75f1-9c69-4167-9db7-1aa7d1973f6c'
194
loc = glance.store.sheepdog.StoreLocation({})
196
- self.assertEqual('imagename', loc.image)
197
+ self.assertEqual('244e75f1-9c69-4167-9db7-1aa7d1973f6c', loc.image)
199
- bad_uri = 'sheepdog:/image'
200
+ bad_uri = 'sheepdog:/244e75f1-9c69-4167-9db7-1aa7d1973f6c'
201
self.assertRaises(exception.BadStoreUri, loc.parse_uri, bad_uri)
203
- bad_uri = 'http://image'
204
+ bad_uri = 'http://244e75f1-9c69-4167-9db7-1aa7d1973f6c'
205
+ self.assertRaises(exception.BadStoreUri, loc.parse_uri, bad_uri)
207
+ bad_uri = 'image; name'
208
self.assertRaises(exception.BadStoreUri, loc.parse_uri, bad_uri)
210
def test_cinder_store_good_location(self):