Skip to content

Commit cf47a83

Browse files
jbeulichkonradwilk
authored andcommitted
xen/hypercall: fix hypercall fallback code for very old hypervisors
While copying the argument structures in HYPERVISOR_event_channel_op() and HYPERVISOR_physdev_op() into the local variable is sufficiently safe even if the actual structure is smaller than the container one, copying back eventual output values the same way isn't: This may collide with on-stack variables (particularly "rc") which may change between the first and second memcpy() (i.e. the second memcpy() could discard that change). Move the fallback code into out-of-line functions, and handle all of the operations known by this old a hypervisor individually: Some don't require copying back anything at all, and for the rest use the individual argument structures' sizes rather than the container's. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Jan Beulich <jbeulich@suse.com> [v2: Reduce #define/#undef usage in HYPERVISOR_physdev_op_compat().] [v3: Fix compile errors when modules use said hypercalls] [v4: Add xen_ prefix to the HYPERCALL_..] [v5: Alter the name and only EXPORT_SYMBOL_GPL one of them] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
1 parent 95a7d76 commit cf47a83

3 files changed

Lines changed: 88 additions & 15 deletions

File tree

arch/x86/include/asm/xen/hypercall.h

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -359,18 +359,14 @@ HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
359359
return _hypercall4(int, update_va_mapping, va,
360360
new_val.pte, new_val.pte >> 32, flags);
361361
}
362+
extern int __must_check xen_event_channel_op_compat(int, void *);
362363

363364
static inline int
364365
HYPERVISOR_event_channel_op(int cmd, void *arg)
365366
{
366367
int rc = _hypercall2(int, event_channel_op, cmd, arg);
367-
if (unlikely(rc == -ENOSYS)) {
368-
struct evtchn_op op;
369-
op.cmd = cmd;
370-
memcpy(&op.u, arg, sizeof(op.u));
371-
rc = _hypercall1(int, event_channel_op_compat, &op);
372-
memcpy(arg, &op.u, sizeof(op.u));
373-
}
368+
if (unlikely(rc == -ENOSYS))
369+
rc = xen_event_channel_op_compat(cmd, arg);
374370
return rc;
375371
}
376372

@@ -386,17 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str)
386382
return _hypercall3(int, console_io, cmd, count, str);
387383
}
388384

385+
extern int __must_check HYPERVISOR_physdev_op_compat(int, void *);
386+
389387
static inline int
390388
HYPERVISOR_physdev_op(int cmd, void *arg)
391389
{
392390
int rc = _hypercall2(int, physdev_op, cmd, arg);
393-
if (unlikely(rc == -ENOSYS)) {
394-
struct physdev_op op;
395-
op.cmd = cmd;
396-
memcpy(&op.u, arg, sizeof(op.u));
397-
rc = _hypercall1(int, physdev_op_compat, &op);
398-
memcpy(arg, &op.u, sizeof(op.u));
399-
}
391+
if (unlikely(rc == -ENOSYS))
392+
rc = HYPERVISOR_physdev_op_compat(cmd, arg);
400393
return rc;
401394
}
402395

drivers/xen/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ ifneq ($(CONFIG_ARM),y)
22
obj-y += manage.o balloon.o
33
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
44
endif
5-
obj-y += grant-table.o features.o events.o
5+
obj-y += grant-table.o features.o events.o fallback.o
66
obj-y += xenbus/
77

88
nostackp := $(call cc-option, -fno-stack-protector)

drivers/xen/fallback.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <linux/kernel.h>
2+
#include <linux/string.h>
3+
#include <linux/bug.h>
4+
#include <linux/export.h>
5+
#include <asm/hypervisor.h>
6+
#include <asm/xen/hypercall.h>
7+
8+
int xen_event_channel_op_compat(int cmd, void *arg)
9+
{
10+
struct evtchn_op op;
11+
int rc;
12+
13+
op.cmd = cmd;
14+
memcpy(&op.u, arg, sizeof(op.u));
15+
rc = _hypercall1(int, event_channel_op_compat, &op);
16+
17+
switch (cmd) {
18+
case EVTCHNOP_close:
19+
case EVTCHNOP_send:
20+
case EVTCHNOP_bind_vcpu:
21+
case EVTCHNOP_unmask:
22+
/* no output */
23+
break;
24+
25+
#define COPY_BACK(eop) \
26+
case EVTCHNOP_##eop: \
27+
memcpy(arg, &op.u.eop, sizeof(op.u.eop)); \
28+
break
29+
30+
COPY_BACK(bind_interdomain);
31+
COPY_BACK(bind_virq);
32+
COPY_BACK(bind_pirq);
33+
COPY_BACK(status);
34+
COPY_BACK(alloc_unbound);
35+
COPY_BACK(bind_ipi);
36+
#undef COPY_BACK
37+
38+
default:
39+
WARN_ON(rc != -ENOSYS);
40+
break;
41+
}
42+
43+
return rc;
44+
}
45+
EXPORT_SYMBOL_GPL(xen_event_channel_op_compat);
46+
47+
int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
48+
{
49+
struct physdev_op op;
50+
int rc;
51+
52+
op.cmd = cmd;
53+
memcpy(&op.u, arg, sizeof(op.u));
54+
rc = _hypercall1(int, physdev_op_compat, &op);
55+
56+
switch (cmd) {
57+
case PHYSDEVOP_IRQ_UNMASK_NOTIFY:
58+
case PHYSDEVOP_set_iopl:
59+
case PHYSDEVOP_set_iobitmap:
60+
case PHYSDEVOP_apic_write:
61+
/* no output */
62+
break;
63+
64+
#define COPY_BACK(pop, fld) \
65+
case PHYSDEVOP_##pop: \
66+
memcpy(arg, &op.u.fld, sizeof(op.u.fld)); \
67+
break
68+
69+
COPY_BACK(irq_status_query, irq_status_query);
70+
COPY_BACK(apic_read, apic_op);
71+
COPY_BACK(ASSIGN_VECTOR, irq_op);
72+
#undef COPY_BACK
73+
74+
default:
75+
WARN_ON(rc != -ENOSYS);
76+
break;
77+
}
78+
79+
return rc;
80+
}

0 commit comments

Comments
 (0)