diff --git a/Makefile b/Makefile index 5dd41c5..5b81e05 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ help: rpms: rpmbuild --define "_rpmdir rpm/" --define "_builddir ." -bb rpm_spec/qubes-utils.spec -all: +all: $(MAKE) -C qrexec-lib all $(MAKE) -C qmemman all $(MAKE) -C core all @@ -25,6 +25,10 @@ install: $(MAKE) -C qmemman install $(MAKE) -C core install +install-kernel-support: + $(MAKE) -C dracut install + $(MAKE) -C kernel-modules install + clean: $(MAKE) -C qrexec-lib clean $(MAKE) -C qmemman clean diff --git a/Makefile.builder b/Makefile.builder index 8408483..c19f19c 100644 --- a/Makefile.builder +++ b/Makefile.builder @@ -1,3 +1,3 @@ -RPM_SPEC_FILES := rpm_spec/qubes-utils.spec +RPM_SPEC_FILES := rpm_spec/qubes-utils.spec rpm_spec/qubes-kernel-vm-support.spec ARCH_BUILD_DIRS := archlinux DEBIAN_BUILD_DIRS := debian diff --git a/dracut/Makefile b/dracut/Makefile new file mode 100644 index 0000000..272669f --- /dev/null +++ b/dracut/Makefile @@ -0,0 +1,4 @@ +install: + install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm + install module-setup.sh mount_modules.sh qubes_cow_setup.sh \ + $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm/ diff --git a/dracut/module-setup.sh b/dracut/module-setup.sh new file mode 100644 index 0000000..6ce44bf --- /dev/null +++ b/dracut/module-setup.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +check() { + if xenstore-read qubes-vm-type &>/dev/null; then + return 0 + else + return 255 + fi +} + +install() { + inst_hook pre-udev 90 $moddir/qubes_cow_setup.sh + inst_hook pre-pivot 50 $moddir/mount_modules.sh + +} diff --git a/dracut/mount_modules.sh b/dracut/mount_modules.sh new file mode 100644 index 0000000..dc1c582 --- /dev/null +++ b/dracut/mount_modules.sh @@ -0,0 +1,13 @@ +# +# This file should be places in pre-pivot directory in dracut's initramfs +# + +#!/bin/sh + +if ! [ -d $NEWROOT/lib/modules/`uname -r` ]; then + echo "Waiting for /dev/xvdd device..." + while ! [ -e /dev/xvdd ]; do sleep 0.1; done + + mount -n -t ext3 /dev/xvdd $NEWROOT/lib/modules +fi + diff --git a/dracut/qubes_cow_setup.sh b/dracut/qubes_cow_setup.sh new file mode 100644 index 0000000..19bb9d3 --- /dev/null +++ b/dracut/qubes_cow_setup.sh @@ -0,0 +1,31 @@ +# +# This file should be places in pre-mount directory in dracut's initramfs +# + +#!/bin/sh +echo "Qubes initramfs script here:" + +if [ -e /dev/mapper/dmroot ] ; then + die "Qubes: FATAL error: /dev/mapper/dmroot already exists?!" +fi + +modprobe xenblk || modprobe xen-blkfront || echo "Qubes: Cannot load Xen Block Frontend..." + +echo "Waiting for /dev/xvda* devices..." +while ! [ -e /dev/xvda ]; do sleep 0.1; done + +if [ `cat /sys/block/xvda/ro` = 1 ] ; then + echo "Qubes: Doing COW setup for AppVM..." + + while ! [ -e /dev/xvdc ]; do sleep 0.1; done + while ! [ -e /dev/xvdc2 ]; do sleep 0.1; done + + echo "0 `cat /sys/block/xvda/size` snapshot /dev/xvda /dev/xvdc2 N 16" | \ + dmsetup create dmroot || { echo "Qubes: FATAL: cannot create dmroot!"; } + echo Qubes: done. +else + echo "Qubes: Doing R/W setup for TemplateVM..." + echo "0 `cat /sys/block/xvda/size` linear /dev/xvda 0" | \ + dmsetup create dmroot || { echo "Qubes: FATAL: cannot create dmroot!"; exit 1; } + echo Qubes: done. +fi diff --git a/kernel-modules/Makefile b/kernel-modules/Makefile new file mode 100644 index 0000000..3f94fe7 --- /dev/null +++ b/kernel-modules/Makefile @@ -0,0 +1,9 @@ +ver := $(shell cat ../version) +srcdir := /usr/src/u2mfn-$(ver) + +install: install-u2mfn + +install-u2mfn: + install -d $(DESTDIR)$(srcdir) + install -m 644 u2mfn/u2mfn.c u2mfn/Makefile $(DESTDIR)$(srcdir) + sed -e 's#@@VERSION@@#$(ver)#' u2mfn/dkms.conf.in > $(DESTDIR)$(srcdir)/dkms.conf diff --git a/kernel-modules/u2mfn/Makefile b/kernel-modules/u2mfn/Makefile new file mode 100644 index 0000000..59e222d --- /dev/null +++ b/kernel-modules/u2mfn/Makefile @@ -0,0 +1,28 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +obj-m += u2mfn.o + +clean: + rm -f *.o *.ko *~ + rm -f .u2mfn.* *.mod.c Module.symvers modules.order + rm -fr .tmp_versions + rm -f Makefile.xen diff --git a/kernel-modules/u2mfn/dkms.conf.in b/kernel-modules/u2mfn/dkms.conf.in new file mode 100644 index 0000000..96ddd70 --- /dev/null +++ b/kernel-modules/u2mfn/dkms.conf.in @@ -0,0 +1,7 @@ +PACKAGE_VERSION="@@VERSION@@" + +# Items below here should not have to change with each driver version +PACKAGE_NAME="u2mfn" + +BUILT_MODULE_NAME[0]="u2mfn" +DEST_MODULE_LOCATION[0]="/extra/" diff --git a/kernel-modules/u2mfn/u2mfn.c b/kernel-modules/u2mfn/u2mfn.c new file mode 100644 index 0000000..bd88df4 --- /dev/null +++ b/kernel-modules/u2mfn/u2mfn.c @@ -0,0 +1,172 @@ +/* + * The Qubes OS Project, http://www.qubes-os.org + * + * Copyright (C) 2010 Rafal Wojtczuk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#ifndef FOREIGN_FRAME_BIT +#include +#endif +#include + +/* copy of /usr/include/u2mfn-kernel.h, to reduce requirements */ +#include +#define U2MFN_MAGIC 0xf5 +#define U2MFN_GET_MFN_FOR_PAGE _IOW(U2MFN_MAGIC, 1, int) +#define U2MFN_GET_LAST_MFN _IO(U2MFN_MAGIC, 2) + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) +static inline unsigned long virt_to_phys(volatile void *address) +{ + return __pa((unsigned long) address); +} +#endif + +#ifdef virt_to_mfn +#define VIRT_TO_MFN virt_to_mfn +#else +extern unsigned long *phys_to_machine_mapping; +static inline unsigned long VIRT_TO_MFN(void *addr) +{ + unsigned int pfn = virt_to_phys(addr) >> PAGE_SHIFT; + return phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT; +} +#endif + +/// User virtual address to mfn translator +/** + \param cmd ignored + \param data the user-specified address + \return mfn corresponding to "data" argument, or -1 on error +*/ +static long u2mfn_ioctl(struct file *f, unsigned int cmd, + unsigned long data) +{ + struct page *user_page; + void *kaddr; + int ret; + + if (_IOC_TYPE(cmd) != U2MFN_MAGIC) { + printk("Qubes u2mfn: wrong IOCTL magic"); + return -ENOTTY; + } + + switch (cmd) { + case U2MFN_GET_MFN_FOR_PAGE: + down_read(¤t->mm->mmap_sem); + ret = get_user_pages + (current, current->mm, data, 1, 1, 0, &user_page, 0); + up_read(¤t->mm->mmap_sem); + if (ret != 1) { + printk("U2MFN_GET_MFN_FOR_PAGE: get_user_pages failed, ret=0x%x\n", ret); + return -1; + } + kaddr = kmap(user_page); + ret = VIRT_TO_MFN(kaddr); + kunmap(user_page); + put_page(user_page); + break; + + case U2MFN_GET_LAST_MFN: + if (f->private_data) + ret = VIRT_TO_MFN(f->private_data); + else + ret = 0; + break; + + default: + printk("Qubes u2mfn: wrong ioctl passed!\n"); + return -ENOTTY; + } + + + return ret; +} + +static int u2mfn_mmap(struct file *f, struct vm_area_struct *vma) +{ + int ret; + char *kbuf; + long length = vma->vm_end - vma->vm_start; + printk("u2mfn_mmap: entering, private=%p\n", f->private_data); + if (f->private_data) + return -EBUSY; + if (length != PAGE_SIZE) + return -EINVAL; + kbuf = (char *) __get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + f->private_data = kbuf; + + ret = remap_pfn_range(vma, vma->vm_start, + virt_to_phys(kbuf) >> PAGE_SHIFT, + length, vma->vm_page_prot); + + printk("u2mfn_mmap: calling remap return %d\n", ret); + if (ret) + return ret; + + + return 0; +} + +static int u2mfn_release(struct inode *i, struct file *f) +{ + printk("u2mfn_release, priv=%p\n", f->private_data); + if (f->private_data) + __free_page(f->private_data); + f->private_data = NULL; + return 0; +} + +static struct file_operations u2mfn_fops = { + .unlocked_ioctl = u2mfn_ioctl, + .mmap = u2mfn_mmap, + .release = u2mfn_release +}; + +/// u2mfn module registration +/** + tries to register "/proc/u2mfn" pseudofile +*/ +static int u2mfn_init(void) +{ + struct proc_dir_entry *u2mfn_node = + proc_create_data("u2mfn", 0666, NULL, + &u2mfn_fops, 0); + if (!u2mfn_node) + return -1; + return 0; +} + +static void u2mfn_exit(void) +{ + remove_proc_entry("u2mfn", 0); +} + +module_init(u2mfn_init); +module_exit(u2mfn_exit); +MODULE_LICENSE("GPL"); diff --git a/rpm_spec/qubes-kernel-vm-support.spec b/rpm_spec/qubes-kernel-vm-support.spec new file mode 100644 index 0000000..30c0995 --- /dev/null +++ b/rpm_spec/qubes-kernel-vm-support.spec @@ -0,0 +1,72 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2015 Marek Marczykowski-Górecki +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + + +%{!?version: %define version %(cat version)} + +Name: qubes-kernel-vm-support +Version: %{version} +Release: 1%{?dist} +Summary: Qubes VM kernel and initramfs modules + +Group: Qubes +Vendor: Invisible Things Lab +License: GPL v2 only +URL: http://www.qubes-os.org + +Requires: dracut +Requires: dkms + +%define _builddir %(pwd) + +%description +This package contains: +1. Dracut module required to setup Qubes VM root filesystem. This package is +needed in VM only when the VM uses its own kernel (via pvgrub or so). Otherwise +initrd is provided by dom0. + +2. u2mfn kernel module sources (dkms) required by GUI agent and R2 version of +libvchan library. + +%prep +# we operate on the current directory, so no need to unpack anything +# symlink is to generate useful debuginfo packages +rm -f %{name}-%{version} +ln -sf . %{name}-%{version} +%setup -T -D + +%build + +%install +make install-kernel-support DESTDIR=%{buildroot} + +%files +/usr/lib/dracut/modules.d/90qubes-vm +/usr/src/u2mfn-%{version}/ + +%post +dkms add -m u2mfn -v %{version} --rpm_safe_upgrade + +%preun +dkms remove -m u2mfn -v %{version} --all --rpm_safe_upgrade + +%changelog +