clock synchronization rewrite

clock synchronization mechanism rewritten to use systemd-timesync instead of NtpDate; at the moment, requires:
- modifying /etc/qubes-rpc/policy/qubes.GetDate to redirect GetDate to designated clockvm
- enabling clocksync service in clockvm ( qvm-features clockvm-name service/clocksync true )

Works as specified in issue listed below, except for:
- each VM synces with clockvm after boot and every 6h
- clockvm synces time with the Internet using systemd-timesync
- dom0 synces itself with clockvm every 1h (using cron)

fixes QubesOS/qubes-issues#1230
This commit is contained in:
Marta Marczykowska-Górecka 2017-07-06 23:37:26 +02:00
parent d9db4f747c
commit 6da06d424e
No known key found for this signature in database
GPG Key ID: 9A752C30B26FD04B
4 changed files with 24 additions and 102 deletions

View File

@ -164,11 +164,13 @@ endif
cp qubes-rpc-policy/qubes.OpenInVM.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenInVM cp qubes-rpc-policy/qubes.OpenInVM.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenInVM
cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell
cp qubes-rpc-policy/qubes.UpdatesProxy.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.UpdatesProxy cp qubes-rpc-policy/qubes.UpdatesProxy.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.UpdatesProxy
cp qubes-rpc-policy/qubes.GetDate.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetDate
cp qubes-rpc/qubes.FeaturesRequest $(DESTDIR)/etc/qubes-rpc/ cp qubes-rpc/qubes.FeaturesRequest $(DESTDIR)/etc/qubes-rpc/
cp qubes-rpc/qubes.GetRandomizedTime $(DESTDIR)/etc/qubes-rpc/ cp qubes-rpc/qubes.GetRandomizedTime $(DESTDIR)/etc/qubes-rpc/
cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/ cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/
cp qubes-rpc/qubes.NotifyUpdates $(DESTDIR)/etc/qubes-rpc/ cp qubes-rpc/qubes.NotifyUpdates $(DESTDIR)/etc/qubes-rpc/
install qubes-rpc/qubesd-query-fast $(DESTDIR)/usr/libexec/qubes/ install qubes-rpc/qubesd-query-fast $(DESTDIR)/usr/libexec/qubes/
install -m 0755 qvm-tools/qvm-sync-clock $(DESTDIR)/usr/bin/qvm-sync-clock
for method in $(ADMIN_API_METHODS_SIMPLE); do \ for method in $(ADMIN_API_METHODS_SIMPLE); do \
ln -s ../../usr/libexec/qubes/qubesd-query-fast \ ln -s ../../usr/libexec/qubes/qubesd-query-fast \
$(DESTDIR)/etc/qubes-rpc/$$method || exit 1; \ $(DESTDIR)/etc/qubes-rpc/$$method || exit 1; \

View File

@ -0,0 +1,6 @@
## Note that policy parsing stops at the first match,
## so adding anything below "$anyvm $anyvm action" line will have no effect
## Please use a single # to start your custom comments
$anyvm $anyvm allow,target=sys-net

View File

@ -1,4 +1,4 @@
#!/usr/bin/python2 #!/usr/bin/python3
# -*- encoding: utf8 -*- # -*- encoding: utf8 -*-
# #
# The Qubes OS Project, http://www.qubes-os.org # The Qubes OS Project, http://www.qubes-os.org
@ -20,115 +20,28 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# #
# #
import fcntl
from optparse import OptionParser
from qubes.qubes import QubesVmCollection
import os.path
import os
import sys import sys
import re import re
import subprocess import subprocess
from qubesadmin import Qubes
qvm_collection = None
def get_netvm_of_vm(vm):
netvm = vm
while netvm.netvm is not None:
netvm = netvm.netvm
if netvm is None or netvm.name == 'dom0':
print >> sys.stderr, 'There seems to be no network connected to ClockVM, aborting.'
sys.exit(1)
return netvm
def main(): def main():
parser = OptionParser()
parser.add_option ("-v", "--verbose", action="store_true", dest="verbose", default=False)
parser.add_option ("-f", "--force", action="store_true", dest="force", default=False)
(options, args) = parser.parse_args () app = Qubes()
clockvm = app.clockvm
lockfile_name = "/var/run/qubes/qvm-sync-clock.lock" p = clockvm.run_service('qubes.GetDate')
if os.path.exists(lockfile_name): date_out = p.stdout.read(25).decode('ascii', errors='strict')
lockfile = open(lockfile_name, "r") date_out = date_out.strip()
else:
lockfile = open(lockfile_name, "w")
fcntl.fcntl(lockfile.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) if not re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+00:?00$', date_out):
try: sys.stderr.write('Invalid date received, aborting!')
fcntl.flock(lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
print >>sys.stderr, "qvm-sync-clock already running, aborting"
sys.exit(1) sys.exit(1)
subprocess.check_call(['date', '-u', '-Iseconds', '-s', date_out],
qvm_collection = QubesVmCollection() stdout=subprocess.DEVNULL)
qvm_collection.lock_db_for_reading() subprocess.check_call(['hwclock', '--systohc'],
qvm_collection.load() stdout=subprocess.DEVNULL)
qvm_collection.unlock_db()
clock_vm = qvm_collection.get_clockvm_vm() if __name__ == '__main__':
main()
if clock_vm is None:
print >> sys.stderr, 'There is no selected ClockVM, aborting.'
sys.exit(1)
if not clock_vm.is_running():
print >> sys.stderr, 'ClockVM not started, exiting!'
sys.exit(1)
net_vm = get_netvm_of_vm(clock_vm)
if options.verbose:
print >> sys.stderr, '--> Waiting for network for ClockVM.'
# Ignore retcode, try even if nm-online failed - user can setup network manually
# on-online has timeout 30sec by default
net_vm.run('nm-online -x', verbose=options.verbose, gui=False, wait=True,
ignore_stderr=True)
# Sync clock
if clock_vm.run('QUBESRPC qubes.SyncNtpClock dom0', user="root",
verbose=options.verbose, gui=False, wait=True, ignore_stderr=True) \
!= 0:
if options.force:
print >> sys.stderr, 'Time sync failed! - Syncing with dom0 ' \
'anyway as requested'
else:
print >> sys.stderr, 'Time sync failed! - Exiting'
sys.exit(1)
else:
# Use the date format based on RFC2822 to avoid localisation issues
p = clock_vm.run('date -u -Iseconds', verbose=options.verbose,
gui=False, passio_popen=True, ignore_stderr=True)
date_out = p.stdout.read(100)
date_out = date_out.strip()
if not re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+00:?00$', date_out):
print >> sys.stderr, 'Invalid date output, aborting!'
sys.exit(1)
# Sync dom0 time
if options.verbose:
print >> sys.stderr, '--> Syncing dom0 clock.'
subprocess.check_call(['sudo', 'date', '-u', '-Iseconds', '-s', date_out],
stdout=None if options.verbose else open(os.devnull, 'w'))
subprocess.check_call(['sudo', 'hwclock', '--systohc'],
stdout=None if options.verbose else open(os.devnull, 'w'))
# Sync other VMs clock
for vm in qvm_collection.values():
if vm.is_running() and vm.qid != 0 and vm.qid != clock_vm.qid:
if options.verbose:
print >> sys.stderr, '--> Syncing \'%s\' clock.' % vm.name
try:
vm.run_service("qubes.SetDateTime", user="root",
localcmd="date -u -Iseconds")
except Exception as e:
print >> sys.stderr, "ERROR syncing time in VM '%s': %s" % (vm.name, str(e))
pass
# order is important!
os.unlink(lockfile_name)
lockfile.close()
main()

View File

@ -427,6 +427,7 @@ fi
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.OpenURL %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.OpenURL
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMShell %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMShell
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.UpdatesProxy %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.UpdatesProxy
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.GetDate
/etc/qubes-rpc/admin.* /etc/qubes-rpc/admin.*
/etc/qubes-rpc/qubes.FeaturesRequest /etc/qubes-rpc/qubes.FeaturesRequest
/etc/qubes-rpc/qubes.GetRandomizedTime /etc/qubes-rpc/qubes.GetRandomizedTime