ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @ 8820:605672867c0f

Check the hypercall number in the privcmd hypercall ioctl.
We check it is a member of a small set of permitted hypercalls.
Fix libxenstat to not use multicalls (not permitted, and not
need for efficiency in libxenstat).

Based on an original patch by Chris Wright.

Signed-off-by: Keir Fraser <keir@xensource.com>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
author kaf24@firebug.cl.cam.ac.uk
date Fri Feb 10 00:16:53 2006 +0100 (2006-02-10)
parents c9edeb3bd652
children b128f55ca05c
line source
1 /******************************************************************************
2 * privcmd.c
3 *
4 * Interface to privileged domain-0 commands.
5 *
6 * Copyright (c) 2002-2004, K A Fraser, B Dragovic
7 */
9 #include <linux/config.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
14 #include <linux/errno.h>
15 #include <linux/mm.h>
16 #include <linux/mman.h>
17 #include <linux/swap.h>
18 #include <linux/smp_lock.h>
19 #include <linux/highmem.h>
20 #include <linux/pagemap.h>
21 #include <linux/seq_file.h>
22 #include <linux/kthread.h>
23 #include <asm/hypervisor.h>
25 #include <asm/pgalloc.h>
26 #include <asm/pgtable.h>
27 #include <asm/uaccess.h>
28 #include <asm/tlb.h>
29 #include <asm/hypervisor.h>
30 #include <xen/public/privcmd.h>
31 #include <xen/interface/xen.h>
32 #include <xen/interface/dom0_ops.h>
33 #include <xen/xen_proc.h>
35 static struct proc_dir_entry *privcmd_intf;
36 static struct proc_dir_entry *capabilities_intf;
38 #define NR_HYPERCALLS 32
39 static DECLARE_BITMAP(hypercall_permission_map, NR_HYPERCALLS);
41 static int privcmd_ioctl(struct inode *inode, struct file *file,
42 unsigned int cmd, unsigned long data)
43 {
44 int ret = -ENOSYS;
45 void __user *udata = (void __user *) data;
47 switch (cmd) {
48 case IOCTL_PRIVCMD_HYPERCALL: {
49 privcmd_hypercall_t hypercall;
51 if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
52 return -EFAULT;
54 /* Check hypercall number for validity. */
55 if (hypercall.op >= NR_HYPERCALLS)
56 return -EINVAL;
57 if (!test_bit(hypercall.op, hypercall_permission_map))
58 return -EINVAL;
60 #if defined(__i386__)
61 __asm__ __volatile__ (
62 "pushl %%ebx; pushl %%ecx; pushl %%edx; "
63 "pushl %%esi; pushl %%edi; "
64 "movl 4(%%eax),%%ebx ;"
65 "movl 8(%%eax),%%ecx ;"
66 "movl 12(%%eax),%%edx ;"
67 "movl 16(%%eax),%%esi ;"
68 "movl 20(%%eax),%%edi ;"
69 "movl (%%eax),%%eax ;"
70 "shll $5,%%eax ;"
71 "addl $hypercall_page,%%eax ;"
72 "call *%%eax ;"
73 "popl %%edi; popl %%esi; popl %%edx; "
74 "popl %%ecx; popl %%ebx"
75 : "=a" (ret) : "0" (&hypercall) : "memory" );
76 #elif defined (__x86_64__)
77 {
78 long ign1, ign2, ign3;
79 __asm__ __volatile__ (
80 "movq %8,%%r10; movq %9,%%r8;"
81 "shlq $5,%%rax ;"
82 "addq $hypercall_page,%%rax ;"
83 "call *%%rax"
84 : "=a" (ret), "=D" (ign1),
85 "=S" (ign2), "=d" (ign3)
86 : "0" ((unsigned long)hypercall.op),
87 "1" ((unsigned long)hypercall.arg[0]),
88 "2" ((unsigned long)hypercall.arg[1]),
89 "3" ((unsigned long)hypercall.arg[2]),
90 "g" ((unsigned long)hypercall.arg[3]),
91 "g" ((unsigned long)hypercall.arg[4])
92 : "r8", "r10", "memory" );
93 }
94 #elif defined (__ia64__)
95 __asm__ __volatile__ (
96 ";; mov r14=%2; mov r15=%3; "
97 "mov r16=%4; mov r17=%5; mov r18=%6;"
98 "mov r2=%1; break 0x1000;; mov %0=r8 ;;"
99 : "=r" (ret)
100 : "r" (hypercall.op),
101 "r" (hypercall.arg[0]),
102 "r" (hypercall.arg[1]),
103 "r" (hypercall.arg[2]),
104 "r" (hypercall.arg[3]),
105 "r" (hypercall.arg[4])
106 : "r14","r15","r16","r17","r18","r2","r8","memory");
107 #endif
108 }
109 break;
111 #if defined(CONFIG_XEN_PRIVILEGED_GUEST)
112 case IOCTL_PRIVCMD_MMAP: {
113 #define PRIVCMD_MMAP_SZ 32
114 privcmd_mmap_t mmapcmd;
115 privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ];
116 privcmd_mmap_entry_t __user *p;
117 int i, rc;
119 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
120 return -EFAULT;
122 p = mmapcmd.entry;
124 for (i = 0; i < mmapcmd.num;
125 i += PRIVCMD_MMAP_SZ, p += PRIVCMD_MMAP_SZ) {
126 int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
127 PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
129 if (copy_from_user(&msg, p,
130 n*sizeof(privcmd_mmap_entry_t)))
131 return -EFAULT;
133 for (j = 0; j < n; j++) {
134 struct vm_area_struct *vma =
135 find_vma( current->mm, msg[j].va );
137 if (!vma)
138 return -EINVAL;
140 if (msg[j].va > PAGE_OFFSET)
141 return -EINVAL;
143 if ((msg[j].va + (msg[j].npages << PAGE_SHIFT))
144 > vma->vm_end )
145 return -EINVAL;
147 if ((rc = direct_remap_pfn_range(
148 vma,
149 msg[j].va&PAGE_MASK,
150 msg[j].mfn,
151 msg[j].npages<<PAGE_SHIFT,
152 vma->vm_page_prot,
153 mmapcmd.dom)) < 0)
154 return rc;
155 }
156 }
157 ret = 0;
158 }
159 break;
161 case IOCTL_PRIVCMD_MMAPBATCH: {
162 mmu_update_t u;
163 privcmd_mmapbatch_t m;
164 struct vm_area_struct *vma = NULL;
165 unsigned long __user *p;
166 unsigned long addr, mfn;
167 uint64_t ptep;
168 int i;
170 if (copy_from_user(&m, udata, sizeof(m))) {
171 ret = -EFAULT;
172 goto batch_err;
173 }
175 if (m.dom == DOMID_SELF) {
176 ret = -EINVAL;
177 goto batch_err;
178 }
180 vma = find_vma(current->mm, m.addr);
181 if (!vma) {
182 ret = -EINVAL;
183 goto batch_err;
184 }
186 if (m.addr > PAGE_OFFSET) {
187 ret = -EFAULT;
188 goto batch_err;
189 }
191 if ((m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end) {
192 ret = -EFAULT;
193 goto batch_err;
194 }
196 p = m.arr;
197 addr = m.addr;
198 for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
199 if (get_user(mfn, p))
200 return -EFAULT;
201 #ifdef __ia64__
202 ret = remap_pfn_range(vma,
203 addr&PAGE_MASK,
204 mfn,
205 1<<PAGE_SHIFT,
206 vma->vm_page_prot);
207 if (ret < 0)
208 goto batch_err;
209 #else
211 ret = create_lookup_pte_addr(vma->vm_mm, addr, &ptep);
212 if (ret)
213 goto batch_err;
215 u.val = pte_val_ma(pfn_pte_ma(mfn, vma->vm_page_prot));
216 u.ptr = ptep;
218 if (HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0)
219 put_user(0xF0000000 | mfn, p);
220 #endif
221 }
223 ret = 0;
224 break;
226 batch_err:
227 printk("batch_err ret=%d vma=%p addr=%lx "
228 "num=%d arr=%p %lx-%lx\n",
229 ret, vma, m.addr, m.num, m.arr,
230 vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
231 break;
232 }
233 break;
234 #endif
236 default:
237 ret = -EINVAL;
238 break;
239 }
241 return ret;
242 }
244 static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
245 {
246 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
247 vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
249 return 0;
250 }
252 static struct file_operations privcmd_file_ops = {
253 .ioctl = privcmd_ioctl,
254 .mmap = privcmd_mmap,
255 };
257 static int capabilities_read(char *page, char **start, off_t off,
258 int count, int *eof, void *data)
259 {
260 int len = 0;
261 *page = 0;
263 if (xen_start_info->flags & SIF_INITDOMAIN)
264 len = sprintf( page, "control_d\n" );
266 *eof = 1;
267 return len;
268 }
270 static int __init privcmd_init(void)
271 {
272 /* Set of hypercalls that privileged applications may execute. */
273 set_bit(__HYPERVISOR_acm_op, hypercall_permission_map);
274 set_bit(__HYPERVISOR_dom0_op, hypercall_permission_map);
275 set_bit(__HYPERVISOR_event_channel_op, hypercall_permission_map);
276 set_bit(__HYPERVISOR_memory_op, hypercall_permission_map);
277 set_bit(__HYPERVISOR_mmu_update, hypercall_permission_map);
278 set_bit(__HYPERVISOR_mmuext_op, hypercall_permission_map);
279 set_bit(__HYPERVISOR_xen_version, hypercall_permission_map);
281 privcmd_intf = create_xen_proc_entry("privcmd", 0400);
282 if (privcmd_intf != NULL)
283 privcmd_intf->proc_fops = &privcmd_file_ops;
285 capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
286 if (capabilities_intf != NULL)
287 capabilities_intf->read_proc = capabilities_read;
289 return 0;
290 }
292 __initcall(privcmd_init);
294 /*
295 * Local variables:
296 * c-file-style: "linux"
297 * indent-tabs-mode: t
298 * c-indent-level: 8
299 * c-basic-offset: 8
300 * tab-width: 8
301 * End:
302 */