Compare commits

..

18 Commits

Author SHA1 Message Date
Marek Marczykowski-Górecki 0be42e4354
version 2.0.21
9 years ago
Marek Marczykowski-Górecki 4b6924a27b
imgconverter: ensure that connection to the VM is properly closed
9 years ago
Marek Marczykowski-Górecki 5c6ad4c669
imgconverter: use more meaningful error for empty icon image
9 years ago
Marek Marczykowski-Górecki 6e4fa03459
udev: fix block devices ignoring rule
9 years ago
Marek Marczykowski-Górecki 11365e353e
udev: ignore temporary devices created during VM startup
9 years ago
Marek Marczykowski-Górecki d4b23691f1
qrexec-lib: enable compiler optimization
9 years ago
Marek Marczykowski-Górecki 0771ddaab3 fedora: fix systemd service files permission
9 years ago
Marek Marczykowski-Górecki 9b762acd0b version 2.0.20
9 years ago
Olivier MEDOC f6460d6e95 archlinux: fix new packaging requirements related to run, sbin, lib64...
9 years ago
Marek Marczykowski-Górecki 034b066700 version 2.0.19
9 years ago
Marek Marczykowski-Górecki d0a23bdd09 debian: O_TMPFILE already defined
9 years ago
Marek Marczykowski-Górecki ba61c8405c version 2.0.18
9 years ago
Marek Marczykowski-Górecki bbdb5ed67f filecopy: fix handling ENOENT error
9 years ago
Marek Marczykowski-Górecki d6eb7e5c58 version 2.0.17
9 years ago
Marek Marczykowski-Górecki d88242bb99 filecopy: really do not use O_TMPFILE when use_tmpfile==0
9 years ago
Marek Marczykowski-Górecki 509ae49001 version 2.0.16
9 years ago
Marek Marczykowski-Górecki 72069d8526 filecopy: create new file unaccessible to the user until fully written
9 years ago
Marek Marczykowski-Górecki 129aeeacd5 version 2.0.15
10 years ago

@ -1,39 +0,0 @@
sudo: required
dist: bionic
language: python
python:
- '2.7'
install:
- test -z "$TESTS_ONLY" || pip install -r ci/requirements.txt
- test -n "$TESTS_ONLY" || git clone https://github.com/QubesOS/qubes-builder ~/qubes-builder
script:
- test -z "$TESTS_ONLY" || python -m unittest discover -v imgconverter -p test.py
- test -n "$TESTS_ONLY" || ~/qubes-builder/scripts/travis-build
env:
- DIST_DOM0=fc31 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
- DISTS_VM=fc29 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
- DISTS_VM=fc30 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
- DISTS_VM=stretch USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
- DISTS_VM=buster USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
- DISTS_VM=centos7 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
jobs:
include:
- env: TESTS_ONLY=1
python: 2.7
- env: TESTS_ONLY=1
python: 3.5
- env: TESTS_ONLY=1
python: 3.6
- env: TESTS_ONLY=1
python: 3.7
- stage: deploy
python: 3.6
env: DIST_DOM0=fc31 TESTS_ONLY=
script: ~/qubes-builder/scripts/travis-deploy
# don't build tags which are meant for code signing only
branches:
except:
- /.*_.*/

@ -1,13 +1,13 @@
ifeq ($(shell uname -m),x86_64)
LIBDIR ?= /usr/lib64
else
LIBDIR ?= /usr/lib
ifndef LIBDIR
ifeq ($(shell uname -m),x86_64)
LIBDIR = /usr/lib64
else
LIBDIR = /usr/lib
endif
endif
SCRIPTSDIR ?= /usr/lib/qubes
SYSLIBDIR ?= /lib
INCLUDEDIR ?= /usr/include
INCLUDEDIR = /usr/include
export LIBDIR SCRIPTSDIR SYSLIBDIR INCLUDEDIR
export LIBDIR INCLUDEDIR
help:
echo "Use rpmbuild to compile this pacakge"
@ -16,29 +16,18 @@ 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 imgconverter all
$(MAKE) -C core all
install:
$(MAKE) -C udev install
$(MAKE) -C qrexec-lib install
$(MAKE) -C qmemman install
$(MAKE) -C imgconverter install
install-fedora-kernel-support:
$(MAKE) -C dracut install
$(MAKE) -C kernel-modules install
$(MAKE) -C grub install-fedora
install-debian-kernel-support:
$(MAKE) -C initramfs-tools install
$(MAKE) -C dracut install
$(MAKE) -C kernel-modules install
$(MAKE) -C grub install-debian
$(MAKE) -C core install
clean:
$(MAKE) -C qrexec-lib clean
$(MAKE) -C qmemman clean
$(MAKE) -C imgconverter clean
$(MAKE) -C core clean

@ -1,3 +1,3 @@
RPM_SPEC_FILES := rpm_spec/qubes-utils.spec rpm_spec/qubes-kernel-vm-support.spec
RPM_SPEC_FILES := rpm_spec/qubes-utils.spec
ARCH_BUILD_DIRS := archlinux
DEBIAN_BUILD_DIRS := debian

@ -4,16 +4,17 @@
# then please put 'unknown'.
# Maintainer: Olivier Medoc <o_medoc@yahoo.fr>
pkgname=(qubes-vm-utils qubes-vm-kernel-support)
pkgname=qubes-vm-utils
pkgver=`cat version`
pkgrel=10
pkgrel=9
epoch=
pkgdesc="Common Linux files for Qubes VM."
arch=("x86_64")
url="http://qubes-os.org/"
license=('GPL')
groups=()
makedepends=(gcc make pkgconfig 'python-setuptools' 'python2-setuptools')
depends=(qubes-libvchan)
makedepends=(qubes-libvchan)
checkdepends=()
optdepends=()
provides=()
@ -21,55 +22,30 @@ conflicts=()
replaces=()
backup=()
options=('staticlibs')
install=PKGBUILD-qubes-vm-utils.install
changelog=
source=(PKGBUILD-initcpio-hook.sh PKGBUILD-initcpio-install.sh)
source=()
noextract=()
md5sums=(SKIP)
md5sums=() #generate with 'makepkg -g'
build() {
for source in qrexec-lib udev qmemman core kernel-modules Makefile dracut imgconverter; do
for source in qrexec-lib udev qmemman core Makefile; do
(ln -s $srcdir/../$source $srcdir/$source)
done
# Build all with python2
PYTHON=python2 make all
# Build imgconverter with python3
make -C imgconverter all
}
package_qubes-vm-utils() {
depends=(imagemagick python2-cairo python2-pillow python2-numpy python-pillow python-numpy)
install=PKGBUILD-qubes-vm-utils.install
# Install all for python2
PYTHON=python2 make install DESTDIR=$pkgdir LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SBINDIR=/usr/bin
# Install imgconverter as python3
make -C imgconverter install DESTDIR=$pkgdir LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SBINDIR=/usr/bin
make all LIBDIR=/usr/lib SBINDIR=/usr/bin
}
package_qubes-vm-kernel-support() {
depends=(mkinitcpio grub)
install=PKGBUILD-qubes-vm-kernel-support.install
package() {
mkdir -p ${pkgdir}/usr/lib/initcpio/install/
mkdir -p ${pkgdir}/usr/lib/initcpio/hooks/
mkdir -p ${pkgdir}/usr/lib/qubes/
mkdir -p ${pkgdir}/usr/bin/
make install DESTDIR=$pkgdir LIBDIR=/usr/lib SBINDIR=/usr/bin
install -m 611 ${srcdir}/PKGBUILD-initcpio-install.sh ${pkgdir}/usr/lib/initcpio/install/qubes
install -m 611 ${srcdir}/PKGBUILD-initcpio-hook.sh ${pkgdir}/usr/lib/initcpio/hooks/qubes
install -m 755 ${srcdir}/dracut/full-dmroot/qubes_cow_setup.sh ${pkgdir}/usr/lib/qubes/qubes_cow_setup.sh
}
# vim:set ts=2 sw=2 et:

@ -1,9 +0,0 @@
#!/usr/bin/ash
run_earlyhook() {
msg "Starting Qubes copy on write setup script"
/usr/lib/qubes/qubes_cow_setup.sh
}

@ -1,20 +0,0 @@
#!/usr/bin/bash
build() {
add_module "xen-blkfront"
add_binary "/usr/bin/sfdisk"
add_binary "/usr/bin/mkswap"
add_binary "/usr/bin/dmsetup"
add_binary "/usr/lib/qubes/qubes_cow_setup.sh"
add_runscript
}
help() {
cat <<HELPEOF
This hook enables Qubes COW Setup (using lvm) in initramfs.
HELPEOF
}

@ -1,27 +0,0 @@
help() {
echo "Before using pvgrub, the kernel you want to use needs to be regenerated with Qubes kernel modules in the TemplateVM:"
echo "1/ Ensure that your kernel and kernel sources are installed (ex: pacman -S linux-lts linux-lts-headers)"
echo "2/ Ensure that grub config file has been generated for your kernel (ex: grub-mkconfig > /boot/grub/grub.cfg)"
echo "3/ Reinstall qubes-vm-kernel-support to ensure Qubes-OS kernel module is compiled and that the initcpio is rebuilt"
echo "This should then be handled automatically in your next kernel updates"
}
## arg 1: the new package version
post_install() {
echo "Adding qubes required hooks to mkinitcpio.conf"
sed 's/^HOOKS="base/HOOKS="lvm2 qubes base/' -i /etc/mkinitcpio.conf
help
}
post_upgrade() {
echo "Adding qubes required hooks to mkinitcpio.conf"
sed 's/^HOOKS="base/HOOKS="lvm2 qubes base/' -i /etc/mkinitcpio.conf
help
}
post_remove() {
echo "Removing qubes required hooks to mkinitcpio.conf"
sed 's/^HOOKS="lvm2 qubes base/HOOKS="base/' -i /etc/mkinitcpio.conf
}

@ -2,8 +2,13 @@
## arg 1: the new package version
post_install() {
ldconfig
/bin/systemctl enable qubes-meminfo-writer-dom0.service > /dev/null 2>&1
/bin/systemctl enable qubes-meminfo-writer.service > /dev/null 2>&1
if [ -r /etc/qubes-release ]; then
# dom0
/bin/systemctl enable qubes-meminfo-writer-dom0.service > /dev/null 2>&1
else
# VM
/bin/systemctl enable qubes-meminfo-writer.service > /dev/null 2>&1
fi
}
post_upgrade() {

@ -1,2 +0,0 @@
Pillow
numpy

@ -0,0 +1,20 @@
PYTHON = /usr/bin/python2
PYTHON_SITEARCH = `python2 -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1)'`
all:
$(PYTHON) -m compileall .
$(PYTHON) -O -m compileall .
.PHONY: all
clean:
$(RM) *.py[co]
.PHONY: clean
install:
mkdir -p $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
ifeq (1,${DEBIANBUILD})
cp *.py $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
else
cp *.py* $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
endif
.PHONY: install

@ -23,18 +23,16 @@ Toolkit for secure transfer and conversion of images between Qubes VMs.'''
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import colorsys
import math
import os
import re
try:
from io import BytesIO
except ImportError:
from cStringIO import StringIO as BytesIO
import cStringIO as StringIO
import subprocess
import sys
import unittest
import PIL.Image
import numpy
import cairo
# those are for "zOMG UlTRa HD! WalLLpapPer 8K!!1!" to work seamlessly;
# 8192 * 5120 * 4 B = 160 MiB, so DoS by memory exhaustion is unlikely
@ -44,13 +42,13 @@ MAX_HEIGHT = 5120
# current max raster icon size in hicolor theme is 256 as of 2013/fedora-18
# beyond that one probably shall use scalable icons
# (SVG is currently unsupported)
ICON_MAXSIZE = 2048
ICON_MAXSIZE = 512
# header consists of two decimal numbers, SPC and LF
re_imghdr = re.compile(br'^\d+ \d+\n$')
def imghdrlen(w, h):
# width & height are inclusive max vals, and +2 for ' ' and '\n'
return len(str(w)) + len(str(h)) + 2
re_imghdr = re.compile(r'^\d+ \d+\n$')
imghdrlen = lambda w, h: int(math.ceil(math.log10(w)) \
+ math.ceil(math.log10(h)) \
+ 2)
class Image(object):
def __init__(self, rgba, size):
@ -72,87 +70,21 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
if p.wait():
raise Exception('Conversion failed')
def save_pil(self, dst):
'''Save image to disk using PIL.'''
img = PIL.Image.frombytes('RGBA', self._size, self._rgba)
img.save(dst)
@property
def data(self):
return self._rgba
@property
def width(self):
return self._size[0]
@property
def height(self):
return self._size[1]
def tint(self, colour):
'''Return new tinted image'''
tr, tg, tb = hex_to_int(colour)
tM = max(tr, tg, tb)
tm = min(tr, tg, tb)
r, g, b = hex_to_float(colour)
h, _, s = colorsys.rgb_to_hls(r, g, b)
result = StringIO.StringIO()
# (trn/tdn, tgn/tdn, tbn/tdn) is the tint color with maximum saturation
if tm == tM:
trn = 1
tgn = 1
tbn = 1
tdn = 2
else:
trn = tr - tm
tgn = tg - tm
tbn = tb - tm
tdn = tM - tm
# use a 1D image representation since we only process a single pixel at a time
pixels = self._size[0] * self._size[1]
x = numpy.fromstring(self._rgba, 'B').reshape(pixels, 4)
r = x[:, 0]
g = x[:, 1]
b = x[:, 2]
a = x[:, 3]
M = numpy.maximum(numpy.maximum(r, g), b).astype('u4')
m = numpy.minimum(numpy.minimum(r, g), b).astype('u4')
# Tn/Td is how much chroma range is reserved for the tint color
# 0 -> greyscale image becomes greyscale image
# 1 -> image becomes solid tint color
Tn = 1
Td = 4
# set chroma to the original pixel chroma mapped to the Tn/Td .. 1 range
# float c2 = (Tn/Td) + (1.0 - Tn/Td) * c
# set lightness to the original pixel lightness mapped to the range for the new chroma value
# float m2 = m * (1.0 - c2) / (1.0 - c)
c = M - m
c2 = (Tn * 255) + (Td - Tn) * c
c2d = Td
m2 = ((255 * c2d) - c2) * m
# the maximum avoids division by 0 when c = 255 (m2 is 0 anyway, so m2d doesn't matter)
m2d = numpy.maximum((255 - c) * c2d, 1)
# precomputed values
c2d_tdn = tdn * c2d
m2_c2d_tdn = m2 * c2d_tdn
m2d_c2d_tdn = m2d * c2d_tdn
c2_m2d = c2 * m2d
# float vt = m2 + tvn * c2
rt = ((m2_c2d_tdn + trn * c2_m2d) // m2d_c2d_tdn).astype('B')
gt = ((m2_c2d_tdn + tgn * c2_m2d) // m2d_c2d_tdn).astype('B')
bt = ((m2_c2d_tdn + tbn * c2_m2d) // m2d_c2d_tdn).astype('B')
xt = numpy.column_stack((rt, gt, bt, a))
return self.__class__(rgba=xt.tobytes(), size=self._size)
for i in xrange(0, self._size[0] * self._size[1] * 4, 4):
r, g, b, a = tuple(ord(c) / 255. for c in self._rgba[i:i+4])
_, l, _ = colorsys.rgb_to_hls(r, g, b)
r, g, b = colorsys.hls_to_rgb(h, l, s)
result.write(''.join(chr(int(i * 255)) for i in [r, g, b, a]))
return self.__class__(rgba=result.getvalue(), size=self._size)
@classmethod
def load_from_file(cls, filename):
@ -174,13 +106,6 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
return cls(rgba=rgba, size=size)
@classmethod
def load_from_file_pil(cls, filename):
'''Loads image from local file using PIL.'''
img = PIL.Image.open(filename)
img = img.convert('RGBA')
return cls(rgba=img.tobytes(), size=img.size)
@classmethod
def get_from_stream(cls, stream, max_width=MAX_WIDTH, max_height=MAX_HEIGHT):
'''Carefully parse image data from stream.
@ -223,8 +148,8 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
def get_from_vm(cls, vm, src, **kwargs):
'Get image from VM by QUBESRPC (qubes.GetImageRGBA).'
p = vm.run_service('qubes.GetImageRGBA')
p.stdin.write('{0}\n'.format(src).encode())
p = vm.run('QUBESRPC qubes.GetImageRGBA dom0', passio_popen=True)
p.stdin.write('{0}\n'.format(src))
p.stdin.close()
try:
@ -250,15 +175,16 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
'''Master end of image filter: writes untrusted image to stdout and
expects header+RGBA on stdin. This method is invoked from qvm-imgconverter-client.'''
filetype = None
if ':' in filename:
filetype, filename = filename.split(':', 1)
filetype, filename = filename.split(':', 1)[0]
sys.stdout.write('{0}:-\n'.format(filetype))
else:
sys.stdout.write('-\n')
try:
sys.stdout.write(open(filename).read())
except Exception as e:
except Exception, e:
raise Exception('Something went wrong: {0!s}'.format(e))
finally:
sys.stdout.close()
@ -267,29 +193,112 @@ expects header+RGBA on stdin. This method is invoked from qvm-imgconverter-clien
return cls.get_from_stream(sys.stdin, **kwargs)
def __eq__(self, other):
return self._size == other._size and self._rgba == other._rgba
def __ne__(self, other):
return not self.__eq__(other)
def hex_to_float(colour, channels=3, depth=8):
'''Convert hex colour definition to tuple of floats.'''
def hex_to_int(colour, channels=3, depth=1):
'''Convert hex colour definition to tuple of ints.'''
if depth % 4 != 0:
raise NotImplementedError('depths not divisible by 4 are unsupported')
length = channels * depth * 2
step = depth * 2
length = channels * depth / 4
step = depth / 4
# get rid of '#' or '0x' in front of hex values
colour = colour[-length:]
return tuple(int(colour[i:i+step], 0x10) for i in range(0, length, step))
return tuple(int(colour[i:i+step], 0x10) / float(2**depth - 1) for i in range(0, length, step))
def tint(src, dst, colour):
'''Tint image to reflect vm label.
src and dst may NOT specify ImageMagick format'''
src and dst may specify format, like png:aqq.gif'''
Image.load_from_file(src).tint(colour).save(dst)
def make_padlock(dst, colour, size=ICON_MAXSIZE):
cs = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size)
cr = cairo.Context(cs)
cr.set_source_rgb(*hex_to_float(colour))
cr.set_line_width(.125 * size)
cr.rectangle(.125 * size, .5 * size, .75 * size, .4375 * size)
cr.fill()
cr.move_to(.25 * size, .5 * size)
cr.line_to(.25 * size, .375 * size)
cr.arc(.5 * size, .375 * size, .25 * size, math.pi, 2 * math.pi)
cr.move_to(.75 * size, .375 * size) # this is unneccessary, but helps readability
cr.line_to(.75 * size, .5 * size)
cr.stroke()
cs.write_to_png(dst)
class TestCaseImage(unittest.TestCase):
def setUp(self):
self.rgba = \
'\x00\x00\x00\xff' '\xff\x00\x00\xff' \
'\x00\xff\x00\xff' '\x00\x00\x00\xff'
self.size = (2, 2)
self.image = Image(rgba=self.rgba, size=self.size)
def test_00_init(self):
self.assertEqual(self.image._rgba, self.rgba)
self.assertEqual(self.image._size, self.size)
def test_01_tint(self):
image = self.image.tint('#0000ff')
self.assertEqual(image._rgba,
'\x00\x00\x00\xff' '\x00\x00\xff\xff'
'\x00\x00\xff\xff' '\x00\x00\x00\xff')
def test_10_get_from_stream(self):
io = StringIO.StringIO('{0[0]} {0[1]}\n{1}'.format(self.size, self.rgba))
image = Image.get_from_stream(io)
self.assertEqual(image._rgba, self.rgba)
self.assertEqual(image._size, self.size)
def test_11_get_from_stream_malformed(self):
io = StringIO.StringIO('{0[0]} {0[1]}\n{1}'.format(self.size, self.rgba[-1])) # one byte too short
with self.assertRaises(Exception):
image = Image.get_from_stream(io)
def test_12_get_from_stream_too_big(self):
io = StringIO.StringIO('{0[0]} {0[1]}\n{1}'.format(self.size, self.rgba)) # 2x2
with self.assertRaises(Exception):
image = Image.get_from_stream(io, max_width=1)
io.seek(0)
with self.assertRaises(Exception):
image = Image.get_from_stream(io, max_height=1)
class TestCaseFunctionsAndConstants(unittest.TestCase):
def test_00_imghdrlen(self):
self.assertEqual(imghdrlen(8, 15), len('8 15\n'))
def test_01_re_imghdr(self):
self.assertTrue(re_imghdr.match('8 15\n'))
self.assertIsNone(re_imghdr.match('8 15'))
self.assertIsNone(re_imghdr.match('815\n'))
self.assertIsNone(re_imghdr.match('x yx\n'))
def test_10_hex_to_float_result_00(self):
self.assertEqual(hex_to_float('#000000'), (0.0, 0.0, 0.0))
def test_11_hex_to_float_result_ff(self):
self.assertEqual(hex_to_float('0xffffff'), (1.0, 1.0, 1.0))
Image.load_from_file_pil(src).tint(colour).save_pil(dst)
def test_12_hex_to_float_depth_3_not_implemented(self):
with self.assertRaises(NotImplementedError):
hex_to_float('123456', depth=3)
if __name__ == '__main__':
unittest.main()
# vim: ft=python sw=4 ts=4 et

696
debian/changelog vendored

@ -1,703 +1,53 @@
qubes-utils (4.1.3) unstable; urgency=medium
[ xaki23 ]
* partition full volatile for non-COW setups too
[ Frédéric Pierret (fepitre) ]
* travis: switch to bionic
[ Marek Marczykowski-Górecki ]
* travis: update python versions
[ Patrick Schleizer ]
* qubes-kernel-vm-support.preinst create folder /boot/grub
* qubes-kernel-vm-support.postinst run update-grub
[ Marek Marczykowski-Górecki ]
* debian: fix dependencies of qubes-kernel-vm-support pkg
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 07 Dec 2019 05:50:26 +0100
qubes-utils (4.1.2) unstable; urgency=medium
[ xaki23 ]
* align volatile swap partition to 1Mb instead of 512b
[ Marek Marczykowski-Górecki ]
* rpm: update python2 deps
* Disable BLS config style in grub
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 22 Sep 2019 05:10:19 +0200
qubes-utils (4.1.1) unstable; urgency=medium
* initrd: mount / rw for the overlayfs setup time
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 10 Jun 2019 00:48:40 +0200
qubes-utils (4.1.0) unstable; urgency=medium
* Remove qrexec related files
* Remove u2mfn module
* travis: update to R4.1
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 08 Jun 2019 03:20:55 +0200
qubes-utils (4.0.24) unstable; urgency=medium
[ Marek Marczykowski-Górecki ]
* Declare u2mfn module version, skip build for qubes kernels
[ Frédéric Pierret (fepitre) ]
* python3: use macro pkgversion
* travis: switch to xenial
* travis: remove older Fedora releases and add Fedora 30
[ Marek Marczykowski-Górecki ]
* initramfs: use overlayfs for /lib/modules, if available
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 06 Jun 2019 21:30:30 +0200
qubes-utils (4.0.23) unstable; urgency=medium
* Disable scrubbing memory pages during initial balloon down
* dracut: fix checking for "Root filesystem" label, improve udev sync
* dracut: add a flag file indicating scrub-pages option support
* Adjust permissions of /dev/xen/hypercall
* Do not use /proc/xen for detecting dom0 anymore
* Really install xen-scrub-pages dracut module
* Add xen_scrub_pages=0 kernel option only if initramfs was rebuilt
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 25 Feb 2019 21:46:52 +0100
qubes-utils (4.0.22) unstable; urgency=medium
* tests: skip img converter test if qubes-img-converter is not
installed
* imgconverter: allow icons up to 2048x2048
* tests: skip the other img converter test too
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 29 Oct 2018 01:03:59 +0100
qubes-utils (4.0.21) unstable; urgency=medium
[ Rusty Bird ]
* Order qubes-meminfo-writer-dom0 before systemd-user-sessions
[ Marek Marczykowski-Górecki ]
* rpm: adjust for fc29
* travis: update Fedora and Debian versions
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 09 Oct 2018 00:25:11 +0200
qubes-utils (4.0.20) unstable; urgency=medium
* udev: create /dev/mapper/dmroot -> xvda3 symlink when its mounted
directly
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 03 Jul 2018 21:11:00 +0200
qubes-utils (4.0.19) unstable; urgency=medium
* rpm: use proper macros for systemd handling
* travis: add centos7
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 02 May 2018 17:55:09 +0200
qubes-utils (4.0.18) unstable; urgency=medium
[ Marek Marczykowski-Górecki ]
* udev: don't call udev-block-add-change for devices excluded by other
rules
* rpm: preparation for src.rpm building
[ Frédéric Pierret ]
* Makefile.builder: currently disable Mock
* Remove _builddir
* Fix debug symbols
* spec.in: add changelog placeholder
[ Marek Marczykowski-Górecki ]
* travis: update Fedora versions
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 21 Apr 2018 14:36:39 +0200
qubes-utils (4.0.17) unstable; urgency=medium
[ Frédéric Pierret ]
* Fix python3 package names with respect to CentOS for consistency
with python34 names
* Remove busybox as it is not provided in RHEL7 anymore
* centos: fix python packages names
* drop busybox dependance
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 27 Feb 2018 15:17:12 +0100
qubes-utils (4.0.16) unstable; urgency=medium
* qrexec: provide common function for handling service call
* debian: adjust required version after adding new function
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 20 Feb 2018 00:05:31 +0100
qubes-utils (4.0.15) unstable; urgency=medium
* udev: update detecting usbip-connected devices
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 18 Jan 2018 19:07:40 +0100
qubes-utils (4.0.14) unstable; urgency=medium
[ Reynir Björnsson ]
* Remove duplicate #define
[ Rusty Bird ]
* udev-block-add-change: ignore unconnected Network Block Device
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 12 Jan 2018 06:16:05 +0100
qubes-utils (4.0.13) unstable; urgency=medium
[ Marek Marczykowski-Górecki ]
* imgconverter: fix make_padlock function
* Update tests
* travis: run imgconverter unit tests
* Make tests python3 compatible
* travis: run tests also on python3
* travis: enable deploy stage for master-staging -> master gate
[ Gianluca Guida ]
* Fix qrexec-lib headers
[ Marek Marczykowski-Górecki ]
* imgconverter: fix handling explicit file type
* tests: integration tests for qvm-convert-img
* travis: run only unit tests
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 23 Dec 2017 02:50:19 +0100
qubes-utils (4.0.12) unstable; urgency=medium
[ Marek Marczykowski-Górecki ]
* debian: make it easier to spot missing files in debian/*.install
* debian: include drauct module in qubes-kernel-vm-support
[ Patrick Schleizer ]
* qubes-kernel-vm-support compatibility with dracut
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 12 Dec 2017 01:41:52 +0100
qubes-utils (4.0.11) unstable; urgency=medium
[ qubesuser ]
* remove unused cairo import
* add Python pillow and numpy dependencies
* use PIL image library instead of ImageMagick to load/save images
when tinting
* reimplement tint algorithm with numpy for reasonable performance
* replace tinting algorithm with one that partially preserves
saturation too
[ Marek Marczykowski-Górecki ]
* Add missing classmethod decorator
* Make udev-block-add-change executable again
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 21 Nov 2017 05:34:50 +0100
qubes-utils (4.0.10) unstable; urgency=medium
[ Olivier MEDOC ]
* archlinux: build imgconverter with both python2 and python3
[ qubesuser ]
* Speed up udev-block-add-change by not using xenstore
[ Your Name ]
* This commit specifies the integer width explicitly to match
`result_header_ext` etc.
[ Marek Marczykowski-Górecki ]
* Initialize pad field in filecopy final response
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 21 Nov 2017 04:46:49 +0100
qubes-utils (4.0.9) unstable; urgency=medium
* Fix initramfs scripts on Debian
* qubes-prepare-vm-kernel: Include kernel and initramfs inside
modules.img
* initramfs: add support for variable partitions layout
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 17 Oct 2017 23:54:15 +0200
qubes-utils (4.0.8) unstable; urgency=medium
[ Frédéric Pierret ]
* Fix CentOS dependencies: python3
[ Marek Marczykowski-Górecki ]
* travis: add fc26 build
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 30 Sep 2017 01:59:38 +0200
qubes-utils (4.0.7) unstable; urgency=medium
[ Olivier MEDOC ]
* Fix gcc Werror because of a typo in a switch/case explicit
fallthrough comment
[ Marek Marczykowski-Górecki ]
* udev: fix loop devices exclusion based on directory flagfile
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 15 Sep 2017 13:43:18 +0200
qubes-utils (4.0.6) unstable; urgency=medium
[ Jean-Philippe Ouellet ]
* Fix off-by-one error in header length calculation
[ Marek Marczykowski-Górecki ]
* udev: major cleanup in block devices handling
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 12 Sep 2017 04:52:48 +0200
qubes-utils (4.0.5) unstable; urgency=medium
* udev: filter-out QEMU devices
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 11 Aug 2017 13:34:11 +0200
qubes-utils (4.0.4) unstable; urgency=medium
[ HW42 ]
* u2mfn: get mfn via pte
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 29 Jul 2017 05:19:34 +0200
qubes-utils (4.0.3) unstable; urgency=medium
[ Rusty Bird ]
* Fall back to sync() if syncfs() is unavailable
[ Marek Marczykowski-Górecki ]
* udev: don't list in qvm-block any device marked to be ignored by
udev
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 06 Jul 2017 19:41:04 +0200
qubes-utils (4.0.2) unstable; urgency=medium
[ Paras Chetal ]
* Fix include header syntax
[ Marek Marczykowski-Górecki ]
* initramfs: use symlink for rw root.img, instead of dm-linear
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 24 Jun 2017 14:55:03 +0200
qubes-utils (4.0.1) unstable; urgency=medium
[ Marek Marczykowski-Górecki ]
* travis: switch to Qubes 4.0
* rpm: add missing build requires
* travis: drop fc23 vm packages building
[ unman ]
* Improve error message when file exists
[ Marek Marczykowski-Górecki ]
* rpm: packge qubesimgconverter for both python2 and python3
* imgconverter: make it really work on python3
* imgconverter: use core3 API in get_from_vm()
* rpm: add missing build requires
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 18 May 2017 01:54:46 +0200
qubes-utils (4.0.0) unstable; urgency=medium
[ Wojtek Porczyk ]
* debian/control: remove unneeded qubesdb dependency
* Package imgconverter as separate Python module
* Move imggen module from artwork.
[ Marek Marczykowski-Górecki ]
* dracut: add missing 'die' function to 'simple' module
* qmemman-meminfo-writer: send simplified meminfo value
* Add python-setuptools to build depends
* debian: adjust file list
* Install python modules to /usr
* initramfs: move qubes_cow_setup hook to pre-trigger
* initramfs: add support for root.img with partition table
* debian: fix install location of python files
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 08 Apr 2017 13:58:53 +0200
qubes-utils (3.2.4) unstable; urgency=medium
[ Johanna A ]
* Builds against 4.9
[ Marek Marczykowski-Górecki ]
* udev: use DM ignore device flag only for DM devices
[ Olivier MEDOC ]
* archlinux: clean up qubes-prepare-vm-kernel
* archlinux: clean up PKGBUILD and bump version number
[ Marek Marczykowski-Górecki ]
* travis: drop debootstrap workaround
[ Olivier MEDOC ]
* archlinux: use dracut native file instead of our own
[ M. Vefa Bicakci ]
* qubes-prepare-vm-kernel: Do not hardcode path to dracut
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 23 Mar 2017 11:34:01 +0100
qubes-utils (3.2.3) wheezy; urgency=medium
[ Marek Marczykowski-Górecki ]
* udev: make USB device version detection more generic
* debian: reformat Build-Depends
* debian: add pkg-config to Build-Depends
[ Rusty Bird ]
* udev-block-add-change: better mount status check
* udev-block-add-change: don't exclude already attached devs
* udev-block-add-change: simplify a check
[ Marek Marczykowski-Górecki ]
* udev-block-add-change: fix checking if partition is mounted
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 17 Jul 2016 05:17:40 +0200
qubes-utils (3.2.2) wheezy; urgency=medium
* udev: expose USB 3.0 devices for PV USB
* udev: ignore usbip-connected USB devices
* udev: fix removing USB entries
* qrexec-lib: convert tabs to spaces
* travis: initial version
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 02 Jun 2016 02:55:11 +0200
qubes-utils (3.2.1) wheezy; urgency=medium
* udev: fix deadlock on xenstore access during dom0 boot
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 18 May 2016 02:59:37 +0200
qubes-utils (3.2.0) wheezy; urgency=medium
[ Johanna A ]
* Builds against linux v4.6-rc4
[ Marek Marczykowski-Górecki ]
* u2mfn: build for both 4.6+ and older kernels
* udev/qvm-block: exclude devices used elsewhere
* udev/qvm-block: exclude device if its partition is already attached
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 16 May 2016 11:54:16 +0200
qubes-utils (3.1.8) wheezy; urgency=medium
[ Marek Marczykowski-Górecki ]
* udev: fix hiding devices from qvm-block
[ Olivier MEDOC ]
* archlinux: ensure gcc, make and pkgconfig are makedependencies
* archlinux: implement kernel-support
* kernel-support: compile u2mfn from source even if it has been never
built
* archlinux: add an install file specifically for vm-kernel-support
* archlinux: fix syntax errors in install file
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 08 Feb 2016 05:06:21 +0100
qubes-utils (3.1.7) wheezy; urgency=medium
[ pqg ]
* Fix build (installation) on Archlinux
[ Marek Marczykowski-Górecki ]
* Fix building Fedora package after Archlinux build fixes
* udev: do not assume static device-mapper major number
* udev: ignore devices set to be ignore elsewhere
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 07 Jan 2016 05:59:40 +0100
qubes-utils (3.1.6) wheezy; urgency=medium
[ HW42 ]
* debian: remove obsolete conffiles in /etc/udev/rules.d
[ Marek Marczykowski-Górecki ]
* qrexec-lib: add glibc version test check for having syncfs
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 13 Dec 2015 04:38:27 +0100
qubes-utils (3.1.5) wheezy; urgency=medium
* Fix for "debian: split libraries out of qubes-utils package"
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 30 Nov 2015 05:55:14 +0100
qubes-utils (3.1.4) wheezy; urgency=medium
[ qubesuser ]
* Fix u2mfn.ko for > 16TB RAM by not truncating to 32-bit improperly
[ Rusty Bird ]
* Check if QubesIncoming filesystem supports O_TMPFILE
[ Marek Marczykowski-Górecki ]
* rpm: disable debuginfo subpackage in qubes-kernel-vm-support
* initramfs: fix swap size
* qrexec: add clarification commends in qrexec.h
[ Rusty Bird ]
* qfile-unpacker: syncfs() to avoid qvm-move-to-vm data loss
[ Marek Marczykowski-Górecki ]
* initramfs: use units of sectors in sfdisk call
* initramfs: initialize volatile.img partition table also in
TemplateVM
* qubes-prepare-vm-kernel: ensure proper permissions on initramfs
* debian: resolve quilt-build-dep-but-no-series-file lintian warning
* Move udev scripts to /usr/lib/qubes, move rules to /lib/udev/
* makefile: honor build env CFLAGS and LDFLAGS
* debian: split libraries out of qubes-utils package
* debian: break hardlink before modifying debian/....dkms
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 27 Nov 2015 20:44:04 +0100
qubes-utils (3.1.3) wheezy; urgency=medium
* qrexec-lib: add qfile packing functions to libqubes-rpc-filecopy
* dracut: split 'full' dracut module into 'full-dmroot' and 'full-
modules'
* dracut: fix qubes-vm module dependencies
* dracut: mount only subdirectory of /lib/modules
* kernel-modules: build/install u2mfn module by default
* dracut: add dmsetup --noudevsync since we're running in pre-udev
hook
* debian: introduce qubes-kernel-vm-support package
* dracut: add a safety check preventing qubes_cow_setup.sh running in
dom0
* qrexec: define NOGUI_CMD_PREFIX
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 11 Nov 2015 05:12:11 +0100
qubes-utils (3.1.2) wheezy; urgency=medium
[ Marek Marczykowski-Górecki ]
* dracut: expand tabs to spaces
* dracut: abort on dmroot assemble error
* dracut: initialize volatile.img partitions
* libqrexec-utils: fix linker options
* libqrexec-utils: bring back buffered write helpers
* libqrexec-utils: bump SO version because of ABI change
[ qubesuser ]
* Fix u2mfn.ko for > 16TB RAM by not truncating to 32-bit improperly
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 24 Oct 2015 23:05:02 +0200
qubes-utils (3.1.1) wheezy; urgency=medium
[ Marek Marczykowski-Górecki ]
* qfile-unpacker: do not call fdatasync() at each file (#1257)
[ qubesuser ]
* Report Xen balloon current size instead of Linux total memory
* use 64-bit integers for memory sizes to support > 2 TB RAM
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 11 Oct 2015 02:48:12 +0200
qubes-utils (3.1.0) wheezy; urgency=medium
* impconverter: add icon data getters
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 30 Sep 2015 22:13:51 +0200
qubes-utils (3.0.10) wheezy; urgency=medium
[ Olivier MEDOC ]
* archlinux: update to match new dependancies and archlinux /usr/lib
guidelines
* archlinux: ensure /usr/sbin is not use to follow archlinux packaging
guidelines
[ Marek Marczykowski-Górecki ]
* imgconverter: ensure that connection to the VM is properly closed
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 08 Aug 2015 04:23:00 +0200
qubes-utils (3.0.9) wheezy; urgency=medium
* imgconverter: use more meaningful error for empty icon image
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 08 Jul 2015 05:58:15 +0200
qubes-utils (3.0.8) wheezy; urgency=medium
qubes-utils (2.0.21) wheezy; urgency=medium
* fedora: fix systemd service files permission
* udev: do not use a separate lock for udev block scripts
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 01 Jul 2015 07:11:28 +0200
qubes-utils (3.0.7) wheezy; urgency=medium
* imgconverter: add eq operation for Image class
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 28 Apr 2015 13:23:09 +0200
qubes-utils (3.0.6) wheezy; urgency=medium
* imgconverter: do not start gui daemon
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 15 Apr 2015 18:49:02 +0200
qubes-utils (3.0.5) wheezy; urgency=medium
* udev: fix block devices ignoring rule
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 03 Apr 2015 11:26:47 +0200
qubes-utils (3.0.4) wheezy; urgency=medium
* qrexec-lib: enable compiler optimization
* udev: ignore temporary devices created during VM startup
* udev: fix block devices ignoring rule
* imgconverter: use more meaningful error for empty icon image
* imgconverter: ensure that connection to the VM is properly closed
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 01 Apr 2015 00:11:15 +0200
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 29 Sep 2015 12:47:50 +0200
qubes-utils (3.0.3) wheezy; urgency=medium
qubes-utils (2.0.20) jessie; urgency=medium
* qrexec-lib: enable compiler optimization
* udev: allow normal user to access /dev/xen/xenbus for vchan
connections
* Add VM kernel related files as qubes-core-vm-kernel-support package
* dracut: do not assume full udevd running inside initramfs
* Provide a script to generate VM kernel files
* dracut: Provide minimalistic initramfs files - no udev, no systemd
* dracut: load ext4 module manually in minimalistic dracut module
* Compile u2mfn module only when not already present
* archlinux: fix new packaging requirements related to run, sbin,
lib64...
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 26 Mar 2015 23:57:42 +0100
-- Olivier MEDOC <o_medoc@yahoo.fr> Mon, 02 Feb 2015 00:19:22 +0100
qubes-utils (3.0.2) jessie; urgency=medium
qubes-utils (2.0.19) jessie; urgency=medium
[ Marek Marczykowski-Górecki ]
* qrexec: create stdin/out/err as sockets instead of pipes
* debian: O_TMPFILE already defined
[ Jason Mehring ]
* Removed -Werror from qrexec Makefile to allow unpack to compile for
both Fedora 20 and 21
* debian: Modified control file for new R3 Debian depends
* debian: Updated changelog to reflect 3.0.1 version change
* debian: Added qubesdb-vm as a depend
* debian: Revert back to using libxen-dev as depend
[ Marek Marczykowski-Górecki ]
* Revert "Removed -Werror from qrexec Makefile to allow unpack to
compile for both Fedora 20 and 21"
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 17 Feb 2015 14:22:38 +0100
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 01 Feb 2015 03:07:29 +0100
qubes-utils (3.0.1) jessie; urgency=medium
qubes-utils (2.0.18) jessie; urgency=medium
[ Wojciech Zygmunt Porczyk ]
* v3.0.1
* This has to be versioned because of dependency in core-agent-linux.
[ Marek Marczykowski-Górecki ]
* Update for new vchan API, remove code not needed anymore
* filecopy: fix handling ENOENT error
* Do not fail when file was successfully created.
* I will test before commit. I will test before commit. I will...
[ Marek Marczykowski-Górecki ]
* filecopy: really do not use O_TMPFILE when use_tmpfile==0
* When file opened with O_TMPFILE but use_tmpfile==0, the file will not be
linked to the directory (the code at the end of process_one_file_reg).
Additionally it is waste of time trying using O_TMPFILE when it's
already known it shouldn't be.
Also use_tmpfile==0 can mean we don't have access to /proc
(set_procfs_fd wasn't called), so even if linking the file to its
directory would be attempted, it would fail. This is the case for
dom0-updates copy.
[ Marek Marczykowski-Górecki ]
* filecopy: create new file unaccessible to the user until fully written
Otherwise source domain can modify (append) the file while the user
already is accessing it. While incoming files should be treated as
untrusted, this problem could allow file modification after the user
makes some sanity checks.
[ Marek Marczykowski-Górecki ]
* udev: update hotplug block scripts for QubesDB
* Some initial work was done, but apparently not complete and buggy.
[ Marek Marczykowski-Górecki ]
* version 3.0.0
[ Marek Marczykowski-Górecki ]
* Fix compile warnings
[ Marek Marczykowski-Górecki ]
* qrexec-utils: add read_vchan_all and write_vchan_all
* Similar to read_all and write_all.
[ Marek Marczykowski-Górecki ]
* qrexec: update protocol
- add new messages
- uniform packet header
- organize #defines
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 23 Jan 2015 01:22:10 +0100
[ Marek Marczykowski-Górecki ]
* code style: change tabs to spaces
qubes-utils (2.0.17) jessie; urgency=medium
[ Marek Marczykowski-Górecki ]
* qrexec-utils: disable write-stdin (buffered writes) compilation
* Not compatible with new qrexec protocol yet. To be done.
* filecopy: really do not use O_TMPFILE when use_tmpfile==0
[ Marek Marczykowski-Górecki ]
* New qrexec protocol
* Use separate vchan to pass I/O for each process, which greatly simplify
protocol implementation (eg. no flow control needed).
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 21 Jan 2015 16:07:40 +0100
[ Marek Marczykowski-Górecki ]
* udev: setup permissions on xen device nodes
qubes-utils (2.0.16) jessie; urgency=medium
[ Marek Marczykowski ]
* qrexec-lib: prevent deadlock on vchan
It can happen that we already cleared libvchan_fd pending state via
libvchan_wait, but data arrived later. This is especially true just
after connection, when client send unsolicited notification to server,
which can confuse it with some requested notification.
* filecopy: create new file unaccessible to the user until fully
written
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 10 Feb 2015 00:00:00 +0100
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 18 Jan 2015 18:05:35 +0100
qubes-utils (3.0.0) jessie; urgency=medium
qubes-utils (2.0.15) jessie; urgency=medium
[ HW42 ]
* use systemd in debian
[ Marek Marczykowski ]
* Update for new vchan API, remove code not needed anymore
* Use Qubes DB instead of Xenstore
* qrexec-lib: prevent deadlock on vchan
[ Marek Marczykowski-Górecki ]
* udev: setup permissions on xen device nodes
* New qrexec protocol
* qrexec-utils: disable write-stdin (buffered writes) compilation
* code style: change tabs to spaces
* qrexec: update protocol
* qrexec-utils: add read_vchan_all and write_vchan_all
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 01 Dec 2014 04:32:48 +0100
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 22 Nov 2014 16:24:11 +0100
qubes-utils (2.0.14) jessie; urgency=medium
[ Marek Marczykowski-Górecki ]

42
debian/control vendored

@ -2,12 +2,7 @@ Source: qubes-utils
Section: admin
Priority: extra
Maintainer: Davíð Steinn Geirsson <david@dsg.is>
Build-Depends:
libxen-dev,
pkg-config,
debhelper (>= 9.0.0),
dh-systemd,
python-setuptools,
Build-Depends: libvchan-xen-dev, libxen-dev, debhelper (>= 8.0.0), quilt (>= 0.60), dh-systemd
Standards-Version: 3.9.3
Homepage: http://www.qubes-os.org
Vcs-Git: http://dsg.is/qubes/qubes-linux-utils.git
@ -15,41 +10,8 @@ Vcs-Git: http://dsg.is/qubes/qubes-linux-utils.git
Package: qubes-utils
Architecture: any
Depends: lsb-base, python-pil, python-numpy, python3-pil, python3-numpy, ${shlibs:Depends}, ${misc:Depends}
Depends: libvchan-xen, lsb-base, ${shlibs:Depends}, ${misc:Depends}
Conflicts: qubes-linux-utils
Breaks: qubes-core-agent (<< 3.1.4)
Recommends: python2.7
Description: Qubes Linux utilities
This package includes the basic qubes utilities necessary for domU.
Package: qubes-kernel-vm-support
Architecture: any
Depends:
busybox,
initramfs-tools | dracut,
grub2-common,
${misc:Depends}
Description: Qubes VM kernel and initramfs modules
This package contains:
1. mkinitramfs 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.
Package: libqubes-rpc-filecopy2
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Breaks: qubes-utils (<< 3.1.4)
Replaces: qubes-utils (<< 3.1.4)
Description: Qubes file copy protocol library
This library can be used for both sending files using qfile protocol and for
receiving them.
Package: libqubes-rpc-filecopy-dev
Architecture: any
Section: libdevel
Depends: libqubes-rpc-filecopy2 (= ${binary:Version}), ${misc:Depends}
Breaks: qubes-utils (<< 3.1.4)
Replaces: qubes-utils (<< 3.1.4)
Description: Development headers for libqrexec-utils
This package contains files required to compile Qubes file copy related
utilities like qfile-agent.

@ -1,2 +0,0 @@
usr/include/libqubes-rpc-filecopy.h
usr/lib/libqubes-rpc-filecopy.so

@ -1 +0,0 @@
usr/lib/libqubes-rpc-filecopy.so.2*

@ -1 +0,0 @@
libqubes-rpc-filecopy 2 libqubes-rpc-filecopy2 (>= 3.1.3)

@ -1,8 +0,0 @@
usr/share/initramfs-tools/scripts/local-top/scrub_pages
usr/share/initramfs-tools/scripts/local-top/qubes_cow_setup
usr/share/initramfs-tools/hooks/qubes_vm
usr/lib/dracut/modules.d/90qubes-vm/*
usr/lib/dracut/modules.d/90qubes-vm-modules/*
usr/lib/dracut/modules.d/90qubes-vm-simple/*
usr/lib/dracut/modules.d/80xen-scrub-pages/*
etc/default/grub.d/30-qubes-kernel-vm-support.cfg

@ -1,64 +0,0 @@
#!/bin/bash
# postinst script for qubes-kernel-vm-support
#
# see: dh_installdeb(1)
set -e
# The postinst script may be called in the following ways:
# * <postinst> 'configure' <most-recently-configured-version>
# * <old-postinst> 'abort-upgrade' <new version>
# * <conflictor's-postinst> 'abort-remove' 'in-favour' <package>
# <new-version>
# * <postinst> 'abort-remove'
# * <deconfigured's-postinst> 'abort-deconfigure' 'in-favour'
# <failed-install-package> <version> 'removing'
# <conflicting-package> <version>
#
# For details, see http://www.debian.org/doc/debian-policy/ or
# https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html or
# the debian-policy package
case "${1}" in
configure)
if [ -x /usr/sbin/update-initramfs ]; then
if update-initramfs -u; then
# "milestone" initramfs update version:
# 1 - addition of xen scrub_pages enabling code
echo 1 > /var/lib/qubes/initramfs-updated
fi
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
exit 0
;;
*)
echo "postinst called with unknown argument \`${1}'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
## https://phabricator.whonix.org/T377
## Debian has no update-grub trigger yet:
## https://bugs.debian.org/481542
if command -v update-grub >/dev/null 2>&1; then
update-grub || \
echo "$DPKG_MAINTSCRIPT_PACKAGE $DPKG_MAINTSCRIPT_NAME ERROR: Running \
'update-grub' failed with exit code $?. $DPKG_MAINTSCRIPT_PACKAGE is most \
likely only the trigger, not the cause. Unless you know this is not an issue, \
you should fix running 'update-grub', otherwise your system might no longer \
boot." >&2
fi
exit 0
# vim: set ts=4 sw=4 sts=4 et :

@ -1,9 +0,0 @@
#!/bin/bash
set -e
mkdir --parents /boot/grub || true
#DEBHELPER#
exit 0

@ -1,5 +0,0 @@
usr/sbin/meminfo-writer
lib/systemd/system/qubes-meminfo-writer.service
usr/lib/qubes/*
usr/lib/python2.7/dist-packages/qubesimgconverter*/*
lib/udev/*

@ -1,3 +0,0 @@
rm_conffile /etc/udev/rules.d/99-qubes-block.rules 3.1.6~
rm_conffile /etc/udev/rules.d/99-qubes-usb.rules 3.1.6~
rm_conffile /etc/udev/rules.d/99-qubes-misc.rules 3.1.6~

10
debian/rules vendored

@ -1,7 +1,7 @@
#!/usr/bin/make -f
# -*- makefile -*-
export DESTDIR=$(shell pwd)/debian/tmp
export DESTDIR=$(shell pwd)/debian/qubes-utils
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
@ -13,10 +13,4 @@ override_dh_auto_build:
make all LIBDIR=/usr/lib DEBIANBUILD=1
override_dh_auto_install:
make install LIBDIR=/usr/lib DEBIANBUILD=1 PYTHON_PREFIX_ARG=--install-layout=deb
make install-debian-kernel-support LIBDIR=/usr/lib DEBIANBUILD=1
# dom0-only file
rm -f $(DESTDIR)/usr/sbin/qubes-prepare-vm-kernel
override_dh_install:
dh_install --fail-missing
make install LIBDIR=/usr/lib DEBIANBUILD=1

@ -1,5 +0,0 @@
install:
$(MAKE) -C simple
$(MAKE) -C full-dmroot
$(MAKE) -C full-modules
$(MAKE) -C xen-balloon-scrub-pages

@ -1,4 +0,0 @@
install:
install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm
install module-setup.sh qubes_cow_setup.sh \
$(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm/

@ -1,21 +0,0 @@
#!/bin/bash
check() {
if xenstore-read qubes-vm-type &>/dev/null || qubesdb-read /qubes-vm-type &>/dev/null; then
return 0
else
return 255
fi
}
depends() {
echo dm
return 0
}
install() {
inst_hook pre-trigger 90 $moddir/qubes_cow_setup.sh
inst_multiple \
sfdisk \
mkswap
}

@ -1,114 +0,0 @@
#!/bin/sh
#
# This file should be placed in pre-trigger directory in dracut's initramfs, or
# scripts/local-top in case of initramfs-tools
#
# initramfs-tools (Debian) API
PREREQS=""
case "$1" in
prereqs)
# This runs during initramfs creation
echo "$PREREQS"
exit 0
;;
esac
# This runs inside real initramfs
if [ -r /scripts/functions ]; then
# We're running in Debian's initramfs
. /scripts/functions
alias die=panic
alias info=true
alias warn=log_warning_msg
alias log_begin=log_begin_msg
alias log_end=log_end_msg
elif [ -r /lib/dracut-lib.sh ]; then
. /lib/dracut-lib.sh
alias log_begin=info
alias log_end=true
else
die() {
echo "$@"
exit 1
}
alias info=echo
alias warn=echo
alias log_begin=echo
alias log_end=true
fi
info "Qubes initramfs script here:"
if ! grep -q 'root=[^ ]*dmroot' /proc/cmdline; then
warn "dmroot not requested, probably not a Qubes VM"
exit 0
fi
if [ -e /dev/mapper/dmroot ] ; then
die "Qubes: FATAL error: /dev/mapper/dmroot already exists?!"
fi
modprobe xenblk || modprobe xen-blkfront || warn "Qubes: Cannot load Xen Block Frontend..."
log_begin "Waiting for /dev/xvda* devices..."
udevadm settle --exit-if-exists=/dev/xvda
log_end
# prefer partition if exists
if [ -b /dev/xvda1 ]; then
if [ -e "/dev/disk/by-partlabel/Root\\x20filesystem" ]; then
ROOT_DEV=$(basename $(readlink "/dev/disk/by-partlabel/Root\\x20filesystem"))
else
ROOT_DEV=xvda3
fi
else
ROOT_DEV=xvda
fi
SWAP_SIZE=$(( 1024 * 1024 * 2 )) # sectors, 1GB
if [ `cat /sys/class/block/$ROOT_DEV/ro` = 1 ] ; then
log_begin "Qubes: Doing COW setup for AppVM..."
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
VOLATILE_SIZE=$(cat /sys/class/block/xvdc/size) # sectors
ROOT_SIZE=$(cat /sys/class/block/$ROOT_DEV/size) # sectors
if [ $VOLATILE_SIZE -lt $SWAP_SIZE ]; then
die "volatile.img smaller than 1GB, cannot continue"
fi
sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
xvdc1: type=82,start=2048,size=$SWAP_SIZE
xvdc2: type=83
EOF
if [ $? -ne 0 ]; then
die "Qubes: failed to setup partitions on volatile device"
fi
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
mkswap /dev/xvdc1
while ! [ -e /dev/xvdc2 ]; do sleep 0.1; done
echo "0 `cat /sys/class/block/$ROOT_DEV/size` snapshot /dev/$ROOT_DEV /dev/xvdc2 N 16" | \
dmsetup --noudevsync create dmroot || die "Qubes: FATAL: cannot create dmroot!"
dmsetup mknodes dmroot
log_end
else
log_begin "Qubes: Doing R/W setup for TemplateVM..."
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
xvdc1: type=82,start=2048,size=$SWAP_SIZE
xvdc3: type=83
EOF
if [ $? -ne 0 ]; then
die "Qubes: failed to setup partitions on volatile device"
fi
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
mkswap /dev/xvdc1
mkdir -p /etc/udev/rules.d
printf 'KERNEL=="%s", SYMLINK+="mapper/dmroot"\n' "$ROOT_DEV" >> \
/etc/udev/rules.d/99-root.rules
udevadm control -R
udevadm trigger
log_end
fi

@ -1,4 +0,0 @@
install:
install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-modules
install module-setup.sh mount_modules.sh \
$(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-modules/

@ -1,9 +0,0 @@
#!/bin/bash
check() {
return 255
}
install() {
inst_hook pre-pivot 50 $moddir/mount_modules.sh
}

@ -1,25 +0,0 @@
#!/bin/sh
#
# This file should be places in pre-pivot directory in dracut's initramfs
#
kver="`uname -r`"
if ! [ -d "$NEWROOT/lib/modules/$kver/kernel" ]; then
echo "Waiting for /dev/xvdd device..."
while ! [ -e /dev/xvdd ]; do sleep 0.1; done
# Mount only `uname -r` subdirectory, to leave the rest of /lib/modules writable
mkdir -p /tmp/modules
mount -n -t ext3 /dev/xvdd /tmp/modules
if ! [ -d "$NEWROOT/lib/modules/$kver" ]; then
mount "$NEWROOT" -o remount,rw
mkdir -p "$NEWROOT/lib/modules/$kver"
mount "$NEWROOT" -o remount,ro
fi
mount --bind "/tmp/modules/$kver" "$NEWROOT/lib/modules/$kver"
umount /tmp/modules
rmdir /tmp/modules
fi
killall udevd systemd-udevd

@ -1,6 +0,0 @@
install:
install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-simple
install module-setup.sh init.sh \
$(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-simple/
# flag indicating the module will (re-)enable scrub-pages option
touch $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-simple/xen-scrub-pages-supported

@ -1,121 +0,0 @@
#!/bin/sh
echo "Qubes initramfs script here:"
mkdir -p /proc /sys /dev
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
if [ -w /sys/devices/system/xen_memory/xen_memory0/scrub_pages ]; then
# re-enable xen-balloon pages scrubbing, after initial balloon down
echo 1 > /sys/devices/system/xen_memory/xen_memory0/scrub_pages
fi
if [ -e /dev/mapper/dmroot ] ; then
echo "Qubes: FATAL error: /dev/mapper/dmroot already exists?!"
fi
/sbin/modprobe xenblk || /sbin/modprobe xen-blkfront || echo "Qubes: Cannot load Xen Block Frontend..."
die() {
echo "$@" >&2
exit 1
}
echo "Waiting for /dev/xvda* devices..."
while ! [ -e /dev/xvda ]; do sleep 0.1; done
# prefer partition if exists
if [ -b /dev/xvda1 ]; then
if [ -d /dev/disk/by-partlabel ]; then
ROOT_DEV=$(basename $(readlink "/dev/disk/by-partlabel/Root\\x20filesystem"))
else
ROOT_DEV=$(grep -l "PARTNAME=Root filesystem" /sys/block/xvda/xvda*/uevent |\
grep -o "xvda[0-9]")
fi
if [ -z "$ROOT_DEV" ]; then
# fallback to third partition
ROOT_DEV=xvda3
fi
else
ROOT_DEV=xvda
fi
SWAP_SIZE=$(( 1024 * 1024 * 2 )) # sectors, 1GB
if [ `cat /sys/class/block/$ROOT_DEV/ro` = 1 ] ; then
echo "Qubes: Doing COW setup for AppVM..."
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
VOLATILE_SIZE=$(cat /sys/class/block/xvdc/size) # sectors
ROOT_SIZE=$(cat /sys/class/block/$ROOT_DEV/size) # sectors
if [ $VOLATILE_SIZE -lt $SWAP_SIZE ]; then
die "volatile.img smaller than 1GB, cannot continue"
fi
/sbin/sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
xvdc1: type=82,start=2048,size=$SWAP_SIZE
xvdc2: type=83
EOF
if [ $? -ne 0 ]; then
echo "Qubes: failed to setup partitions on volatile device"
exit 1
fi
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
/sbin/mkswap /dev/xvdc1
while ! [ -e /dev/xvdc2 ]; do sleep 0.1; done
echo "0 `cat /sys/class/block/$ROOT_DEV/size` snapshot /dev/$ROOT_DEV /dev/xvdc2 N 16" | \
/sbin/dmsetup create dmroot || { echo "Qubes: FATAL: cannot create dmroot!"; exit 1; }
/sbin/dmsetup mknodes dmroot
echo Qubes: done.
else
echo "Qubes: Doing R/W setup for TemplateVM..."
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
/sbin/sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
xvdc1: type=82,start=2048,size=$SWAP_SIZE
xvdc3: type=83
EOF
if [ $? -ne 0 ]; then
die "Qubes: failed to setup partitions on volatile device"
fi
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
/sbin/mkswap /dev/xvdc1
ln -s ../$ROOT_DEV /dev/mapper/dmroot
echo Qubes: done.
fi
/sbin/modprobe ext4
mkdir -p /sysroot
mount /dev/mapper/dmroot /sysroot -o rw
NEWROOT=/sysroot
kver="`uname -r`"
if ! [ -d "$NEWROOT/lib/modules/$kver/kernel" ]; then
echo "Waiting for /dev/xvdd device..."
while ! [ -e /dev/xvdd ]; do sleep 0.1; done
mkdir -p /tmp/modules
mount -n -t ext3 /dev/xvdd /tmp/modules
if /sbin/modprobe overlay; then
# if overlayfs is supported, use that to provide fully writable /lib/modules
if ! [ -d "$NEWROOT/lib/.modules_work" ]; then
mkdir -p "$NEWROOT/lib/.modules_work"
fi
mount -t overlay none $NEWROOT/lib/modules -o lowerdir=/tmp/modules,upperdir=$NEWROOT/lib/modules,workdir=$NEWROOT/lib/.modules_work
else
# otherwise mount only `uname -r` subdirectory, to leave the rest of
# /lib/modules writable
if ! [ -d "$NEWROOT/lib/modules/$kver" ]; then
mkdir -p "$NEWROOT/lib/modules/$kver"
fi
mount --bind "/tmp/modules/$kver" "$NEWROOT/lib/modules/$kver"
fi
umount /tmp/modules
rmdir /tmp/modules
fi
umount /dev /sys /proc
mount "$NEWROOT" -o remount,ro
exec /sbin/switch_root $NEWROOT /sbin/init

@ -1,34 +0,0 @@
#!/bin/bash
check() {
return 255
}
depends() {
echo dm
return 0
}
installkernel() {
hostonly='' instmods overlay
}
install() {
inst $moddir/init.sh /init
inst_multiple \
basename \
readlink \
uname \
grep \
kmod \
modprobe \
ln \
switch_root \
mount \
umount \
mkdir \
rmdir \
sleep \
sfdisk \
mkswap
}

@ -1,4 +0,0 @@
install:
install -d $(DESTDIR)/usr/lib/dracut/modules.d/80xen-scrub-pages
install module-setup.sh scrub_pages.sh \
$(DESTDIR)/usr/lib/dracut/modules.d/80xen-scrub-pages/

@ -1,17 +0,0 @@
#!/bin/bash
check() {
if [ -r /usr/share/qubes/marker-vm ]; then
return 0
else
return 255
fi
}
depends() {
return 0
}
install() {
inst_hook pre-trigger 60 $moddir/scrub_pages.sh
}

@ -1,20 +0,0 @@
#!/bin/sh
#
# This file should be placed in pre-trigger directory in dracut's initramfs, or
# scripts/local-top in case of initramfs-tools
#
# initramfs-tools (Debian) API
PREREQS=""
case "$1" in
prereqs)
# This runs during initramfs creation
echo "$PREREQS"
exit 0
;;
esac
if [ -w /sys/devices/system/xen_memory/xen_memory0/scrub_pages ]; then
# re-enable xen-balloon pages scrubbing, after initial balloon down
echo 1 > /sys/devices/system/xen_memory/xen_memory0/scrub_pages
fi

@ -1,7 +0,0 @@
install-fedora:
install -D -m 0644 grub.qubes-kernel-vm-support \
$(DESTDIR)/etc/default/grub.qubes-kernel-vm-support
install-debian:
install -D -m 0644 grub.qubes-kernel-vm-support \
$(DESTDIR)/etc/default/grub.d/30-qubes-kernel-vm-support.cfg

@ -1,8 +0,0 @@
# add kernel options only in VM, and only if initramfs is updated already
# /var/lib/qubes/initramfs-updated contains "milestone" initramfs update version:
# 1 - addition of xen scrub_pages enabling code
if [ -r /usr/share/qubes/marker-vm ] &&
[ "$(cat /var/lib/qubes/initramfs-updated 2>/dev/null || echo 0)" -ge 1 ]; then
GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX xen_scrub_pages=0"
fi
GRUB_ENABLE_BLSCFG=false

@ -1,18 +0,0 @@
PYTHON ?= python
all:
$(PYTHON) setup.py build
.PHONY: all
clean:
$(PYTHON) setup.py clean
.PHONY: clean
install:
$(PYTHON) setup.py install -O1 $(PYTHON_PREFIX_ARG) --root $(DESTDIR)
#ifeq (1,${DEBIANBUILD})
# cp *.py $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
#else
# cp *.py* $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
#endif
.PHONY: install

@ -1,90 +0,0 @@
#!/usr/bin/env python2
'''Qubes Image Generation
Toolkit for generating icons and images for Qubes OS.'''
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2013-2015 Wojtek Porczyk <woju@invisiblethingslab.com>
#
# 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.
from __future__ import absolute_import
__all__ = ['make_padlock']
import math
import cairo
import qubesimgconverter
def polar(r, a):
return r * math.cos(a), r * math.sin(a)
def make_padlock(dst, colour, size=qubesimgconverter.ICON_MAXSIZE, disp=False):
cs = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size)
cr = cairo.Context(cs)
cr.set_source_rgb(*[c / 256.0
for c in qubesimgconverter.hex_to_int(colour)])
cr.set_line_width(.125 * size)
cr.rectangle(.125 * size, .5 * size, .75 * size, .4375 * size)
cr.fill()
cr.move_to(.25 * size, .5 * size)
cr.line_to(.25 * size, .375 * size)
cr.arc(.5 * size, .375 * size, .25 * size, math.pi, 2 * math.pi)
cr.move_to(.75 * size, .375 * size) # this is unneccessary, but helps readability
cr.line_to(.75 * size, .5 * size)
cr.stroke()
if disp:
# Careful with those. I have run into severe
# floating point errors when adjusting.
arrows = 2
gap = 45 * math.pi / 180
offset = 0
radius = .1875 * size
width = 0.05 * size
cx = .5 * size
# cy = .6875 * size
cy = .625 * size
arrow = 2 * math.pi / arrows
for i in range(arrows):
cr.move_to(cx, cy)
cr.rel_move_to(*polar( radius - width, offset + i * arrow))
cr.arc(cx, cy, radius - width, offset + i * arrow, offset + (i + 1) * arrow - gap)
cr.rel_line_to(*polar( width, offset + (i + 1) * arrow - gap + math.pi))
cr.rel_line_to(*polar( width * math.sqrt(8), offset + (i + 1) * arrow - gap + math.pi / 4))
cr.rel_line_to(*polar( width * math.sqrt(8), offset + (i + 1) * arrow - gap - math.pi / 4))
cr.rel_line_to(*polar( width, offset + (i + 1) * arrow - gap + math.pi))
cr.arc_negative(cx, cy, radius + width, offset + (i + 1) * arrow - gap, offset + i * arrow)
cr.close_path()
cr.set_source_rgb(0xcc / 256.0, 0, 0) # tango's red
cr.set_line_width(.0500 * size)
cr.set_line_join(cairo.LINE_JOIN_ROUND)
cr.stroke_preserve()
cr.set_source_rgb(1.0, 1.0, 1.0)
cr.fill()
cs.write_to_png(dst)
# vim: ft=python sw=4 ts=4 et

@ -1,81 +0,0 @@
#!/usr/bin/env python2
from __future__ import absolute_import
try:
from io import BytesIO
except ImportError:
from cStringIO import StringIO as BytesIO
import unittest
import qubesimgconverter
class TestCaseImage(unittest.TestCase):
def setUp(self):
self.rgba = \
b'\x00\x00\x00\xff' b'\xff\x00\x00\xff' \
b'\x00\xff\x00\xff' b'\x00\x00\x00\xff'
self.size = (2, 2)
self.image = qubesimgconverter.Image(rgba=self.rgba, size=self.size)
def test_00_init(self):
self.assertEqual(self.image._rgba, self.rgba)
self.assertEqual(self.image._size, self.size)
def test_01_tint(self):
image = self.image.tint('#0000ff')
self.assertEqual(image._rgba,
b'\x00\x00\x3f\xff' b'\x00\x00\xff\xff'
b'\x00\x00\xff\xff' b'\x00\x00\x3f\xff')
def test_10_get_from_stream(self):
io = BytesIO('{0[0]} {0[1]}\n'.format(self.size).encode() + self.rgba)
image = qubesimgconverter.Image.get_from_stream(io)
self.assertEqual(image._rgba, self.rgba)
self.assertEqual(image._size, self.size)
def test_11_get_from_stream_malformed(self):
io = BytesIO('{0[0]} {0[1]}\n'.format(self.size).encode() +
self.rgba[:-1]) # one byte too short
with self.assertRaises(Exception):
image = qubesimgconverter.Image.get_from_stream(io)
def test_12_get_from_stream_too_big(self):
io = BytesIO('{0[0]} {0[1]}\n'.format(self.size).encode() + self.rgba) # 2x2
with self.assertRaises(Exception):
image = qubesimgconverter.Image.get_from_stream(io, max_width=1)
io.seek(0)
with self.assertRaises(Exception):
image = qubesimgconverter.Image.get_from_stream(io, max_height=1)
class TestCaseFunctionsAndConstants(unittest.TestCase):
def test_00_imghdrlen(self):
self.assertEqual(qubesimgconverter.imghdrlen(8, 15), len('8 15\n'))
self.assertEqual(qubesimgconverter.imghdrlen(100, 100), len('100 100\n'))
def test_01_re_imghdr(self):
self.assertTrue(qubesimgconverter.re_imghdr.match(b'8 15\n'))
self.assertIsNone(qubesimgconverter.re_imghdr.match(b'8 15'))
self.assertIsNone(qubesimgconverter.re_imghdr.match(b'815\n'))
self.assertIsNone(qubesimgconverter.re_imghdr.match(b'x yx\n'))
def test_10_hex_to_float_result_00(self):
self.assertEqual(qubesimgconverter.hex_to_int('#000000'), (0, 0, 0))
def test_11_hex_to_float_result_ff(self):
self.assertEqual(qubesimgconverter.hex_to_int('0xffffff'),
(0xff, 0xff, 0xff))
def test_12_hex_to_float_depth_3_not_implemented(self):
with self.assertRaises(ValueError):
qubesimgconverter.hex_to_int('123456', depth=3)
if __name__ == '__main__':
unittest.main()

@ -1,99 +0,0 @@
# vim: fileencoding=utf-8
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2017
# Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
#
# 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.
#
import itertools
import qubes.tests.extra
# noinspection PyPep8Naming
class TC_00_ImgConverter(qubes.tests.extra.ExtraTestCase):
def setUp(self):
super(TC_00_ImgConverter, self).setUp()
# noinspection PyAttributeOutsideInit
self.vm = self.create_vms(["vm"])[0]
self.vm.start()
self.image_size = 16
# RGB data for the image
self.image_data = [
(0xff // self.image_size * x, 0x80, 0xff // self.image_size * y,
0xff)
for x in range(self.image_size)
for y in range(self.image_size)]
def create_img(self, filename):
'''Create image file with given sample content
:param filename: output filename
'''
p = self.vm.run(
'convert -size {}x{} -depth 8 rgba:- "{}" 2>&1'.format(
self.image_size, self.image_size, filename),
passio_popen=True)
bytes_data = bytes(bytearray(itertools.chain(*self.image_data)))
(stdout, _) = p.communicate(bytes_data)
if p.returncode != 0:
self.skipTest('failed to create test image: {}'.format(stdout))
def assertCorrectlyTransformed(self, orig_filename, trusted_filename):
self.assertEquals(
self.vm.run('test -r "{}"'.format(trusted_filename), wait=True), 0)
self.assertEquals(
self.vm.run('test -r "{}"'.format(orig_filename), wait=True), 0)
# retrieve original image too, to compensate for compression
p = self.vm.run('convert "{}" rgb:-'.format(orig_filename),
passio_popen=True)
orig_image_data, _ = p.communicate()
p = self.vm.run('convert "{}" rgb:-'.format(trusted_filename),
passio_popen=True)
trusted_image_data, _ = p.communicate()
self.assertEquals(orig_image_data, trusted_image_data)
def test_000_png(self):
self.create_img('test.png')
p = self.vm.run('qvm-convert-img test.png trusted.png 2>&1',
passio_popen=True)
(stdout, _) = p.communicate()
if p.returncode == 127:
self.skipTest('qubes-img-converter not installed')
self.assertEquals(p.returncode, 0, 'qvm-convert-img failed: {}'.format(
stdout))
self.assertCorrectlyTransformed('test.png', 'trusted.png')
def test_010_filename_with_spaces(self):
self.create_img('test with spaces.png')
p = self.vm.run('qvm-convert-img "test with spaces.png" '
'"trusted with spaces.png" 2>&1',
passio_popen=True)
(stdout, _) = p.communicate()
if p.returncode == 127:
self.skipTest('qubes-img-converter not installed')
self.assertEquals(p.returncode, 0, 'qvm-convert-img failed: {}'.format(
stdout))
self.assertCorrectlyTransformed(
'test with spaces.png', 'trusted with spaces.png')
def list_tests():
tests = [TC_00_ImgConverter]
return tests

@ -1,19 +0,0 @@
import setuptools
setuptools.setup(
name='qubesimgconverter',
version=open('../version').read().strip(),
author='Invisible Things Lab',
author_email='woju@invisiblethingslab.com',
description='Toolkit for secure transfer and conversion of images between Qubes VMs.',
license='GPL2+',
url='https://www.qubes-os.org/',
packages=['qubesimgconverter'],
entry_points={
'qubes.tests.extra.for_template':
'qubesimgconverter = qubesimgconverter.test_integ:list_tests',
}
)
# vim: ts=4 sts=4 sw=4 et

@ -1,8 +0,0 @@
install:
install -D local-top/qubes_cow_setup.sh \
$(DESTDIR)/usr/share/initramfs-tools/scripts/local-top/qubes_cow_setup
install -D local-top/scrub_pages.sh \
$(DESTDIR)/usr/share/initramfs-tools/scripts/local-top/scrub_pages
install -D qubes_vm \
$(DESTDIR)/usr/share/initramfs-tools/hooks/qubes_vm

@ -1 +0,0 @@
../../dracut/full-dmroot/qubes_cow_setup.sh

@ -1 +0,0 @@
../../dracut/xen-balloon-scrub-pages/scrub_pages.sh

@ -1,21 +0,0 @@
#!/bin/sh
if grep -q '^[0-]*$' /sys/hypervisor/uuid; then
echo "Not intended for dom0"
exit 0
fi
PREREQS="dmsetup"
case "$1" in
prereqs)
echo "$PREREQS"
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
copy_exec /sbin/sfdisk
copy_exec /sbin/mkswap
force_load xen-blkfront
force_load dm-snapshot

@ -1,5 +0,0 @@
install: install-scripts
install-scripts:
install -d $(DESTDIR)/usr/sbin
install qubes-prepare-vm-kernel $(DESTDIR)/usr/sbin

@ -1,84 +0,0 @@
#!/bin/sh
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2015 Marek Marczykowski-Górecki
# <marmarekp@invisiblethingslab.com>
#
# 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.
#
#
set -e
basedir=/var/lib/qubes/vm-kernels
function build_modules_img() {
kver=$1
initramfs=$2
output_file=$3
mkdir /tmp/qubes-modules-$kver
truncate -s 400M /tmp/qubes-modules-$kver.img
mkfs -t ext3 -F /tmp/qubes-modules-$kver.img > /dev/null
mount /tmp/qubes-modules-$kver.img /tmp/qubes-modules-$kver -o loop
cp -a -t /tmp/qubes-modules-$kver /lib/modules/$kver
cp "/boot/vmlinuz-$kver" "/tmp/qubes-modules-$kver/vmlinuz"
cp "$initramfs" "/tmp/qubes-modules-$kver/initramfs"
umount /tmp/qubes-modules-$kver
rmdir /tmp/qubes-modules-$kver
mv /tmp/qubes-modules-$kver.img $output_file
}
function build_initramfs() {
kver=$1
output_file=$2
dracut --nomdadmconf --nolvmconf --force \
--modules "kernel-modules qubes-vm-simple" \
--conf /dev/null --confdir /var/empty \
-d "xenblk xen-blkfront cdrom ext4 jbd2 crc16 dm_snapshot" \
$output_file $kver
chmod 644 "$output_file"
}
if [ -z "$1" ]; then
echo "Usage: $0 <kernel-version> [<display-kernel-version>]" >&2
exit 1
fi
if [ ! -r /boot/vmlinuz-$1 -o ! -d /lib/modules/$1 ]; then
echo "ERROR: Kernel version $1 not installed" >&2
exit 1
fi
kernel_version=$1
if [ -n "$2" ]; then
output_dir="$basedir/$2"
else
output_dir="$basedir/$kernel_version"
fi
echo "--> Building files for $kernel_version in $output_dir"
mkdir -p "$output_dir"
cp "/boot/vmlinuz-$kernel_version" "$output_dir/vmlinuz"
echo "---> Generating initramfs"
build_initramfs "$kernel_version" "$output_dir/initramfs"
echo "---> Generating modules.img"
build_modules_img "$kernel_version" "$output_dir/initramfs" \
"$output_dir/modules.img"
echo "--> Done."

@ -1,7 +1,8 @@
CC=gcc
CFLAGS+=-Wall -Wextra -Werror -g -O3
CFLAGS=-Wall -Wextra -Werror -g -O3
SBINDIR ?= /usr/sbin
all: meminfo-writer
SBINDIR?=/usr/sbin
_XENSTORE_H=$(shell ls /usr/include/xenstore.h)
ifneq "$(_XENSTORE_H)" ""
@ -9,9 +10,9 @@ ifneq "$(_XENSTORE_H)" ""
endif
meminfo-writer: meminfo-writer.o
$(CC) $(LDFLAGS) -g -o meminfo-writer meminfo-writer.o -lxenstore
$(CC) -g -o meminfo-writer meminfo-writer.o -lxenstore
install:
install -D meminfo-writer $(DESTDIR)/$(SBINDIR)/meminfo-writer
install -D meminfo-writer $(DESTDIR)$(SBINDIR)/meminfo-writer
ifeq (1,${DEBIANBUILD})
install -d $(DESTDIR)/lib/systemd/system/
install -m 0644 qubes-meminfo-writer.service $(DESTDIR)/lib/systemd/system/

@ -16,21 +16,21 @@ int used_mem_change_threshold;
int delay;
int usr1_received;
const char *parse(const char *meminfo_buf, const char* dom_current_buf)
const char *parse(const char *buf)
{
const char *ptr = meminfo_buf;
const char *ptr = buf;
static char outbuf[4096];
long long val;
int val;
int len;
int ret;
long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapTotal =
int MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapTotal =
0, SwapFree = 0;
unsigned long long key;
long long used_mem, used_mem_diff;
long used_mem, used_mem_diff;
int nitems = 0;
while (nitems != (1<<6)-1 || !*ptr) {
ret = sscanf(ptr, "%*s %lld kB\n%n", &val, &len);
ret = sscanf(ptr, "%*s %d kB\n%n", &val, &len);
if (ret < 1 || len < (int)sizeof (unsigned long long)) {
ptr += len;
continue;
@ -59,12 +59,6 @@ const char *parse(const char *meminfo_buf, const char* dom_current_buf)
ptr += len;
}
if(dom_current_buf) {
long long DomTotal = strtoll(dom_current_buf, 0, 10);
if(DomTotal)
MemTotal = DomTotal;
}
used_mem =
MemTotal - Buffers - Cached - MemFree + SwapTotal - SwapFree;
if (used_mem < 0)
@ -78,7 +72,10 @@ const char *parse(const char *meminfo_buf, const char* dom_current_buf)
|| (used_mem > prev_used_mem && used_mem / 10 > (MemTotal+12) / 13
&& used_mem_diff > used_mem_change_threshold/2)) {
prev_used_mem = used_mem;
sprintf(outbuf, "%lld", used_mem);
sprintf(outbuf,
"MemTotal: %d kB\nMemFree: %d kB\nBuffers: %d kB\nCached: %d kB\n"
"SwapTotal: %d kB\nSwapFree: %d kB\n", MemTotal,
MemFree, Buffers, Cached, SwapTotal, SwapFree);
return outbuf;
}
return NULL;
@ -106,50 +103,13 @@ void usr1_handler(int sig __attribute__((__unused__))) {
usr1_received = 1;
}
static inline void pread0_string(int fd, char* buf, size_t buf_size)
{
int n = pread(fd, buf, buf_size - 1, 0);
if (n < 0) {
perror("pread");
exit(1);
}
buf[n] = 0;
}
static void update(struct xs_handle *xs, int meminfo_fd, int dom_current_fd)
{
char dom_current_buf[32];
char dom_current_buf2[32];
char meminfo_buf[4096];
const char *meminfo_data;
pread0_string(dom_current_fd, dom_current_buf, sizeof(dom_current_buf));
/* check until the dom current reading is stable to avoid races */
for(;;) {
pread0_string(meminfo_fd, meminfo_buf, sizeof(meminfo_buf));
pread0_string(dom_current_fd, dom_current_buf2, sizeof(dom_current_buf2));
if(!strcmp(dom_current_buf, dom_current_buf2))
break;
pread0_string(meminfo_fd, meminfo_buf, sizeof(meminfo_buf));
pread0_string(dom_current_fd, dom_current_buf, sizeof(dom_current_buf));
if(!strcmp(dom_current_buf, dom_current_buf2))
break;
}
meminfo_data = parse(meminfo_buf, dom_current_buf);
if (meminfo_data)
send_to_qmemman(xs, meminfo_data);
}
int main(int argc, char **argv)
{
int meminfo_fd, dom_current_fd;
struct xs_handle *xs;
char buf[4096];
int n;
const char *meminfo_data;
int fd;
struct xs_handle *xs;
if (argc != 3 && argc != 4)
usage();
@ -161,8 +121,6 @@ int main(int argc, char **argv)
if (argc == 4) {
pid_t pid;
sigset_t mask, oldmask;
int fd;
char buf[32];
switch (pid = fork()) {
case -1:
@ -197,14 +155,9 @@ int main(int argc, char **argv)
}
}
meminfo_fd = open("/proc/meminfo", O_RDONLY);
if (meminfo_fd < 0) {
perror("open /proc/meminfo");
exit(1);
}
dom_current_fd = open("/sys/devices/system/xen_memory/xen_memory0/info/current_kb", O_RDONLY);
if (dom_current_fd < 0) {
perror("open /sys/devices/system/xen_memory/xen_memory0/info/current_kb");
fd = open("/proc/meminfo", O_RDONLY);
if (fd < 0) {
perror("open meminfo");
exit(1);
}
xs = xs_domain_open();
@ -214,8 +167,15 @@ int main(int argc, char **argv)
}
if (argc == 3) {
/* if not waiting for signal, fork after first info written to xenstore */
update(xs, meminfo_fd, dom_current_fd);
n = pread(fd, buf, sizeof(buf)-1, 0);
if (n < 0) {
perror("pread");
exit(1);
}
buf[n] = 0;
meminfo_data = parse(buf);
if (meminfo_data)
send_to_qmemman(xs, meminfo_data);
n = fork();
if (n < 0) {
perror("fork");
@ -227,8 +187,15 @@ int main(int argc, char **argv)
}
for (;;) {
update(xs, meminfo_fd, dom_current_fd);
n = pread(fd, buf, sizeof(buf)-1, 0);
if (n < 0) {
perror("pread");
exit(1);
}
buf[n] = 0;
meminfo_data = parse(buf);
if (meminfo_data)
send_to_qmemman(xs, meminfo_data);
usleep(delay);
}
}

@ -1,6 +1,5 @@
[Unit]
Description=Qubes memory information reporter
Before=systemd-user-sessions.service
After=qubes-core.service qubes-qmemman.service
ConditionPathExists=/var/run/qubes/qmemman.sock

@ -1,10 +1,20 @@
CC=gcc
CFLAGS+=-I. -g -O2 -Wall -Wextra -Werror -pie -fPIC
SO_VER=2
LDFLAGS+=-shared
XENLIBS=-lxenctrl -lxenstore -lvchan
COMMONIOALL=ioall.o
SO_VER=1
LDFLAGS=-shared
all: libqubes-rpc-filecopy.so.$(SO_VER)
libqubes-rpc-filecopy.so.$(SO_VER): ioall.o copy-file.o crc32.o unpack.o pack.o
_XENSTORE_H=$(shell ls /usr/include/xenstore.h)
ifneq "$(_XENSTORE_H)" ""
CFLAGS+= -DUSE_XENSTORE_H
endif
all: libqrexec-utils.so.$(SO_VER) libqubes-rpc-filecopy.so.$(SO_VER)
libqrexec-utils.so.$(SO_VER): unix-server.o ioall.o buffer.o write-stdin.o exec.o txrx-vchan.o
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^ $(XENLIBS)
libqubes-rpc-filecopy.so.$(SO_VER): ioall.o copy-file.o crc32.o unpack.o
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^
%.a:
@ -14,7 +24,12 @@ clean:
install:
mkdir -p $(DESTDIR)$(LIBDIR)
cp libqrexec-utils.so.$(SO_VER) $(DESTDIR)$(LIBDIR)
ln -s libqrexec-utils.so.$(SO_VER) $(DESTDIR)$(LIBDIR)/libqrexec-utils.so
cp libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)
ln -s libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)/libqubes-rpc-filecopy.so
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp libqrexec-utils.h $(DESTDIR)$(INCLUDEDIR)
cp libqubes-rpc-filecopy.h $(DESTDIR)$(INCLUDEDIR)
cp qrexec.h $(DESTDIR)$(INCLUDEDIR)

@ -0,0 +1,115 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libqrexec-utils.h"
#define BUFFER_LIMIT 50000000
static int total_mem;
static char *limited_malloc(int len)
{
char *ret;
total_mem += len;
if (total_mem > BUFFER_LIMIT) {
fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n");
exit(1);
}
ret = malloc(len);
if (!ret) {
perror("malloc");
exit(1);
}
return ret;
}
static void limited_free(char *ptr, int len)
{
free(ptr);
total_mem -= len;
}
void buffer_init(struct buffer *b)
{
b->buflen = 0;
b->data = NULL;
}
void buffer_free(struct buffer *b)
{
if (b->buflen)
limited_free(b->data, b->buflen);
buffer_init(b);
}
/*
The following two functions can be made much more efficient.
Yet the profiling output show they are not significant CPU hogs, so
we keep them so simple to make them obviously correct.
*/
void buffer_append(struct buffer *b, const char *data, int len)
{
int newsize;
char *qdata;
if (len < 0 || len > BUFFER_LIMIT) {
fprintf(stderr, "buffer_append %d\n", len);
exit(1);
}
if (len == 0)
return;
newsize = len + b->buflen;
qdata = limited_malloc(len + b->buflen);
memcpy(qdata, b->data, b->buflen);
memcpy(qdata + b->buflen, data, len);
buffer_free(b);
b->buflen = newsize;
b->data = qdata;
}
void buffer_remove(struct buffer *b, int len)
{
int newsize;
char *qdata = NULL;
if (len < 0 || len > b->buflen) {
fprintf(stderr, "buffer_remove %d/%d\n", len, b->buflen);
exit(1);
}
newsize = b->buflen - len;
if (newsize > 0) {
qdata = limited_malloc(newsize);
memcpy(qdata, b->data + len, newsize);
}
buffer_free(b);
b->buflen = newsize;
b->data = qdata;
}
int buffer_len(struct buffer *b)
{
return b->buflen;
}
void *buffer_data(struct buffer *b)
{
return b->data;
}

@ -1,49 +1,49 @@
#include <unistd.h>
#include "ioall.h"
#include <ioall.h>
#include "libqubes-rpc-filecopy.h"
#include "crc32.h"
notify_progress_t *notify_progress_func = NULL;
void register_notify_progress(notify_progress_t *func)
{
notify_progress_func = func;
notify_progress_func = func;
}
int copy_file(int outfd, int infd, long long size, unsigned long *crc32)
{
char buf[4096];
long long written = 0;
int ret;
int count;
while (written < size) {
if (size - written > (int)sizeof(buf))
count = sizeof buf;
else
count = size - written;
ret = read(infd, buf, count);
if (!ret)
return COPY_FILE_READ_EOF;
if (ret < 0)
return COPY_FILE_READ_ERROR;
/* acumulate crc32 if requested */
if (crc32)
*crc32 = Crc32_ComputeBuf(*crc32, buf, ret);
if (!write_all(outfd, buf, ret))
return COPY_FILE_WRITE_ERROR;
if (notify_progress_func != NULL)
notify_progress_func(ret, 0);
written += ret;
}
return COPY_FILE_OK;
char buf[4096];
long long written = 0;
int ret;
int count;
while (written < size) {
if (size - written > (int)sizeof(buf))
count = sizeof buf;
else
count = size - written;
ret = read(infd, buf, count);
if (!ret)
return COPY_FILE_READ_EOF;
if (ret < 0)
return COPY_FILE_READ_ERROR;
/* acumulate crc32 if requested */
if (crc32)
*crc32 = Crc32_ComputeBuf(*crc32, buf, ret);
if (!write_all(outfd, buf, ret))
return COPY_FILE_WRITE_ERROR;
if (notify_progress_func != NULL)
notify_progress_func(ret, 0);
written += ret;
}
return COPY_FILE_OK;
}
const char * copy_file_status_to_str(int status)
{
switch (status) {
case COPY_FILE_OK: return "OK";
case COPY_FILE_READ_EOF: return "Unexpected end of data while reading";
case COPY_FILE_READ_ERROR: return "Error reading";
case COPY_FILE_WRITE_ERROR: return "Error writing";
default: return "????????";
}
switch (status) {
case COPY_FILE_OK: return "OK";
case COPY_FILE_READ_EOF: return "Unexpected end of data while reading";
case COPY_FILE_READ_ERROR: return "Error reading";
case COPY_FILE_WRITE_ERROR: return "Error writing";
default: return "????????";
}
}

@ -0,0 +1,79 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "libqrexec-utils.h"
static do_exec_t *exec_func = NULL;
void register_exec_func(do_exec_t *func) {
exec_func = func;
}
void fix_fds(int fdin, int fdout, int fderr)
{
int i;
for (i = 0; i < 256; i++)
if (i != fdin && i != fdout && i != fderr)
close(i);
dup2(fdin, 0);
dup2(fdout, 1);
dup2(fderr, 2);
close(fdin);
close(fdout);
if (fderr != 2)
close(fderr);
}
void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
int *stderr_fd)
{
int inpipe[2], outpipe[2], errpipe[2];
if (pipe(inpipe) || pipe(outpipe) || (stderr_fd && pipe(errpipe))) {
perror("pipe");
exit(1);
}
switch (*pid = fork()) {
case -1:
perror("fork");
exit(-1);
case 0:
if (stderr_fd) {
fix_fds(inpipe[0], outpipe[1], errpipe[1]);
} else
fix_fds(inpipe[0], outpipe[1], 2);
if (exec_func != NULL)
exec_func(cmdline);
exit(-1);
default:;
}
close(inpipe[0]);
close(outpipe[1]);
*stdin_fd = inpipe[1];
*stdout_fd = outpipe[0];
if (stderr_fd) {
close(errpipe[1]);
*stderr_fd = errpipe[0];
}
}

@ -27,90 +27,90 @@
void perror_wrapper(const char * msg)
{
int prev=errno;
perror(msg);
errno=prev;
int prev=errno;
perror(msg);
errno=prev;
}
void set_nonblock(int fd)
{
int fl = fcntl(fd, F_GETFL, 0);
if (fl & O_NONBLOCK)
return;
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
int fl = fcntl(fd, F_GETFL, 0);
if (fl & O_NONBLOCK)
return;
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}
void set_block(int fd)
{
int fl = fcntl(fd, F_GETFL, 0);
if (!(fl & O_NONBLOCK))
return;
fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
int fl = fcntl(fd, F_GETFL, 0);
if (!(fl & O_NONBLOCK))
return;
fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
}
int write_all(int fd, const void *buf, int size)
{
int written = 0;
int ret;
while (written < size) {
ret = write(fd, (char *) buf + written, size - written);
if (ret == -1 && errno == EINTR)
continue;
if (ret <= 0) {
return 0;
}
written += ret;
}
// fprintf(stderr, "sent %d bytes\n", size);
return 1;
int written = 0;
int ret;
while (written < size) {
ret = write(fd, (char *) buf + written, size - written);
if (ret == -1 && errno == EINTR)
continue;
if (ret <= 0) {
return 0;
}
written += ret;
}
// fprintf(stderr, "sent %d bytes\n", size);
return 1;
}
int read_all(int fd, void *buf, int size)
{
int got_read = 0;
int ret;
while (got_read < size) {
ret = read(fd, (char *) buf + got_read, size - got_read);
if (ret == -1 && errno == EINTR)
continue;
if (ret == 0) {
errno = 0;
fprintf(stderr, "EOF\n");
return 0;
}
if (ret < 0) {
if (errno != EAGAIN)
perror_wrapper("read");
return 0;
}
if (got_read == 0) {
// force blocking operation on further reads
set_block(fd);
}
got_read += ret;
}
// fprintf(stderr, "read %d bytes\n", size);
return 1;
int got_read = 0;
int ret;
while (got_read < size) {
ret = read(fd, (char *) buf + got_read, size - got_read);
if (ret == -1 && errno == EINTR)
continue;
if (ret == 0) {
errno = 0;
fprintf(stderr, "EOF\n");
return 0;
}
if (ret < 0) {
if (errno != EAGAIN)
perror_wrapper("read");
return 0;
}
if (got_read == 0) {
// force blocking operation on further reads
set_block(fd);
}
got_read += ret;
}
// fprintf(stderr, "read %d bytes\n", size);
return 1;
}
int copy_fd_all(int fdout, int fdin)
{
int ret;
char buf[4096];
for (;;) {
ret = read(fdin, buf, sizeof(buf));
if (ret == -1 && errno == EINTR)
continue;
if (!ret)
break;
if (ret < 0) {
perror_wrapper("read");
return 0;
}
if (!write_all(fdout, buf, ret)) {
perror_wrapper("write");
return 0;
}
}
return 1;
int ret;
char buf[4096];
for (;;) {
ret = read(fdin, buf, sizeof(buf));
if (ret == -1 && errno == EINTR)
continue;
if (!ret)
break;
if (ret < 0) {
perror_wrapper("read");
return 0;
}
if (!write_all(fdout, buf, ret)) {
perror_wrapper("write");
return 0;
}
}
return 1;
}

@ -0,0 +1,69 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
* Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
*
* 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 <sys/select.h>
struct buffer {
char *data;
int buflen;
};
typedef void (do_exec_t)(const char *);
void register_exec_func(do_exec_t *func);
void buffer_init(struct buffer *b);
void buffer_free(struct buffer *b);
void buffer_append(struct buffer *b, const char *data, int len);
void buffer_remove(struct buffer *b, int len);
int buffer_len(struct buffer *b);
void *buffer_data(struct buffer *b);
void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
int *stderr_fd);
int peer_server_init(int port);
char *peer_client_init(int dom, int port);
void wait_for_vchan_or_argfd(int max, fd_set * rdset, fd_set * wrset);
unsigned int read_ready_vchan_ext(void);
int read_all(int fd, void *buf, int size);
int read_all_vchan_ext(void *buf, int size);
int write_all(int fd, const void *buf, int size);
int write_all_vchan_ext(const void *buf, int size);
unsigned int buffer_space_vchan_ext(void);
void fix_fds(int fdin, int fdout, int fderr);
void set_nonblock(int fd);
void set_block(int fd);
int get_server_socket(const char *);
int do_accept(int s);
enum {
WRITE_STDIN_OK = 0x200,
WRITE_STDIN_BUFFERED,
WRITE_STDIN_ERROR
};
int flush_client_data(int fd, int client_id, struct buffer *buffer);
int write_stdin(int fd, int client_id, const char *data, int len,
struct buffer *buffer);
void set_nonblock(int fd);
int fork_and_flush_stdin(int fd, struct buffer *buffer);

@ -30,46 +30,38 @@
#define LEGAL_EOF 31415926
#include <stdint.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/types.h>
struct file_header {
uint32_t namelen;
uint32_t mode;
uint64_t filelen;
uint32_t atime;
uint32_t atime_nsec;
uint32_t mtime;
uint32_t mtime_nsec;
unsigned int namelen;
unsigned int mode;
unsigned long long filelen;
unsigned int atime;
unsigned int atime_nsec;
unsigned int mtime;
unsigned int mtime_nsec;
};
struct result_header {
uint32_t error_code;
uint32_t _pad;
uint64_t crc32;
uint32_t error_code;
uint32_t _pad;
uint64_t crc32;
} __attribute__((packed));
/* optional info about last processed file */
struct result_header_ext {
uint32_t last_namelen;
char last_name[0];
uint32_t last_namelen;
char last_name[0];
} __attribute__((packed));
enum {
COPY_FILE_OK,
COPY_FILE_READ_EOF,
COPY_FILE_READ_ERROR,
COPY_FILE_WRITE_ERROR
COPY_FILE_OK,
COPY_FILE_READ_EOF,
COPY_FILE_READ_ERROR,
COPY_FILE_WRITE_ERROR
};
/* feedback handling */
typedef void (notify_progress_t)(int, int);
typedef void (error_handler_t)(const char *fmt, va_list args);
void register_notify_progress(notify_progress_t *func);
void register_error_handler(error_handler_t *func);
/* common functions */
int copy_file(int outfd, int infd, long long size, unsigned long *crc32);
const char *copy_file_status_to_str(int status);
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit);
@ -82,22 +74,9 @@ int copy_fd_all(int fdout, int fdin);
void set_nonblock(int fd);
void set_block(int fd);
/* unpacking */
extern unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
size_t bufLen );
extern int do_unpack(void);
/* packing */
int single_file_processor(const char *filename, const struct stat *st);
int do_fs_walk(const char *file, int ignore_symlinks);
/* used in tar2qfile to alter only headers, but keep original file stream */
void write_headers(const struct file_header *hdr, const char *filename);
int copy_file_with_crc(int outfd, int infd, long long size);
/* MUST be called before first do_fs_walk/single_file_processor */
void qfile_pack_init(void);
void set_ignore_quota_error(int value);
/* those two will call registered error handler if needed */
void wait_for_result(void);
void notify_end_and_wait_for_result(void);
extern int do_unpack(void);
#endif /* _LIBQUBES_RPC_FILECOPY_H */

@ -1,229 +0,0 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <stdarg.h>
#include <dirent.h>
#include <sys/types.h>
#include "libqubes-rpc-filecopy.h"
static unsigned long crc32_sum;
static int ignore_quota_error = 0;
error_handler_t *error_handler = NULL;
void register_error_handler(error_handler_t *value) {
error_handler = value;
}
_Noreturn static void call_error_handler(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (error_handler) {
error_handler(fmt, args);
} else {
vfprintf(stderr, fmt, args);
}
va_end(args);
exit(1);
}
static int write_all_with_crc(int fd, const void *buf, int size)
{
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
return write_all(fd, buf, size);
}
void notify_end_and_wait_for_result(void)
{
struct file_header end_hdr;
/* nofity end of transfer */
memset(&end_hdr, 0, sizeof(end_hdr));
end_hdr.namelen = 0;
end_hdr.filelen = 0;
write_all_with_crc(1, &end_hdr, sizeof(end_hdr));
set_block(0);
wait_for_result();
}
void wait_for_result(void)
{
struct result_header hdr;
struct result_header_ext hdr_ext;
char last_filename[MAX_PATH_LENGTH + 1];
char last_filename_prefix[] = "; Last file: ";
if (!read_all(0, &hdr, sizeof(hdr))) {
if (errno == EAGAIN) {
// no result sent and stdin still open
return;
} else {
// other read error or EOF
exit(1); // hopefully remote has produced error message
}
}
if (!read_all(0, &hdr_ext, sizeof(hdr_ext))) {
// remote used old result_header struct
hdr_ext.last_namelen = 0;
}
if (hdr_ext.last_namelen > MAX_PATH_LENGTH) {
// read only at most MAX_PATH_LENGTH chars
hdr_ext.last_namelen = MAX_PATH_LENGTH;
}
if (!read_all(0, last_filename, hdr_ext.last_namelen)) {
fprintf(stderr, "Failed to get last filename\n");
hdr_ext.last_namelen = 0;
}
last_filename[hdr_ext.last_namelen] = '\0';
if (!hdr_ext.last_namelen)
/* set prefix to empty string */
last_filename_prefix[0] = '\0';
errno = hdr.error_code;
if (hdr.error_code != 0) {
switch (hdr.error_code) {
case EEXIST:
call_error_handler("A file named %s already exists in QubesIncoming dir", last_filename);
break;
case EINVAL:
call_error_handler("File copy: Corrupted data from packer%s%s", last_filename_prefix, last_filename);
break;
case EDQUOT:
if (ignore_quota_error) {
/* skip also CRC check as sender and receiver might be
* desynchronized in this case */
return;
}
/* fallthrough */
default:
call_error_handler("File copy: %s%s%s",
strerror(hdr.error_code), last_filename_prefix, last_filename);
}
}
if (hdr.crc32 != crc32_sum) {
call_error_handler("File transfer failed: checksum mismatch");
}
}
void write_headers(const struct file_header *hdr, const char *filename)
{
if (!write_all_with_crc(1, hdr, sizeof(*hdr))
|| !write_all_with_crc(1, filename, hdr->namelen)) {
set_block(0);
wait_for_result();
exit(1);
}
}
int copy_file_with_crc(int outfd, int infd, long long size) {
return copy_file(outfd, infd, size, &crc32_sum);
}
int single_file_processor(const char *filename, const struct stat *st)
{
struct file_header hdr;
int fd;
mode_t mode = st->st_mode;
hdr.namelen = strlen(filename) + 1;
hdr.mode = mode;
hdr.atime = st->st_atim.tv_sec;
hdr.atime_nsec = st->st_atim.tv_nsec;
hdr.mtime = st->st_mtim.tv_sec;
hdr.mtime_nsec = st->st_mtim.tv_nsec;
if (S_ISREG(mode)) {
int ret;
fd = open(filename, O_RDONLY);
if (fd < 0)
call_error_handler("open %s", filename);
hdr.filelen = st->st_size;
write_headers(&hdr, filename);
ret = copy_file(1, fd, hdr.filelen, &crc32_sum);
if (ret != COPY_FILE_OK) {
if (ret != COPY_FILE_WRITE_ERROR)
call_error_handler("Copying file %s: %s", filename,
copy_file_status_to_str(ret));
else {
set_block(0);
wait_for_result();
exit(1);
}
}
close(fd);
}
if (S_ISDIR(mode)) {
hdr.filelen = 0;
write_headers(&hdr, filename);
}
if (S_ISLNK(mode)) {
char name[st->st_size + 1];
if (readlink(filename, name, sizeof(name)) != st->st_size)
call_error_handler("readlink %s", filename);
hdr.filelen = st->st_size;
write_headers(&hdr, filename);
if (!write_all_with_crc(1, name, st->st_size)) {
set_block(0);
wait_for_result();
exit(1);
}
}
// check for possible error from qfile-unpacker
wait_for_result();
return 0;
}
int do_fs_walk(const char *file, int ignore_symlinks)
{
char *newfile;
struct stat st;
struct dirent *ent;
DIR *dir;
if (lstat(file, &st))
call_error_handler("stat %s", file);
if (S_ISLNK(st.st_mode) && ignore_symlinks)
return 0;
single_file_processor(file, &st);
if (!S_ISDIR(st.st_mode))
return 0;
dir = opendir(file);
if (!dir)
call_error_handler("opendir %s", file);
while ((ent = readdir(dir))) {
char *fname = ent->d_name;
if (!strcmp(fname, ".") || !strcmp(fname, ".."))
continue;
if (asprintf(&newfile, "%s/%s", file, fname) >= 0) {
do_fs_walk(newfile, ignore_symlinks);
free(newfile);
} else {
fprintf(stderr, "asprintf failed\n");
exit(1);
}
}
closedir(dir);
// directory metadata is resent; this makes the code simple,
// and the atime/mtime is set correctly at the second time
single_file_processor(file, &st);
return 0;
}
void qfile_pack_init(void) {
crc32_sum = 0;
ignore_quota_error = 0;
// this will allow checking for possible feedback packet in the middle of transfer
set_nonblock(0);
signal(SIGPIPE, SIG_IGN);
error_handler = NULL;
}
void set_ignore_quota_error(int value) {
ignore_quota_error = value;
}

@ -0,0 +1,106 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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.
*
*/
/* See also http://wiki.qubes-os.org/trac/wiki/Qrexec */
#define QREXEC_DAEMON_SOCKET_DIR "/var/run/qubes"
#define MAX_FDS 256
#define MAX_DATA_CHUNK 4096
#define REXEC_PORT 512
#define QREXEC_AGENT_TRIGGER_PATH "/var/run/qubes/qrexec-agent"
#define QREXEC_AGENT_FDPASS_PATH "/var/run/qubes/qrexec-agent-fdpass"
#define MEMINFO_WRITER_PIDFILE "/var/run/meminfo-writer.pid"
#define QUBES_RPC_MULTIPLEXER_PATH "/usr/lib/qubes/qubes-rpc-multiplexer"
#define QUBES_RPC_MAGIC_CMD "QUBESRPC"
enum {
/* messages from qrexec_client to qrexec_daemon (both in dom0) */
/* start process in VM and pass its stdin/out/err to dom0 */
MSG_CLIENT_TO_SERVER_EXEC_CMDLINE = 0x100,
/* start process in VM discarding its stdin/out/err (connect to /dev/null) */
MSG_CLIENT_TO_SERVER_JUST_EXEC,
/* connect to existing process in VM to receive its stdin/out/err
* struct connect_existing_params passed as data */
MSG_CLIENT_TO_SERVER_CONNECT_EXISTING,
/* messages qrexec_daemon(dom0)->qrexec_agent(VM) */
/* same as MSG_CLIENT_TO_SERVER_CONNECT_EXISTING */
MSG_SERVER_TO_AGENT_CONNECT_EXISTING,
/* same as MSG_CLIENT_TO_SERVER_EXEC_CMDLINE */
MSG_SERVER_TO_AGENT_EXEC_CMDLINE,
/* same as MSG_CLIENT_TO_SERVER_JUST_EXEC */
MSG_SERVER_TO_AGENT_JUST_EXEC,
/* pass data to process stdin */
MSG_SERVER_TO_AGENT_INPUT,
/* detach from process; qrexec_agent should close pipes to process
* stdin/out/err; it's up to the VM child process if it cause its termination */
MSG_SERVER_TO_AGENT_CLIENT_END,
/* flow control, qrexec_daemon->qrexec_agent */
/* suspend reading of named fd from child process */
MSG_XOFF,
/* resume reading of named fd from child process */
MSG_XON,
/* messages qrexec_agent(VM)->qrexec_daemon(dom0) */
/* pass data from process stdout */
MSG_AGENT_TO_SERVER_STDOUT,
/* pass data from process stderr */
MSG_AGENT_TO_SERVER_STDERR,
/* inform that process terminated and pass its exit code; this should be
* send after all data from stdout/err are send */
MSG_AGENT_TO_SERVER_EXIT_CODE,
/* call Qubes RPC service
* struct trigger_connect_params passed as data */
MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING,
/* messages qrexec_daemon->qrexec_client (both in dom0) */
/* same as MSG_AGENT_TO_SERVER_STDOUT */
MSG_SERVER_TO_CLIENT_STDOUT,
/* same as MSG_AGENT_TO_SERVER_STDERR */
MSG_SERVER_TO_CLIENT_STDERR,
/* same as MSG_AGENT_TO_SERVER_EXIT_CODE */
MSG_SERVER_TO_CLIENT_EXIT_CODE
};
struct server_header {
unsigned int type;
unsigned int client_id;
unsigned int len;
};
struct client_header {
unsigned int type;
unsigned int len;
};
struct connect_existing_params {
char ident[32];
};
struct trigger_connect_params {
char exec_index[64];
char target_vmname[32];
struct connect_existing_params process_fds;
};

@ -0,0 +1,247 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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 <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <libvchan.h>
#ifdef USE_XENSTORE_H
#include <xenstore.h>
#else
#include <xs.h>
#endif
#include <xenctrl.h>
static struct libvchan *ctrl;
static int is_server;
int write_all_vchan_ext(const void *buf, int size)
{
int written = 0;
int ret;
while (written < size) {
ret =
libvchan_write(ctrl, (const char *) buf + written,
size - written);
if (ret <= 0) {
perror("write");
exit(1);
}
written += ret;
}
// fprintf(stderr, "sent %d bytes\n", size);
return size;
}
int read_all_vchan_ext(void *buf, int size)
{
int written = 0;
int ret;
while (written < size) {
ret =
libvchan_read(ctrl, (char *) buf + written,
size - written);
if (ret == 0) {
fprintf(stderr, "EOF\n");
exit(1);
}
if (ret < 0) {
perror("read");
exit(1);
}
written += ret;
}
// fprintf(stderr, "read %d bytes\n", size);
return size;
}
unsigned int read_ready_vchan_ext()
{
int ready = libvchan_data_ready(ctrl);
if (ready < 0) {
fprintf(stderr, "libvchan_data_ready returned invalid size\n");
exit(1);
}
return ready;
}
unsigned int buffer_space_vchan_ext()
{
int space = libvchan_buffer_space(ctrl);
if (space < 0) {
fprintf(stderr, "libvchan_buffer_space returned invalid size\n");
exit(1);
}
return space;
}
// if the remote domain is destroyed, we get no notification
// thus, we check for the status periodically
#ifdef XENCTRL_HAS_XC_INTERFACE
static xc_interface *xc_handle = NULL;
#else
static int xc_handle = -1;
#endif
void slow_check_for_libvchan_is_eof(struct libvchan *ctrl)
{
struct evtchn_status evst;
evst.port = ctrl->evport;
evst.dom = DOMID_SELF;
if (xc_evtchn_status(xc_handle, &evst)) {
perror("xc_evtchn_status");
exit(1);
}
if (evst.status != EVTCHNSTAT_interdomain) {
fprintf(stderr, "event channel disconnected\n");
exit(0);
}
}
int wait_for_vchan_or_argfd_once(int max, fd_set * rdset, fd_set * wrset)
{
int vfd, ret;
struct timespec tv = { 1, 100000000 };
sigset_t empty_set;
sigemptyset(&empty_set);
vfd = libvchan_fd_for_select(ctrl);
FD_SET(vfd, rdset);
if (vfd > max)
max = vfd;
max++;
ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set);
if (ret < 0) {
if (errno != EINTR) {
perror("select");
exit(1);
} else {
FD_ZERO(rdset);
FD_ZERO(wrset);
fprintf(stderr, "eintr\n");
return 1;
}
}
if (libvchan_is_eof(ctrl)) {
fprintf(stderr, "libvchan_is_eof\n");
exit(0);
}
if (!is_server && ret == 0)
slow_check_for_libvchan_is_eof(ctrl);
if (FD_ISSET(vfd, rdset))
// the following will never block; we need to do this to
// clear libvchan_fd pending state
libvchan_wait(ctrl);
return ret;
}
void wait_for_vchan_or_argfd(int max, fd_set * rdset, fd_set * wrset)
{
fd_set r = *rdset, w = *wrset;
do {
*rdset = r;
*wrset = w;
}
while (wait_for_vchan_or_argfd_once(max, rdset, wrset) == 0);
}
int peer_server_init(int port)
{
is_server = 1;
ctrl = libvchan_server_init(port);
if (!ctrl) {
perror("libvchan_server_init");
exit(1);
}
return 0;
}
char *peer_client_init(int dom, int port)
{
struct xs_handle *xs;
char buf[64];
char *name;
char *dummy, *dummy2;
unsigned int len = 0;
char devbuf[128];
char dombuf[128];
unsigned int count;
char **vec;
// double_buffered = 1; // writes to vchan are buffered, nonblocking
// double_buffer_init();
xs = xs_daemon_open();
if (!xs) {
perror("xs_daemon_open");
exit(1);
}
snprintf(buf, sizeof(buf), "/local/domain/%d/name", dom);
name = xs_read(xs, 0, buf, &len);
if (!name) {
perror("xs_read domainname");
exit(1);
}
snprintf(devbuf, sizeof(devbuf),
"/local/domain/%d/device/vchan/%d/event-channel", dom,
port);
snprintf(dombuf, sizeof(dombuf), "/local/domain/%d", dom);
xs_watch(xs, devbuf, devbuf);
do {
vec = xs_read_watch(xs, &count);
if (vec)
free(vec);
len = 0;
dummy = xs_read(xs, 0, devbuf, &len);
if (dummy)
free(dummy);
else {
/* check if domain still alive */
dummy2 = xs_read(xs, 0, dombuf, &len);
if (!dummy2) {
fprintf(stderr, "domain dead\n");
exit(1);
}
free(dummy2);
}
}
while (!dummy || !len); // wait for the server to create xenstore entries
xs_daemon_close(xs);
// now client init should succeed; "while" is redundant
while (!(ctrl = libvchan_client_init(dom, port)));
#ifdef XENCTRL_HAS_XC_INTERFACE
xc_handle = xc_interface_open(NULL, 0, 0);
if (!xc_handle) {
#else
xc_handle = xc_interface_open();
if (xc_handle < 0) {
#endif
perror("xc_interface_open");
exit(1);
}
return name;
}

@ -0,0 +1,73 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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 <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
//#include "qrexec.h"
int get_server_socket(const char *socket_address)
{
struct sockaddr_un sockname;
int s;
unlink(socket_address);
s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0) {
printf("socket() failed\n");
exit(1);
}
memset(&sockname, 0, sizeof(sockname));
sockname.sun_family = AF_UNIX;
strncpy(sockname.sun_path, socket_address, sizeof sockname.sun_path);
sockname.sun_path[sizeof sockname.sun_path - 1] = 0;
if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) {
printf("bind() failed\n");
close(s);
exit(1);
}
// chmod(sockname.sun_path, 0666);
if (listen(s, 5) == -1) {
perror("listen() failed\n");
close(s);
exit(1);
}
return s;
}
int do_accept(int s)
{
struct sockaddr_un peer;
unsigned int addrlen;
int fd;
addrlen = sizeof(peer);
fd = accept(s, (struct sockaddr *) &peer, &addrlen);
if (fd == -1) {
perror("unix accept");
exit(1);
}
return fd;
}

@ -1,5 +1,6 @@
#define _GNU_SOURCE /* For O_NOFOLLOW. */
#include <errno.h>
#include <ioall.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/stat.h>
@ -9,7 +10,6 @@
#include <stdio.h>
#include <limits.h>
#include "libqubes-rpc-filecopy.h"
#include "ioall.h"
#include "crc32.h"
char untrusted_namebuf[MAX_PATH_LENGTH];
@ -35,203 +35,194 @@ void send_status_and_crc(int code, const char *last_filename);
void do_exit(int code, const char *last_filename)
{
close(0);
send_status_and_crc(code, last_filename);
exit(code);
close(0);
send_status_and_crc(code, last_filename);
exit(code);
}
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit)
{
bytes_limit = new_bytes_limit;
files_limit = new_files_limit;
bytes_limit = new_bytes_limit;
files_limit = new_files_limit;
}
void set_verbose(int value)
{
verbose = value;
verbose = value;
}
void set_procfs_fd(int value)
{
procdir_fd = value;
use_tmpfile = 1;
procdir_fd = value;
use_tmpfile = 1;
}
unsigned long crc32_sum = 0;
int read_all_with_crc(int fd, void *buf, int size) {
int ret;
ret = read_all(fd, buf, size);
if (ret)
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
return ret;
int ret;
ret = read_all(fd, buf, size);
if (ret)
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
return ret;
}
void send_status_and_crc(int code, const char *last_filename) {
struct result_header hdr;
struct result_header_ext hdr_ext;
int saved_errno;
saved_errno = errno;
hdr.error_code = code;
hdr._pad = 0;
hdr.crc32 = crc32_sum;
if (!write_all(1, &hdr, sizeof(hdr)))
perror("write status");
if (last_filename) {
hdr_ext.last_namelen = strlen(last_filename);
if (!write_all(1, &hdr_ext, sizeof(hdr_ext)))
perror("write status ext");
if (!write_all(1, last_filename, hdr_ext.last_namelen))
perror("write last_filename");
}
errno = saved_errno;
struct result_header hdr;
struct result_header_ext hdr_ext;
int saved_errno;
saved_errno = errno;
hdr.error_code = code;
hdr.crc32 = crc32_sum;
if (!write_all(1, &hdr, sizeof(hdr)))
perror("write status");
if (last_filename) {
hdr_ext.last_namelen = strlen(last_filename);
if (!write_all(1, &hdr_ext, sizeof(hdr_ext)))
perror("write status ext");
if (!write_all(1, last_filename, hdr_ext.last_namelen))
perror("write last_filename");
}
errno = saved_errno;
}
void fix_times_and_perms(struct file_header *untrusted_hdr,
const char *untrusted_name)
const char *untrusted_name)
{
struct timeval times[2] =
{
{untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
{untrusted_hdr->mtime, untrusted_hdr->mtime_nsec / 1000}
};
if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
do_exit(errno, untrusted_name);
if (utimes(untrusted_name, times)) /* as above */
do_exit(errno, untrusted_name);
struct timeval times[2] =
{ {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
{untrusted_hdr->mtime,
untrusted_hdr->mtime_nsec / 1000}
};
if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
do_exit(errno, untrusted_name);
if (utimes(untrusted_name, times)) /* as above */
do_exit(errno, untrusted_name);
}
void process_one_file_reg(struct file_header *untrusted_hdr,
const char *untrusted_name)
const char *untrusted_name)
{
int ret;
int fdout = -1;
/* make the file inaccessible until fully written */
if (use_tmpfile) {
fdout = open(".", O_WRONLY | O_TMPFILE, 0700);
if (fdout < 0) {
if (errno==ENOENT || /* most likely, kernel too old for O_TMPFILE */
errno==EOPNOTSUPP) /* filesystem has no support for O_TMPFILE */
use_tmpfile = 0;
else
do_exit(errno, untrusted_name);
}
}
if (fdout < 0)
fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */
if (fdout < 0)
do_exit(errno, untrusted_name);
/* sizes are signed elsewhere */
if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit))
do_exit(EDQUOT, untrusted_name);
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
do_exit(EDQUOT, untrusted_name);
total_bytes += untrusted_hdr->filelen;
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
if (ret != COPY_FILE_OK) {
if (ret == COPY_FILE_READ_EOF
|| ret == COPY_FILE_READ_ERROR)
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message
else
do_exit(errno, untrusted_name);
}
if (use_tmpfile) {
char fd_str[7];
snprintf(fd_str, sizeof(fd_str), "%d", fdout);
if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0)
do_exit(errno, untrusted_name);
}
close(fdout);
fix_times_and_perms(untrusted_hdr, untrusted_name);
int ret;
int fdout = -1;
/* make the file inaccessible until fully written */
if (use_tmpfile) {
fdout = open(".", O_WRONLY | O_TMPFILE, 0700);
if (fdout < 0) {
if (errno==ENOENT)
/* if it fails, do not attempt further use - most likely kernel too old */
use_tmpfile = 0;
else
do_exit(errno, untrusted_name);
}
}
if (fdout < 0)
fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */
if (fdout < 0)
do_exit(errno, untrusted_name);
/* sizes are signed elsewhere */
if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit))
do_exit(EDQUOT, untrusted_name);
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
do_exit(EDQUOT, untrusted_name);
total_bytes += untrusted_hdr->filelen;
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
if (ret != COPY_FILE_OK) {
if (ret == COPY_FILE_READ_EOF
|| ret == COPY_FILE_READ_ERROR)
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message
else
do_exit(errno, untrusted_name);
}
fdatasync(fdout);
if (use_tmpfile) {
char fd_str[7];
snprintf(fd_str, sizeof(fd_str), "%d", fdout);
if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0)
do_exit(errno, untrusted_name);
}
close(fdout);
fix_times_and_perms(untrusted_hdr, untrusted_name);
}
void process_one_file_dir(struct file_header *untrusted_hdr,
const char *untrusted_name)
const char *untrusted_name)
{
// fix perms only when the directory is sent for the second time
// it allows to transfer r.x directory contents, as we create it rwx initially
struct stat buf;
if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
return;
if (errno != EEXIST)
do_exit(errno, untrusted_name);
if (stat(untrusted_name,&buf) < 0)
do_exit(errno, untrusted_name);
total_bytes += buf.st_size;
/* size accumulated after the fact, so don't check limit here */
fix_times_and_perms(untrusted_hdr, untrusted_name);
// fix perms only when the directory is sent for the second time
// it allows to transfer r.x directory contents, as we create it rwx initially
struct stat buf;
if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
return;
if (errno != EEXIST)
do_exit(errno, untrusted_name);
if (stat(untrusted_name,&buf) < 0)
do_exit(errno, untrusted_name);
total_bytes += buf.st_size;
/* size accumulated after the fact, so don't check limit here */
fix_times_and_perms(untrusted_hdr, untrusted_name);
}
void process_one_file_link(struct file_header *untrusted_hdr,
const char *untrusted_name)
const char *untrusted_name)
{
char untrusted_content[MAX_PATH_LENGTH];
unsigned int filelen;
if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
do_exit(ENAMETOOLONG, untrusted_name);
filelen = untrusted_hdr->filelen; /* sanitized above */
total_bytes += filelen;
if (bytes_limit && total_bytes > bytes_limit)
do_exit(EDQUOT, untrusted_name);
if (!read_all_with_crc(0, untrusted_content, filelen))
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message
untrusted_content[filelen] = 0;
if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
do_exit(errno, untrusted_name);
char untrusted_content[MAX_PATH_LENGTH];
unsigned int filelen;
if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
do_exit(ENAMETOOLONG, untrusted_name);
filelen = untrusted_hdr->filelen; /* sanitized above */
total_bytes += filelen;
if (bytes_limit && total_bytes > bytes_limit)
do_exit(EDQUOT, untrusted_name);
if (!read_all_with_crc(0, untrusted_content, filelen))
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message
untrusted_content[filelen] = 0;
if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
do_exit(errno, untrusted_name);
}
void process_one_file(struct file_header *untrusted_hdr)
{
unsigned int namelen;
if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */
namelen = untrusted_hdr->namelen; /* sanitized above */
if (!read_all_with_crc(0, untrusted_namebuf, namelen))
do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message
untrusted_namebuf[namelen] = 0;
if (S_ISREG(untrusted_hdr->mode))
process_one_file_reg(untrusted_hdr, untrusted_namebuf);
else if (S_ISLNK(untrusted_hdr->mode))
process_one_file_link(untrusted_hdr, untrusted_namebuf);
else if (S_ISDIR(untrusted_hdr->mode))
process_one_file_dir(untrusted_hdr, untrusted_namebuf);
else
do_exit(EINVAL, untrusted_namebuf);
if (verbose && !S_ISDIR(untrusted_hdr->mode))
fprintf(stderr, "%s\n", untrusted_namebuf);
unsigned int namelen;
if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */
namelen = untrusted_hdr->namelen; /* sanitized above */
if (!read_all_with_crc(0, untrusted_namebuf, namelen))
do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message
untrusted_namebuf[namelen] = 0;
if (S_ISREG(untrusted_hdr->mode))
process_one_file_reg(untrusted_hdr, untrusted_namebuf);
else if (S_ISLNK(untrusted_hdr->mode))
process_one_file_link(untrusted_hdr, untrusted_namebuf);
else if (S_ISDIR(untrusted_hdr->mode))
process_one_file_dir(untrusted_hdr, untrusted_namebuf);
else
do_exit(EINVAL, untrusted_namebuf);
if (verbose && !S_ISDIR(untrusted_hdr->mode))
fprintf(stderr, "%s\n", untrusted_namebuf);
}
int do_unpack(void)
{
struct file_header untrusted_hdr;
int cwd_fd;
int saved_errno;
total_bytes = total_files = 0;
/* initialize checksum */
crc32_sum = 0;
while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
/* check for end of transfer marker */
if (untrusted_hdr.namelen == 0) {
errno = 0;
break;
}
total_files++;
if (files_limit && total_files > files_limit)
do_exit(EDQUOT, untrusted_namebuf);
process_one_file(&untrusted_hdr);
}
saved_errno = errno;
cwd_fd = open(".", O_RDONLY);
if (cwd_fd >= 0 && syncfs(cwd_fd) == 0 && close(cwd_fd) == 0)
errno = saved_errno;
send_status_and_crc(errno, untrusted_namebuf);
return errno;
struct file_header untrusted_hdr;
total_bytes = total_files = 0;
/* initialize checksum */
crc32_sum = 0;
while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
/* check for end of transfer marker */
if (untrusted_hdr.namelen == 0) {
errno = 0;
break;
}
total_files++;
if (files_limit && total_files > files_limit)
do_exit(EDQUOT, untrusted_namebuf);
process_one_file(&untrusted_hdr);
}
send_status_and_crc(errno, untrusted_namebuf);
return errno;
}

@ -0,0 +1,135 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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 <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include "qrexec.h"
#include "libqrexec-utils.h"
/*
There is buffered data in "buffer" for client id "client_id", and select()
reports that "fd" is writable. Write as much as possible to fd, if all sent,
notify the peer that this client's pipe is no longer full.
*/
int flush_client_data(int fd, int client_id, struct buffer *buffer)
{
int ret;
int len;
for (;;) {
len = buffer_len(buffer);
if (len > MAX_DATA_CHUNK)
len = MAX_DATA_CHUNK;
ret = write(fd, buffer_data(buffer), len);
if (ret == -1) {
if (errno != EAGAIN) {
return WRITE_STDIN_ERROR;
} else
return WRITE_STDIN_BUFFERED;
}
// we previously called buffer_remove(buffer, len)
// it will be wrong if we change MAX_DATA_CHUNK to something large
// as pipes writes are atomic only to PIPE_MAX limit
buffer_remove(buffer, ret);
len = buffer_len(buffer);
if (!len) {
struct server_header s_hdr;
s_hdr.type = MSG_XON;
s_hdr.client_id = client_id;
s_hdr.len = 0;
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
return WRITE_STDIN_OK;
}
}
}
/*
Write "len" bytes from "data" to "fd". If not all written, buffer the rest
to "buffer", and notify the peer that the client "client_id" pipe is full via
MSG_XOFF message.
*/
int write_stdin(int fd, int client_id, const char *data, int len,
struct buffer *buffer)
{
int ret;
int written = 0;
if (buffer_len(buffer)) {
buffer_append(buffer, data, len);
return WRITE_STDIN_BUFFERED;
}
while (written < len) {
ret = write(fd, data + written, len - written);
if (ret == 0) {
perror("write_stdin: write returns 0 ???");
exit(1);
}
if (ret == -1) {
struct server_header s_hdr;
if (errno != EAGAIN)
return WRITE_STDIN_ERROR;
buffer_append(buffer, data + written,
len - written);
s_hdr.type = MSG_XOFF;
s_hdr.client_id = client_id;
s_hdr.len = 0;
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
return WRITE_STDIN_BUFFERED;
}
written += ret;
}
return WRITE_STDIN_OK;
}
/*
Data feed process has exited, so we need to clear all control structures for
the client. However, if we have buffered data for the client (which is rare btw),
fire&forget a separate process to flush them.
*/
int fork_and_flush_stdin(int fd, struct buffer *buffer)
{
int i;
if (!buffer_len(buffer))
return 0;
switch (fork()) {
case -1:
perror("fork");
exit(1);
case 0:
break;
default:
return 1;
}
for (i = 0; i < MAX_FDS; i++)
if (i != fd && i != 2)
close(i);
set_block(fd);
write_all(fd, buffer_data(buffer), buffer_len(buffer));
_exit(0);
}

@ -1,87 +0,0 @@
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2015 Marek Marczykowski-Górecki
# <marmarek@invisiblethingslab.com>
#
# 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.
#
Name: qubes-kernel-vm-support
Version: @VERSION@
Release: 1%{?dist}
Summary: Qubes VM initramfs modules
Source0: qubes-utils-%{version}.tar.gz
Group: Qubes
Vendor: Invisible Things Lab
License: GPL v2 only
URL: http://www.qubes-os.org
Requires: dracut
%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.
%prep
%setup -q -n qubes-utils-%{version}
%install
make install-fedora-kernel-support DESTDIR=%{buildroot}
%files
/usr/lib/dracut/modules.d/90qubes-vm
/usr/lib/dracut/modules.d/90qubes-vm-modules
/usr/lib/dracut/modules.d/90qubes-vm-simple
/usr/lib/dracut/modules.d/80xen-scrub-pages
/usr/sbin/qubes-prepare-vm-kernel
%config(noreplace) /etc/default/grub.qubes-kernel-vm-support
%triggerin -- grub2-tools
if ! grep -q '/etc/default/grub.qubes-kernel-vm-support$' /etc/default/grub 2>/dev/null; then
# do not keep Qubes-related settings directly in user-controlled config,
# include another file
echo '. /etc/default/grub.qubes-kernel-vm-support' >> /etc/default/grub
fi
%preun
if [ $1 -eq 0 ]; then
if grep -q '/etc/default/grub.qubes-kernel-vm-support$' /etc/default/grub 2>/dev/null; then
sed -i -e '/grub.qubes-kernel-vm-support$/d' /etc/default/grub
fi
fi
%posttrans
# Rebuild all initramfs images to include updated modules
if [ -r /usr/share/qubes/marker-vm ] && [ -x /usr/bin/dracut ]; then
ret=0
for img in /boot/initramfs-*.img; do
kver="${img#*initramfs-}"
kver="${kver%.img}"
dracut -f "$img" "$kver" || ret=$?
done
if [ "$ret" -eq 0 ]; then
# "milestone" initramfs update version:
# 1 - addition of xen scrub_pages enabling code
echo 1 > /var/lib/qubes/initramfs-updated
fi
fi
%changelog
@CHANGELOG@

@ -0,0 +1,100 @@
%define version %(cat version)
%if 0%{?qubes_builder}
%define _builddir %(pwd)
%endif
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
Name: qubes-utils
Version: %{version}
Release: 1%{?dist}
Summary: Common Linux files for Qubes Dom0 and VM
Group: Qubes
License: GPL
URL: http://www.qubes-os.org
Requires: udev
Requires: %{name}-libs
Requires: ImageMagick
Requires: pycairo
BuildRequires: qubes-libvchan-devel
%description
Common Linux files for Qubes Dom0 and VM
%package devel
Summary: Development headers for qubes-utils
Release: 1%{?dist}
Requires: %{name}-libs
%description devel
Development header and files for qubes-utils
%package libs
Summary: Qubes utils libraries
Release: 1%{?dist}
%description libs
Libraries for qubes-utils
%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
make all
%install
make install DESTDIR=%{buildroot}
%post
# dom0
/bin/systemctl enable qubes-meminfo-writer-dom0.service > /dev/null 2>&1
# VM
/bin/systemctl enable qubes-meminfo-writer.service > /dev/null 2>&1
%postun
if [ $1 -eq 0 ]; then
/bin/systemctl disable qubes-meminfo-writer.service > /dev/null 2>&1
/bin/systemctl disable qubes-meminfo-writer.service > /dev/null 2>&1
fi
%post libs -p /sbin/ldconfig
%postun libs -p /sbin/ldconfig
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
/etc/udev/rules.d/99-qubes-*.rules
/usr/libexec/qubes/udev-*
%{_sbindir}/meminfo-writer
%{_unitdir}/qubes-meminfo-writer.service
%{_unitdir}/qubes-meminfo-writer-dom0.service
%{python_sitearch}/qubes/__init__.py
%{python_sitearch}/qubes/__init__.pyc
%{python_sitearch}/qubes/__init__.pyo
%attr(0755,root,root) %{python_sitearch}/qubes/imgconverter.py
%{python_sitearch}/qubes/imgconverter.pyc
%{python_sitearch}/qubes/imgconverter.pyo
%files libs
%{_libdir}/libqrexec-utils.so.1
%{_libdir}/libqubes-rpc-filecopy.so.1
%files devel
%defattr(-,root,root,-)
/usr/include/libqrexec-utils.h
/usr/include/libqubes-rpc-filecopy.h
/usr/include/qrexec.h
%{_libdir}/libqrexec-utils.so
%{_libdir}/libqubes-rpc-filecopy.so
%changelog

@ -1,132 +0,0 @@
Name: qubes-utils
Version: @VERSION@
Release: 1%{?dist}
Summary: Common Linux files for Qubes Dom0 and VM
Source0: %{name}-%{version}.tar.gz
Group: Qubes
License: GPL
URL: http://www.qubes-os.org
Requires: udev
Requires: %{name}-libs
Requires: ImageMagick
Requires: python%{python3_pkgversion}-qubesimgconverter
%{?systemd_requires}
BuildRequires: systemd
BuildRequires: python2-setuptools
BuildRequires: python%{python3_pkgversion}-setuptools
BuildRequires: python2-rpm-macros
BuildRequires: python3-rpm-macros
# for meminfo-writer
BuildRequires: xen-devel
BuildRequires: gcc
%description
Common Linux files for Qubes Dom0 and VM
%package -n python2-qubesimgconverter
Summary: Python package qubesimgconverter
Requires: python2
Requires: pycairo
%if 0%{?rhel} >= 7
Requires: python-pillow
Requires: numpy
%else
Requires: python2-pillow
Requires: python2-numpy
%endif
%description -n python2-qubesimgconverter
Python package qubesimgconverter
%package -n python%{python3_pkgversion}-qubesimgconverter
Summary: Python package qubesimgconverter
Requires: python%{python3_pkgversion}
Requires: python%{python3_pkgversion}-cairo
Requires: python%{python3_pkgversion}-pillow
Requires: python%{python3_pkgversion}-numpy
%description -n python%{python3_pkgversion}-qubesimgconverter
Python package qubesimgconverter
%package devel
Summary: Development headers for qubes-utils
Release: 1%{?dist}
Requires: %{name}-libs
%description devel
Development header and files for qubes-utils
%package libs
Summary: Qubes utils libraries
Release: 1%{?dist}
%description libs
Libraries for qubes-utils
%prep
%setup -q
%build
export PYTHON=%{__python2}
make all BACKEND_VMM=@BACKEND_VMM@
%install
make install DESTDIR=%{buildroot} PYTHON=%{__python2}
rm -rf imgconverter/build
%make_install -C imgconverter PYTHON=%{__python3}
%post
# dom0
%systemd_post qubes-meminfo-writer-dom0.service
# VM
%systemd_post qubes-meminfo-writer.service
%preun
%systemd_preun qubes-meminfo-writer-dom0.service
%systemd_preun qubes-meminfo-writer.service
%postun
%systemd_postun_with_restart qubes-meminfo-writer-dom0.service
%systemd_postun_with_restart qubes-meminfo-writer.service
%post libs -p /sbin/ldconfig
%postun libs -p /sbin/ldconfig
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
/lib/udev/rules.d/*-qubes-*.rules
/usr/lib/qubes/udev-*
%{_sbindir}/meminfo-writer
%{_unitdir}/qubes-meminfo-writer.service
%{_unitdir}/qubes-meminfo-writer-dom0.service
%files -n python2-qubesimgconverter
%{python2_sitelib}/qubesimgconverter/__init__.py*
%{python2_sitelib}/qubesimgconverter/imggen.py*
%{python2_sitelib}/qubesimgconverter/test.py*
%{python2_sitelib}/qubesimgconverter/test_integ.py*
%{python2_sitelib}/qubesimgconverter-%{version}-py?.?.egg-info
%files -n python%{python3_pkgversion}-qubesimgconverter
%{python3_sitelib}/qubesimgconverter/__init__.py
%{python3_sitelib}/qubesimgconverter/imggen.py
%{python3_sitelib}/qubesimgconverter/test.py
%{python3_sitelib}/qubesimgconverter/test_integ.py
%{python3_sitelib}/qubesimgconverter-%{version}-py?.?.egg-info
%{python3_sitelib}/qubesimgconverter/__pycache__
%files libs
%{_libdir}/libqubes-rpc-filecopy.so.2
%files devel
%defattr(-,root,root,-)
/usr/include/libqubes-rpc-filecopy.h
%{_libdir}/libqubes-rpc-filecopy.so
%changelog
@CHANGELOG@

@ -1,14 +1,13 @@
all:
install:
mkdir -p $(DESTDIR)$(SYSLIBDIR)/udev/rules.d
cp udev-qubes-block.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/99-qubes-block.rules
cp udev-qubes-usb.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/99-qubes-usb.rules
cp udev-qubes-misc.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/99-qubes-misc.rules
cp udev-qubes-dmroot.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/90-qubes-dmroot.rules
mkdir -p $(DESTDIR)/etc/udev/rules.d
cp udev-qubes-block.rules $(DESTDIR)/etc/udev/rules.d/99-qubes-block.rules
cp udev-qubes-usb.rules $(DESTDIR)/etc/udev/rules.d/99-qubes-usb.rules
mkdir -p $(DESTDIR)$(SCRIPTSDIR)
cp udev-block-add-change $(DESTDIR)$(SCRIPTSDIR)
cp udev-block-remove $(DESTDIR)$(SCRIPTSDIR)
cp udev-usb-add-change $(DESTDIR)$(SCRIPTSDIR)
cp udev-usb-remove $(DESTDIR)$(SCRIPTSDIR)
mkdir -p $(DESTDIR)/usr/libexec/qubes
cp udev-block-add-change $(DESTDIR)/usr/libexec/qubes/
cp udev-block-remove $(DESTDIR)/usr/libexec/qubes/
cp udev-block-cleanup $(DESTDIR)/usr/libexec/qubes/
cp udev-usb-add-change $(DESTDIR)/usr/libexec/qubes/
cp udev-usb-remove $(DESTDIR)/usr/libexec/qubes/

@ -1,145 +1,47 @@
#!/bin/bash
shopt -s nullglob
export LC_CTYPE=en_US.UTF-8
NAME=${DEVNAME#/dev/}
DESC="`echo "${ID_MODEL} (${ID_FS_LABEL})" | iconv -f utf8 -t ascii//TRANSLIT`"
SIZE=$[ $(cat /sys/$DEVPATH/size) * 512 ]
MODE=w
QDB_KEY="/qubes-block-devices/$NAME"
XS_KEY="qubes-block-devices/$NAME"
xs_remove() {
if is_attached /sys$DEVPATH; then
return 0
fi
if qubesdb-read -q "$QDB_KEY/desc" >/dev/null; then
qubesdb-rm "$QDB_KEY/"
qubesdb-write /qubes-block-devices ''
fi
}
is_used() {
local sys_devpath=$1
local devname=$(grep ^DEVNAME= $sys_devpath/uevent | cut -f 2 -d =)
# mounted; or enabled swap
if lsblk -dnr -o MOUNTPOINT "/dev/$devname" | grep -q .; then
return 0
fi
# part of other device-mapper
if [ -n "`ls -A $sys_devpath/holders 2> /dev/null`" ]; then
return 0
fi
# open device-mapper device
if [ -f "$sys_devpath/dm/name" ] && \
/sbin/dmsetup info "$(cat $sys_devpath/dm/name)" |\
grep -q "^Open count:.*[1-9]"; then
return 0
if [ "$QUBES_EXPOSED" == "1" ]; then
xenstore-rm "$XS_KEY"
fi
return 1
echo QUBES_EXPOSED=0
}
refresh_another() {
# launch this script for other device
local devpath=$1
local launch_env=$(udevadm info -q all -x -p "$devpath" \
| grep ^E: | cut -d ' ' -f 2- | tr ' ' ':')
env -i PATH=$PATH $launch_env $0
}
is_attached() {
dev_hex=$(stat -c %t:%T /dev/$(basename $1))
if [ -z "$dev_hex" -o "$dev_hex" = "0:0" ]; then
return 1
fi
# looking at sysfs is much faster than looking at xenstore
# this code requires no subprocesses and doesn't hit argument length limitations
for i in /sys/bus/xen-backend/drivers/vbd/vbd-*/physical_device; do
read i_dev_hex < "$i"
if test "$i_dev_hex" == "$dev_hex"; then
return 0
fi
done
return 1
}
# update info about parent devices, if any:
if [ -f /sys$DEVPATH/partition ]; then
parent=$(dirname $(readlink -f /sys$DEVPATH))
refresh_another /$(realpath --relative-to=/sys $parent)
# if parent device is already attached, skip its partitions
if is_attached $parent; then
xs_remove
exit 0
fi
fi
# and underlying devices of device-mapper (if any)
for dev in /sys$DEVPATH/slaves/*; do
refresh_another /$(realpath --relative-to=/sys $dev)
done
# cache slave devices for remove event
if [ -n "$DM_NAME" ]; then
ls -1 /sys$DEVPATH/slaves/ > /var/run/qubes/block-slave-cache-$NAME
# Ignore mounted...
if fgrep -q $DEVNAME /proc/mounts; then
xs_remove
exit 0
fi
# then take care of this device:
# udev rules already excluded this device:
if [ "$DM_UDEV_DISABLE_DISK_RULES_FLAG" = "1" ]; then
# ... and used by device-mapper
if [ -n "`ls -A /sys/$DEVPATH/holders 2> /dev/null`" ]; then
xs_remove
exit 0
fi
# device itself is already used
if is_used /sys$DEVPATH; then
# ... and used device-mapper devices
if [ -n "$DM_NAME" ] && /sbin/dmsetup info "$DM_NAME" | grep -q "^Open count:.*[1-9]"; then
xs_remove
exit 0
fi
# or one of its partitions is used
# or already attached (prevent attaching both device and its partition(s) at
# the same time)
for part in /sys$DEVPATH/$NAME*; do
if [ -d $part ]; then
if is_used $part || is_attached $part; then
xs_remove
exit 0
fi
fi
done
# or "empty" loop device
# ... and "empty" loop devices
if [ "$MAJOR" -eq 7 -a ! -d /sys/$DEVPATH/loop ]; then
xs_remove
exit 0
fi
# or unconnected Network Block Device
if [ "$MAJOR" -eq 43 -a ! -e /sys/$DEVPATH/pid ]; then
# ... and temporary devices used during VM startup
if [[ "$NAME" = 'loop'* ]] && \
[[ "`cat /sys/block/${NAME%p*}/loop/backing_file`" = \
'/var/lib/qubes/'*'/volatile.img' ]]; then
xs_remove
exit 0
fi
# ... and loop devices from excluded directories
if [[ "$NAME" = 'loop'* ]]; then
backing_file=$(cat /sys/block/${NAME}/loop/backing_file)
if [ -n "$backing_file" ]; then
dir_to_check=$(dirname "$backing_file")
while [ "$dir_to_check" != "/" -a "$dir_to_check" != "." ]; do
if [ -e "$dir_to_check/.qubes-exclude-block-devices" ]; then
xs_remove
exit 0
fi
dir_to_check=$(dirname "$dir_to_check")
done
fi
fi
# Check if device is read-only
if [ "`cat /sys/$DEVPATH/ro`" -eq 1 ]; then
MODE=r
@ -164,12 +66,18 @@ if [ -n "$DM_NAME" ]; then
DESC="$DM_NAME"
fi
# The last one is meant to trigger watches
qubesdb-write \
"$QDB_KEY/desc" "$DESC" \
"$QDB_KEY/size" "$SIZE" \
"$QDB_KEY/mode" "$MODE" \
/qubes-block-devices ''
# Get lock only in dom0 - there are so many block devices so it causes xenstore
# deadlocks sometimes.
if [ -f /etc/qubes-release ]; then
# Skip xenstore-write if cannot obtain lock. This can mean very early system startup
# stage without /run mounted (or populated). Devices will be rediscovered later
# by qubes-core startup script.
exec 9>>/var/run/qubes/block-xenstore.lock || exit 0
flock 9
fi
xenstore-write "$XS_KEY/desc" "$DESC" "$XS_KEY/size" "$SIZE" "$XS_KEY/mode" "$MODE"
echo QUBES_EXPOSED=1
# Make sure that block backend is loaded
/sbin/modprobe xen-blkback 2> /dev/null || /sbin/modprobe blkbk

@ -0,0 +1,8 @@
#!/bin/sh
DEVID=$[ $MAJOR * 256 + $MINOR ]
XS_PATH="device/vbd/$DEVID"
# Double check that DEVID is not empty
[ -n "$DEVID" ] && xenstore-rm $XS_PATH

@ -1,16 +1,32 @@
#!/bin/sh
NAME=${DEVNAME#/dev/}
QDB_KEY="/qubes-block-devices/$NAME"
# Trailing slash is intentional - it will remove the whole directory, instead of
# a single base entry
qubesdb-rm "$QDB_KEY/"
qubesdb-write /qubes-block-devices ''
XS_KEY="qubes-block-devices/$NAME"
xenstore-rm "$XS_KEY"
if [ -r /var/run/qubes/block-slave-cache-$NAME ]; then
# update info about underlying devices of device-mapper (if any);
for dev in $(cat /var/run/qubes/block-slave-cache-$NAME); do
udevadm trigger /sys/class/block/$dev
# If device was connected to some VM - detach it
# Notice: this can be run also in VM, so we cannot use xl...
device_detach() {
xs_path=$1
xenstore-write $xs_path/online 0 $xs_path/state 5
# Wait for backend to finish dev shutdown
try=30
# -lt will break loop also when 'state' will be empty
while [ "`xenstore-read $xs_path/state 2> /dev/null`" -lt 6 ]; do
try=$[ $try - 1 ]
[ "$try" -le 0 ] && break
sleep 0.1
done
rm -f /var/run/qubes/block-slave-cache-$NAME
fi
xenstore-rm $xs_path
}
for XS_DEV_PATH in `xenstore-ls -f backend/vbd | grep 'backend/vbd/[0-9]*/[0-9]* ' | cut -f 1 -d ' '`; do
CUR_DEVICE=`xenstore-read "$XS_DEV_PATH/params"`
if [ "$CUR_DEVICE" == "$DEVNAME" ]; then
device_detach "$XS_DEV_PATH"
exit 0
fi
done

@ -1,4 +1,4 @@
# Expose all (except xen-frontend) block devices via Qubes DB
# Expose all (except xen-frontend) block devices via xenstore
# Only block devices are interesting
SUBSYSTEM!="block", GOTO="qubes_block_end"
@ -10,16 +10,17 @@ KERNEL=="xvda|xvdb|xvdc*|xvdd", ENV{UDISKS_IGNORE}="1"
# Skip xen-blkfront devices
ENV{MAJOR}=="202", GOTO="qubes_block_end"
# skip devices excluded elsewhere
ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="qubes_block_end"
# Skip device-mapper devices
KERNEL=="dm-*", ENV{DM_NAME}=="snapshot-*", GOTO="qubes_block_end"
KERNEL=="dm-*", ENV{DM_NAME}=="origin-*", GOTO="qubes_block_end"
KERNEL=="dm-*", ENV{DM_NAME}=="", GOTO="qubes_block_end"
ENV{MAJOR}=="253", ENV{DM_NAME}=="snapshot-*", GOTO="qubes_block_end"
ENV{MAJOR}=="253", ENV{DM_NAME}=="origin-*", GOTO="qubes_block_end"
ENV{MAJOR}=="253", ENV{DM_NAME}=="", GOTO="qubes_block_end"
ACTION=="add", RUN+="/usr/lib/qubes/udev-block-add-change"
ACTION=="change", RUN+="/usr/lib/qubes/udev-block-add-change"
ACTION=="remove", RUN+="/usr/lib/qubes/udev-block-remove"
IMPORT{db}="QUBES_EXPOSED"
ACTION=="add", IMPORT{program}="/usr/bin/flock /var/run/qubes-udev.lock -c /usr/libexec/qubes/udev-block-add-change"
ACTION=="change", IMPORT{program}="/usr/bin/flock /var/run/qubes-udev.lock -c /usr/libexec/qubes/udev-block-add-change"
ACTION=="remove", RUN+="/usr/libexec/qubes/udev-block-remove"
LABEL="qubes_block_end"
# Cleanup disconnected frontend from xenstore
ACTION=="remove", SUBSYSTEM=="block", ENV{MAJOR}=="202", RUN+="/usr/libexec/qubes/udev-block-cleanup"

@ -1,5 +0,0 @@
# Create /dev/mapper/dmroot symlink on TemplateVM/StandaloneVM to make
# grub-mkconfig happy.
# On TemplateBasedVM, it is really a device mapper device.
SUBSYSTEM=="block", ENV{ID_PART_ENTRY_NAME}=="Root\x20filesystem", ATTR{ro}=="0", SYMLINK+="mapper/dmroot"

@ -1,7 +0,0 @@
# Setup permissions to allow libvchan connections as normal user
KERNEL=="xen/evtchn", MODE="0660", GROUP="qubes"
KERNEL=="xen/gntdev", MODE="0660", GROUP="qubes"
KERNEL=="xen/gntalloc", MODE="0660", GROUP="qubes"
KERNEL=="xen/privcmd", MODE="0660", GROUP="qubes"
KERNEL=="xen/xenbus", MODE="0660", GROUP="qubes"
KERNEL=="xen/hypercall", MODE="0660", GROUP="qubes"

@ -1,13 +1,10 @@
# Expose all USB devices (except block) via Qubes DB
# Expose all USB devices (except block) via xenstore
# Handle only USB devices
SUBSYSTEM!="usb", GOTO="qubes_usb_end"
# ignore qemu emulated devices in HVM
ENV{ID_VENDOR}=="QEMU", GOTO="qubes_usb_end"
ACTION=="add", IMPORT{program}="/usr/lib/qubes/udev-usb-add-change"
ACTION=="change", IMPORT{program}="/usr/lib/qubes/udev-usb-add-change"
ACTION=="remove", RUN+="/usr/lib/qubes/udev-usb-remove"
ACTION=="add", IMPORT{program}="/usr/libexec/qubes/udev-usb-add-change"
ACTION=="change", IMPORT{program}="/usr/libexec/qubes/udev-usb-add-change"
ACTION=="remove", RUN+="/usr/libexec/qubes/udev-usb-remove"
LABEL="qubes_usb_end"

@ -12,7 +12,7 @@
[ "`echo $TYPE | cut -f1 -d/`" = "9" ] && exit 0
[ "$DEVTYPE" != "usb_device" ] && exit 0
# qubesdb doesn't allow dot in key name
# xenstore doesn't allow dot in key name
XSNAME=`basename ${DEVPATH} | tr . _`
# FIXME: For some devices (my Cherry keyboard) ID_SERIAL does not
@ -21,19 +21,20 @@ XSNAME=`basename ${DEVPATH} | tr . _`
#DESC=`python -c "dev='%d-%d' % (int('${BUSNUM}'.lstrip('0')), (int('${DEVNUM}'.lstrip('0'))-1)); from xen.util import vusb_util; print vusb_util.get_usbdevice_info(dev);"`
DESC="${ID_VENDOR_ID}:${ID_MODEL_ID} ${ID_SERIAL}"
VERSION=`cat /sys/$DEVPATH/version | tr -d ' '|cut -f 1 -d .`
# ignore usbip-connected devices, as most likely already passed through from
# another VM
if echo $DEVPATH | grep -q /vhci_hcd; then
exit 0
VERSION=`cat /sys/$DEVPATH/version`
if [ "${VERSION}" = " 1.00" -o "${VERSION}" = " 1.10" ] ; then
VERSION=1
elif [ "${VERSION}" = " 2.00" ] ; then
VERSION=2
else
# FIXME: silently ignoring devices with unexpected USB version
exit 0
fi
QDB_KEY="/qubes-usb-devices/$XSNAME"
XS_KEY="qubes-usb-devices/$XSNAME"
qubesdb-write "$QDB_KEY/desc" "$DESC"
qubesdb-write "$QDB_KEY/usb-ver" "$VERSION"
qubesdb-write /qubes-usb-devices ''
xenstore-write "$XS_KEY/desc" "$DESC"
xenstore-write "$XS_KEY/usb-ver" "$VERSION"
# Make sure PVUSB backend driver is loaded.
/sbin/modprobe xen-usbback 2> /dev/null || true
/sbin/modprobe xen-usbback 2> /dev/null || /sbin/modprobe usbbk

@ -4,7 +4,6 @@
[ "`echo $TYPE | cut -f1 -d/`" = "9" ] && exit 0
NAME=`basename ${DEVPATH} | tr . _`
QDB_KEY="/qubes-usb-devices/$NAME/"
XS_KEY="qubes-usb-devices/$NAME"
qubesdb-rm "$QDB_KEY"
qubesdb-write /qubes-usb-devices ''
xenstore-rm "$XS_KEY"

@ -1 +1 @@
4.1.3
2.0.21

Loading…
Cancel
Save