1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
|
From 8dc90d163650ce8aa36ae0b46debab83cc61edb6 Mon Sep 17 00:00:00 2001
From: Ian Jackson <ian.jackson@eu.citrix.com>
Date: Fri, 14 Jun 2013 16:43:19 +0100
Subject: [PATCH 20/23] libxc: check return values from malloc
A sufficiently malformed input to libxc (such as a malformed input ELF
or other guest-controlled data) might cause one of libxc's malloc() to
fail. In this case we need to make sure we don't dereference or do
pointer arithmetic on the result.
Search for all occurrences of \b(m|c|re)alloc in libxc, and all
functions which call them, and add appropriate error checking where
missing.
This includes the functions xc_dom_malloc*, which now print a message
when they fail so that callers don't have to do so.
The function xc_cpuid_to_str wasn't provided with a sane return value
and has a pretty strange API, which now becomes a little stranger.
There are no in-tree callers.
Changes in the Xen 4.2 version of this series:
* No need to fix code relating to ARM.
* No need to fix code relating to superpage support.
* Additionally fix `dom->p2m_host = xc_dom_malloc...' in xc_dom_ia64.c.
This is part of the fix to a security issue, XSA-55.
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
---
tools/libxc/xc_cpuid_x86.c | 20 ++++++++++++++++++--
tools/libxc/xc_dom_core.c | 13 +++++++++++++
tools/libxc/xc_dom_elfloader.c | 2 ++
tools/libxc/xc_dom_ia64.c | 6 ++++++
tools/libxc/xc_dom_x86.c | 3 +++
tools/libxc/xc_domain_restore.c | 5 +++++
tools/libxc/xc_linux_osdep.c | 4 ++++
tools/libxc/xc_private.c | 2 ++
tools/libxc/xenctrl.h | 2 +-
9 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
index 0882ce6..da435ce 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -589,6 +589,8 @@ static int xc_cpuid_do_domctl(
static char *alloc_str(void)
{
char *s = malloc(33);
+ if ( s == NULL )
+ return s;
memset(s, 0, 33);
return s;
}
@@ -600,6 +602,8 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs)
for ( i = 0; i < 4; i++ )
{
strs[i] = alloc_str();
+ if ( strs[i] == NULL )
+ continue;
for ( j = 0; j < 32; j++ )
strs[i][j] = !!((regs[i] & (1U << (31 - j)))) ? '1' : '0';
}
@@ -680,7 +684,7 @@ int xc_cpuid_check(
const char **config,
char **config_transformed)
{
- int i, j;
+ int i, j, rc;
unsigned int regs[4];
memset(config_transformed, 0, 4 * sizeof(*config_transformed));
@@ -692,6 +696,11 @@ int xc_cpuid_check(
if ( config[i] == NULL )
continue;
config_transformed[i] = alloc_str();
+ if ( config_transformed[i] == NULL )
+ {
+ rc = -ENOMEM;
+ goto fail_rc;
+ }
for ( j = 0; j < 32; j++ )
{
unsigned char val = !!((regs[i] & (1U << (31 - j))));
@@ -708,12 +717,14 @@ int xc_cpuid_check(
return 0;
fail:
+ rc = -EPERM;
+ fail_rc:
for ( i = 0; i < 4; i++ )
{
free(config_transformed[i]);
config_transformed[i] = NULL;
}
- return -EPERM;
+ return rc;
}
/*
@@ -758,6 +769,11 @@ int xc_cpuid_set(
}
config_transformed[i] = alloc_str();
+ if ( config_transformed[i] == NULL )
+ {
+ rc = -ENOMEM;
+ goto fail;
+ }
for ( j = 0; j < 32; j++ )
{
diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
index a54ddae..3cbf9f7 100644
--- a/tools/libxc/xc_dom_core.c
+++ b/tools/libxc/xc_dom_core.c
@@ -120,9 +120,17 @@ void *xc_dom_malloc(struct xc_dom_image *dom, size_t size)
{
struct xc_dom_mem *block;
+ if ( size > SIZE_MAX - sizeof(*block) )
+ {
+ DOMPRINTF("%s: unreasonable allocation size", __FUNCTION__);
+ return NULL;
+ }
block = malloc(sizeof(*block) + size);
if ( block == NULL )
+ {
+ DOMPRINTF("%s: allocation failed", __FUNCTION__);
return NULL;
+ }
memset(block, 0, sizeof(*block) + size);
block->next = dom->memblocks;
dom->memblocks = block;
@@ -138,7 +146,10 @@ void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
block = malloc(sizeof(*block));
if ( block == NULL )
+ {
+ DOMPRINTF("%s: allocation failed", __FUNCTION__);
return NULL;
+ }
memset(block, 0, sizeof(*block));
block->mmap_len = size;
block->mmap_ptr = mmap(NULL, block->mmap_len,
@@ -146,6 +157,7 @@ void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
-1, 0);
if ( block->mmap_ptr == MAP_FAILED )
{
+ DOMPRINTF("%s: mmap failed", __FUNCTION__);
free(block);
return NULL;
}
@@ -202,6 +214,7 @@ void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
close(fd);
if ( block != NULL )
free(block);
+ DOMPRINTF("%s: failed (on file `%s')", __FUNCTION__, filename);
return NULL;
}
diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c
index 61b5798..be58276 100644
--- a/tools/libxc/xc_dom_elfloader.c
+++ b/tools/libxc/xc_dom_elfloader.c
@@ -329,6 +329,8 @@ static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
return rc;
elf = xc_dom_malloc(dom, sizeof(*elf));
+ if ( elf == NULL )
+ return -1;
dom->private_loader = elf;
rc = elf_init(elf, dom->kernel_blob, dom->kernel_size);
xc_elf_set_logfile(dom->xch, elf, 1);
diff --git a/tools/libxc/xc_dom_ia64.c b/tools/libxc/xc_dom_ia64.c
index 7c0eff1..076821c 100644
--- a/tools/libxc/xc_dom_ia64.c
+++ b/tools/libxc/xc_dom_ia64.c
@@ -188,6 +188,12 @@ int arch_setup_meminit(struct xc_dom_image *dom)
/* setup initial p2m */
dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * nbr);
+ if ( dom->p2m_host == NULL )
+ {
+ DOMPRINTF("%s: xc_dom_malloc failed for p2m_host",
+ __FUNCTION__);
+ return -1;
+ }
for ( pfn = 0; pfn < nbr; pfn++ )
dom->p2m_host[pfn] = start + pfn;
diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c
index 75d6b83..448d9a1 100644
--- a/tools/libxc/xc_dom_x86.c
+++ b/tools/libxc/xc_dom_x86.c
@@ -780,6 +780,9 @@ int arch_setup_meminit(struct xc_dom_image *dom)
}
dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages);
+ if ( dom->p2m_host == NULL )
+ return -EINVAL;
+
if ( dom->superpages )
{
int count = dom->total_pages >> SUPERPAGE_PFN_SHIFT;
diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c
index 3994f8f..f9ed6b2 100644
--- a/tools/libxc/xc_domain_restore.c
+++ b/tools/libxc/xc_domain_restore.c
@@ -1180,6 +1180,11 @@ static int apply_batch(xc_interface *xch, uint32_t dom, struct restore_ctx *ctx,
/* Map relevant mfns */
pfn_err = calloc(j, sizeof(*pfn_err));
+ if ( pfn_err == NULL )
+ {
+ PERROR("allocation for pfn_err failed");
+ return -1;
+ }
region_base = xc_map_foreign_bulk(
xch, dom, PROT_WRITE, region_mfn, pfn_err, j);
diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
index 787e742..98e041c 100644
--- a/tools/libxc/xc_linux_osdep.c
+++ b/tools/libxc/xc_linux_osdep.c
@@ -378,6 +378,8 @@ static void *linux_privcmd_map_foreign_range(xc_interface *xch, xc_osdep_handle
num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT;
arr = calloc(num, sizeof(xen_pfn_t));
+ if ( arr == NULL )
+ return NULL;
for ( i = 0; i < num; i++ )
arr[i] = mfn + i;
@@ -402,6 +404,8 @@ static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle
num_per_entry = chunksize >> XC_PAGE_SHIFT;
num = num_per_entry * nentries;
arr = calloc(num, sizeof(xen_pfn_t));
+ if ( arr == NULL )
+ return NULL;
for ( i = 0; i < nentries; i++ )
for ( j = 0; j < num_per_entry; j++ )
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index 3e03a91..848ceed 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -771,6 +771,8 @@ const char *xc_strerror(xc_interface *xch, int errcode)
errbuf = pthread_getspecific(errbuf_pkey);
if (errbuf == NULL) {
errbuf = malloc(XS_BUFSIZE);
+ if ( errbuf == NULL )
+ return "(failed to allocate errbuf)";
pthread_setspecific(errbuf_pkey, errbuf);
}
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index b7741ca..8952048 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1778,7 +1778,7 @@ int xc_cpuid_set(xc_interface *xch,
int xc_cpuid_apply_policy(xc_interface *xch,
domid_t domid);
void xc_cpuid_to_str(const unsigned int *regs,
- char **strs);
+ char **strs); /* some strs[] may be NULL if ENOMEM */
int xc_mca_op(xc_interface *xch, struct xen_mc *mc);
#endif
--
1.7.2.5
#From 052a689aa526ca51fd70528d4b0f83dfb2de99c1 Mon Sep 17 00:00:00 2001
#From: Ian Jackson <ian.jackson@eu.citrix.com>
#Date: Fri, 14 Jun 2013 16:43:19 +0100
#Subject: [PATCH 21/23] libxc: range checks in xc_dom_p2m_host and _guest
#
#These functions take guest pfns and look them up in the p2m. They did
#no range checking.
#
#However, some callers, notably xc_dom_boot.c:setup_hypercall_page want
#to pass untrusted guest-supplied value(s). It is most convenient to
#detect this here and return INVALID_MFN.
#
#This is part of the fix to a security issue, XSA-55.
#
#Changes from Xen 4.2 version of this patch:
#* 4.2 lacks dom->rambase_pfn, so don't add/subtract/check it.
#
#Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
#---
# tools/libxc/xc_dom.h | 4 ++++
# 1 files changed, 4 insertions(+), 0 deletions(-)
#
diff --git a/tools/libxc/xc_dom.h b/tools/libxc/xc_dom.h
index 0161459..d801f66 100644
--- a/tools/libxc/xc_dom.h
+++ b/tools/libxc/xc_dom.h
@@ -331,6 +331,8 @@ static inline xen_pfn_t xc_dom_p2m_host(struct xc_dom_image *dom, xen_pfn_t pfn)
{
if (dom->shadow_enabled)
return pfn;
+ if (pfn >= dom->total_pages)
+ return INVALID_MFN;
return dom->p2m_host[pfn];
}
@@ -339,6 +341,8 @@ static inline xen_pfn_t xc_dom_p2m_guest(struct xc_dom_image *dom,
{
if (xc_dom_feature_translated(dom))
return pfn;
+ if (pfn >= dom->total_pages)
+ return INVALID_MFN;
return dom->p2m_host[pfn];
}
--
1.7.2.5
#From 2a548e22915535ac13694eb38222903bca7245e3 Mon Sep 17 00:00:00 2001
#From: Matthew Daley <mattjd@gmail.com>
#Date: Fri, 14 Jun 2013 16:43:19 +0100
#Subject: [PATCH 22/23] libxc: check blob size before proceeding in xc_dom_check_gzip
#
#This is part of the fix to a security issue, XSA-55.
#
#Signed-off-by: Matthew Daley <mattjd@gmail.com>
#---
# tools/libxc/xc_dom_core.c | 5 +++++
# 1 files changed, 5 insertions(+), 0 deletions(-)
#
diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
index 3cbf9f7..f8d1b08 100644
--- a/tools/libxc/xc_dom_core.c
+++ b/tools/libxc/xc_dom_core.c
@@ -284,6 +284,11 @@ size_t xc_dom_check_gzip(xc_interface *xch, void *blob, size_t ziplen)
unsigned char *gzlen;
size_t unziplen;
+ if ( ziplen < 6 )
+ /* Too small. We need (i.e. the subsequent code relies on)
+ * 2 bytes for the magic number plus 4 bytes length. */
+ return 0;
+
if ( strncmp(blob, "\037\213", 2) )
/* not gzipped */
return 0;
--
1.7.2.5
#From d21d36e84354c04638b60a739a5f7c3d9f8adaf8 Mon Sep 17 00:00:00 2001
#From: Ian Jackson <ian.jackson@eu.citrix.com>
#Date: Fri, 14 Jun 2013 16:43:19 +0100
#Subject: [PATCH 23/23] libxc: Better range check in xc_dom_alloc_segment
#
#If seg->pfn is too large, the arithmetic in the range check might
#overflow, defeating the range check.
#
#This is part of the fix to a security issue, XSA-55.
#
#Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
#Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
#---
# tools/libxc/xc_dom_core.c | 3 ++-
# 1 files changed, 2 insertions(+), 1 deletions(-)
#
diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
index f8d1b08..e79e38d 100644
--- a/tools/libxc/xc_dom_core.c
+++ b/tools/libxc/xc_dom_core.c
@@ -509,7 +509,8 @@ int xc_dom_alloc_segment(struct xc_dom_image *dom,
seg->vstart = start;
seg->pfn = (seg->vstart - dom->parms.virt_base) / page_size;
- if ( pages > dom->total_pages || /* double test avoids overflow probs */
+ if ( pages > dom->total_pages || /* multiple test avoids overflow probs */
+ seg->pfn > dom->total_pages ||
pages > dom->total_pages - seg->pfn)
{
xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY,
--
1.7.2.5
|