u2mfn: get mfn via pte
Before this commit u2mfn got the address via kmap(get_user_pages(...)). This has the problem that get_user_pages() does not work in some cases. For example when qemu in a stubdom tries to get the mfn for a page which is mapped from the target domain u2mfn fails because get_user_pages() cannot be used for such mappings. So get the address from the pte with apply_to_page_range(). Since we are only interested in one page get_locked_pte() would be simpler but it's not available to modules.
This commit is contained in:
parent
7458893b8f
commit
7e6bee6281
@ -54,6 +54,11 @@ static inline unsigned long VIRT_TO_MFN(void *addr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int u2mfn_get_mfn(pte_t *pte, pgtable_t token, unsigned long addr, void *data) {
|
||||||
|
*((unsigned long *) data) = pfn_to_mfn(pte_pfn(*pte));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// User virtual address to mfn translator
|
/// User virtual address to mfn translator
|
||||||
/**
|
/**
|
||||||
\param cmd ignored
|
\param cmd ignored
|
||||||
@ -63,9 +68,8 @@ static inline unsigned long VIRT_TO_MFN(void *addr)
|
|||||||
static long u2mfn_ioctl(struct file *f, unsigned int cmd,
|
static long u2mfn_ioctl(struct file *f, unsigned int cmd,
|
||||||
unsigned long data)
|
unsigned long data)
|
||||||
{
|
{
|
||||||
struct page *user_page;
|
|
||||||
void *kaddr;
|
|
||||||
long ret;
|
long ret;
|
||||||
|
unsigned long mfn;
|
||||||
|
|
||||||
if (_IOC_TYPE(cmd) != U2MFN_MAGIC) {
|
if (_IOC_TYPE(cmd) != U2MFN_MAGIC) {
|
||||||
printk("Qubes u2mfn: wrong IOCTL magic");
|
printk("Qubes u2mfn: wrong IOCTL magic");
|
||||||
@ -74,26 +78,15 @@ static long u2mfn_ioctl(struct file *f, unsigned int cmd,
|
|||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case U2MFN_GET_MFN_FOR_PAGE:
|
case U2MFN_GET_MFN_FOR_PAGE:
|
||||||
down_read(¤t->mm->mmap_sem);
|
ret = apply_to_page_range(current->mm, data, PAGE_SIZE, u2mfn_get_mfn, &mfn);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
|
||||||
ret = get_user_pages
|
if (ret < 0 || mfn == INVALID_P2M_ENTRY) {
|
||||||
(data, 1, (FOLL_WRITE | FOLL_FORCE), &user_page, 0);
|
printk("U2MFN_GET_MFN_FOR_PAGE: failed to get mfn, "
|
||||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
|
"addr=0x%lx ret=0x%lx\n", data, ret);
|
||||||
ret = get_user_pages
|
|
||||||
(data, 1, 1, 0, &user_page, 0);
|
|
||||||
#else
|
|
||||||
ret = get_user_pages
|
|
||||||
(current, current->mm, data, 1, 1, 0, &user_page, 0);
|
|
||||||
#endif
|
|
||||||
up_read(¤t->mm->mmap_sem);
|
|
||||||
if (ret != 1) {
|
|
||||||
printk("U2MFN_GET_MFN_FOR_PAGE: get_user_pages failed, ret=0x%lx\n", ret);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
kaddr = kmap(user_page);
|
|
||||||
ret = VIRT_TO_MFN(kaddr);
|
ret = mfn;
|
||||||
kunmap(user_page);
|
|
||||||
put_page(user_page);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case U2MFN_GET_LAST_MFN:
|
case U2MFN_GET_LAST_MFN:
|
||||||
|
Loading…
Reference in New Issue
Block a user