[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] merge with xen-unstable.hg
# HG changeset patch # User Alex Williamson <alex.williamson@xxxxxx> # Date 1184078366 21600 # Node ID 42586a0f4407528a32ba9da003d14a8ff49193bf # Parent 87b0b6a08dbdf5882c6223b0b6b7b189a15b0482 # Parent 80099a459d7a2f9c2d7f895ffc8854ca9435206d merge with xen-unstable.hg --- tools/xenstore/fake_libxc.c | 143 - tools/xenstore/speedtest.c | 130 - tools/xenstore/testsuite/01simple.test | 4 tools/xenstore/testsuite/02directory.test | 45 tools/xenstore/testsuite/03write.test | 28 tools/xenstore/testsuite/04rm.test | 20 tools/xenstore/testsuite/05filepermissions.test | 81 - tools/xenstore/testsuite/06dirpermissions.test | 119 - tools/xenstore/testsuite/07watch.test | 176 -- tools/xenstore/testsuite/08transaction.slowtest | 43 tools/xenstore/testsuite/08transaction.test | 92 - tools/xenstore/testsuite/09domain.test | 19 tools/xenstore/testsuite/10domain-homedir.test | 18 tools/xenstore/testsuite/11domain-watch.test | 50 tools/xenstore/testsuite/12readonly.test | 38 tools/xenstore/testsuite/13watch-ack.test | 21 tools/xenstore/testsuite/14complexperms.test | 68 tools/xenstore/testsuite/test.sh | 64 tools/xenstore/testsuite/vg-suppressions | 9 tools/xenstore/xenstored_test.h | 37 tools/xenstore/xs_crashme.c | 393 ---- tools/xenstore/xs_random.c | 1590 -------------------- tools/xenstore/xs_stress.c | 207 -- tools/xenstore/xs_test.c | 812 ---------- xen/arch/x86/genapic/es7000.h | 120 - .hgignore | 4 Config.mk | 7 buildconfigs/enable-xen-config | 36 buildconfigs/ketchup | 742 +++++++++ buildconfigs/mk.linux-2.6-mm | 14 buildconfigs/mk.linux-2.6-paravirt | 4 buildconfigs/mk.linux-2.6-rc | 14 buildconfigs/mk.linux-2.6-tip | 14 buildconfigs/mk.linux-2.6-xen | 4 buildconfigs/src.tarball | 12 docs/man/xm.pod.1 | 331 ++-- tools/blktap/drivers/Makefile | 1 tools/blktap/lib/Makefile | 2 tools/examples/init.d/xendomains | 29 tools/examples/xend-config.sxp | 6 tools/firmware/etherboot/README | 5 tools/firmware/rombios/rombios.c | 4 tools/firmware/vmxassist/vm86.c | 190 +- tools/ioemu/keymaps/ja | 1 tools/ioemu/keymaps/modifiers | 4 tools/ioemu/vnc_keysym.h | 4 tools/libxc/Makefile | 1 tools/libxc/xc_domain.c | 1 tools/libxc/xc_misc.c | 2 tools/libxc/xenctrl.h | 3 tools/python/xen/lowlevel/xc/xc.c | 69 tools/python/xen/util/acmpolicy.py | 1199 +++++++++++++++ tools/python/xen/util/bootloader.py | 521 ++++++ tools/python/xen/util/security.py | 791 ++++++++- tools/python/xen/util/xsconstants.py | 104 + tools/python/xen/util/xspolicy.py | 66 tools/python/xen/xend/XendAPI.py | 66 tools/python/xen/xend/XendConfig.py | 40 tools/python/xen/xend/XendDomain.py | 35 tools/python/xen/xend/XendDomainInfo.py | 198 ++ tools/python/xen/xend/XendError.py | 18 tools/python/xen/xend/XendNode.py | 61 tools/python/xen/xend/XendOptions.py | 3 tools/python/xen/xend/XendVDI.py | 12 tools/python/xen/xend/XendXSPolicy.py | 222 ++ tools/python/xen/xend/XendXSPolicyAdmin.py | 314 +++ tools/python/xen/xend/server/SrvDomain.py | 3 tools/python/xen/xend/server/blkif.py | 15 tools/python/xen/xend/server/netif.py | 9 tools/python/xen/xend/server/vfbif.py | 5 tools/python/xen/xm/create.py | 8 tools/python/xen/xm/main.py | 42 tools/security/policies/security_policy.xsd | 29 tools/security/xensec_ezpolicy | 16 tools/xcutils/Makefile | 2 tools/xenmon/xenbaked.c | 2 tools/xenstat/libxenstat/src/xenstat.c | 2 tools/xenstore/Makefile | 94 - tools/xenstore/xenstored_core.c | 105 - tools/xenstore/xenstored_domain.c | 4 tools/xenstore/xenstored_transaction.c | 1 tools/xenstore/xenstored_watch.c | 12 tools/xentrace/xentrace.c | 2 tools/xm-test/tests/info/02_info_compiledata_pos.py | 4 xen/arch/ia64/Rules.mk | 2 xen/arch/ia64/xen/dom0_ops.c | 46 xen/arch/powerpc/Makefile | 16 xen/arch/powerpc/Rules.mk | 2 xen/arch/powerpc/boot_of.c | 27 xen/arch/powerpc/domain.c | 2 xen/arch/powerpc/domain_build.c | 136 - xen/arch/powerpc/external.c | 85 - xen/arch/powerpc/mm.c | 2 xen/arch/powerpc/mpic_init.c | 58 xen/arch/powerpc/mpic_init.h | 4 xen/arch/powerpc/of_handler/Makefile | 1 xen/arch/powerpc/of_handler/head.S | 26 xen/arch/powerpc/of_handler/ofh.c | 1 xen/arch/powerpc/of_handler/rtas.c | 82 + xen/arch/powerpc/of_handler/vdevice.c | 2 xen/arch/powerpc/of_handler/xen_hvcall.S | 26 xen/arch/powerpc/ofd_fixup.c | 37 xen/arch/powerpc/oftree.h | 4 xen/arch/powerpc/powerpc64/hypercall_table.S | 2 xen/arch/powerpc/rtas.c | 151 + xen/arch/powerpc/rtas.h | 31 xen/arch/powerpc/rtas_flash.c | 182 ++ xen/arch/powerpc/rtas_nvram.c | 129 + xen/arch/powerpc/sysctl.c | 6 xen/arch/powerpc/time.c | 2 xen/arch/x86/Rules.mk | 2 xen/arch/x86/dmi_scan.c | 2 xen/arch/x86/domain.c | 2 xen/arch/x86/domain_build.c | 3 xen/arch/x86/e820.c | 34 xen/arch/x86/genapic/es7000plat.c | 214 -- xen/arch/x86/hvm/svm/emulate.c | 4 xen/arch/x86/hvm/svm/svm.c | 135 + xen/arch/x86/hvm/vlapic.c | 4 xen/arch/x86/hvm/vmx/intr.c | 67 xen/arch/x86/hvm/vmx/vmcs.c | 15 xen/arch/x86/hvm/vmx/vmx.c | 630 ++++--- xen/arch/x86/mm.c | 34 xen/arch/x86/mm/hap/hap.c | 2 xen/arch/x86/mm/p2m.c | 23 xen/arch/x86/mm/shadow/common.c | 15 xen/arch/x86/mm/shadow/multi.c | 13 xen/arch/x86/mm/shadow/private.h | 4 xen/arch/x86/mpparse.c | 6 xen/arch/x86/setup.c | 126 - xen/arch/x86/sysctl.c | 32 xen/arch/x86/traps.c | 2 xen/arch/x86/x86_32/seg_fixup.c | 84 + xen/arch/x86/x86_32/traps.c | 10 xen/arch/x86/x86_32/xen.lds.S | 4 xen/arch/x86/x86_64/compat/traps.c | 25 xen/arch/x86/x86_64/compat_kexec.S | 2 xen/arch/x86/x86_64/entry.S | 1 xen/arch/x86/x86_64/mm.c | 113 - xen/arch/x86/x86_64/traps.c | 29 xen/arch/x86/x86_64/xen.lds.S | 4 xen/common/compat/kernel.c | 3 xen/common/domain.c | 41 xen/common/domctl.c | 1 xen/common/event_channel.c | 21 xen/common/kernel.c | 21 xen/common/page_alloc.c | 9 xen/include/asm-x86/config.h | 8 xen/include/asm-x86/hvm/svm/svm.h | 40 xen/include/asm-x86/hvm/vmx/vmcs.h | 4 xen/include/asm-x86/hvm/vmx/vmx.h | 24 xen/include/asm-x86/mach-es7000/mach_mpparse.h | 7 xen/include/asm-x86/mach-generic/mach_apic.h | 5 xen/include/asm-x86/mm.h | 3 xen/include/asm-x86/paging.h | 16 xen/include/asm-x86/processor.h | 7 xen/include/asm-x86/regs.h | 5 xen/include/asm-x86/system.h | 4 xen/include/public/domctl.h | 3 xen/include/public/sysctl.h | 20 xen/include/xen/compat.h | 2 xen/include/xen/cpumask.h | 9 xen/include/xen/init.h | 6 firmware/etherboot/eb-rtl8139.zrom | 0 164 files changed, 6505 insertions(+), 6293 deletions(-) diff -r 87b0b6a08dbd -r 42586a0f4407 .hgignore --- a/.hgignore Mon Jul 09 09:22:58 2007 -0600 +++ b/.hgignore Tue Jul 10 08:39:26 2007 -0600 @@ -67,6 +67,9 @@ ^linux-[^/]*-xen0/.*$ ^linux-[^/]*-xenU/.*$ ^linux-[^/]*-paravirt/.*$ +^linux-[^/]*-mm/.*$ +^linux-[^/]*-rc/.*$ +^linux-[^/]*-tip/.*$ ^linux-[^/]*\.patch$ ^mkddbxen$ ^netbsd-[^/]*-tools/.*$ @@ -241,6 +244,7 @@ ^xen/arch/powerpc/dom0\.bin$ ^xen/arch/powerpc/asm-offsets\.s$ ^xen/arch/powerpc/firmware$ +^xen/arch/powerpc/firmware.dbg$ ^xen/arch/powerpc/firmware_image.bin$ ^xen/arch/powerpc/xen\.lds$ ^xen/arch/powerpc/\.xen-syms$ diff -r 87b0b6a08dbd -r 42586a0f4407 Config.mk --- a/Config.mk Mon Jul 09 09:22:58 2007 -0600 +++ b/Config.mk Tue Jul 10 08:39:26 2007 -0600 @@ -17,8 +17,9 @@ SHELL ?= /bin/sh SHELL ?= /bin/sh # Tools to run on system hosting the build -HOSTCC = gcc -HOSTCFLAGS = -Wall -Werror -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCC = gcc +HOSTCFLAGS = -Wall -Werror -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS += -fno-strict-aliasing DISTDIR ?= $(XEN_ROOT)/dist DESTDIR ?= / @@ -58,6 +59,8 @@ CFLAGS += -g CFLAGS += -g endif +CFLAGS += -fno-strict-aliasing + CFLAGS += -std=gnu99 CFLAGS += -Wall -Wstrict-prototypes diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/enable-xen-config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildconfigs/enable-xen-config Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,36 @@ +#!/bin/sh + +set -ex + +if [ $# -ne 1 ] ; then + echo "Usage $(basename $0) <config-file>" 1>&2 + exit 1 +fi + +CONFIG=$1 + +setopt() +{ + OPTION=$1 + VALUE=$2 + + # First remove any existing instances of this option + sed -e "s/^# ${OPTION} is not set$//g ; s/^^{OPTION}=.$//g" -i "${CONFIG}" + + # Then append the new value + case ${VALUE} in + y|m) echo "${OPTION}=${VALUE}" >> "${CONFIG}" ;; + n) echo "# ${OPTION} is not set" >> "${CONFIG}" ;; + *) echo "Invalid value ${VALUE} for ${OPTION}" 1>&2 ; exit 1 ;; + esac +} + +setopt CONFIG_PARAVIRT y +setopt CONFIG_XEN y +setopt CONFIG_VMI y +setopt CONFIG_LGUEST n +setopt CONFIG_XEN_BLKDEV_FRONTEND y +setopt CONFIG_XEN_NETDEV_FRONTEND y +setopt CONFIG_HVC_XEN y + +exit 0 diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/ketchup --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildconfigs/ketchup Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,742 @@ +#!/usr/bin/python +# +# ketchup 0.9.8 +# http://selenic.com/ketchup/wiki +# +# Copyright 2004 Matt Mackall <mpm@xxxxxxxxxxx> +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. +# +# Usage: +# +# in an existing kernel directory, run: +# +# ketchup <version> +# +# where version is a complete kernel version, or a branch name to grab +# the latest version +# +# You can override some variables by creating a ~/.ketchuprc file. +# The ~/.ketchuprc is just a Python script, eg. it might look like this: +# +# kernel_url = 'http://kernel.localdomain/pub/linux/kernel' +# archive = os.environ["HOME"] + '/tmp/ketchup-archive' +# gpg = '/weird/path/to/gpg' +# + +import re, sys, urllib, os, getopt, glob, shutil + +def error(*args): + sys.stderr.write("ketchup: ") + for a in args: + sys.stderr.write(str(a)) + sys.stderr.write("\n") + +def qprint(*args): + if not options["quiet"]: + sys.stdout.write(" ".join(map(str, args))) + sys.stdout.write("\n") + +def lprint(*args): + sys.stdout.write(" ".join(map(str, args))) + sys.stdout.write("\n") + + +def fancyopts(args, options, state, syntax=''): + long = [] + short = '' + map = {} + dt = {} + + def help(state, opt, arg, options = options, syntax = syntax): + lprint("Usage: ", syntax) + + for s, l, d, c in options: + opt = ' ' + if s: opt = opt + '-' + s + ' ' + if l: opt = opt + '--' + l + ' ' + if d: opt = opt + '(' + str(d) + ')' + lprint(opt) + if c: lprint(' %s' % c) + sys.exit(0) + + options = [('h', 'help', help, 'Show usage info')] + options + + for s, l, d, c in options: + map['-'+s] = map['--'+l]=l + state[l] = d + dt[l] = type(d) + if not d is None and not type(d) is type(help): s, l = s + ':', l + '=' + if s: short = short + s + if l: long.append(l) + + if os.environ.has_key("KETCHUP_OPTS"): + args = os.environ["KETCHUP_OPTS"].split() + args + + try: + opts, args = getopt.getopt(args, short, long) + except getopt.GetoptError: + help(state, None, args) + sys.exit(-1) + + for opt, arg in opts: + if dt[map[opt]] is type(help): state[map[opt]](state,map[opt],arg) + elif dt[map[opt]] is type(1): state[map[opt]] = int(arg) + elif dt[map[opt]] is type(''): state[map[opt]] = arg + elif dt[map[opt]] is type([]): state[map[opt]].append(arg) + elif dt[map[opt]] is type(None): state[map[opt]] = 1 + + return args + +# Default values +kernel_url = 'http://www.kernel.org/pub/linux/kernel' +archive = os.environ["HOME"] + "/.ketchup" +rename_prefix = 'linux-' +rename_with_localversion = False +wget = "/usr/bin/wget" +gpg = "/usr/bin/gpg" +precommand = postcommand = None +default_tree = None +local_trees = {} + +# Functions to parse version strings + +def tree(ver): + return float(re.match(r'(\d+\.\d+)', ver).group(1)) + +def rev(ver): + p = pre(ver) + r = int(re.match(r'\d+\.\d+\.(\d+)', ver).group(1)) + if p: r = r - 1 + return r + +def pre(ver): + try: return re.match(r'\d+\.\d+\.\d+(\.\d+)?-((rc|pre)\d+)', ver).group(2) + except: return None + +def post(ver): + try: return re.match(r'\d+\.\d+\.\d+\.(\d+)', ver).group(1) + except: return None + +def pretype(ver): + try: return re.match(r'\d+\.\d+\.\d+(\.\d+)?-((rc|pre)\d+)', ver).group(3) + except: return None + +def prenum(ver): + try: return int(re.match(r'\d+\.\d+\.\d+-((rc|pre)(\d+))', ver).group(3)) + except: return None + +def prebase(ver): + return re.match(r'(\d+\.\d+\.\d+((-(rc|pre)|\.)\d+)?)', ver).group(1) + +def revbase(ver): + return "%s.%s" % (tree(ver), rev(ver)) + +def base(ver): + v = revbase(ver) + if post(ver): v += "." + post(ver) + return v + +def forkname(ver): + try: return re.match(r'\d+.\d+.\d+(\.\d+)?(-(rc|pre)\d+)?(-(\w+?)\d+)?', + ver).group(5) + except: return None + +def forknum(ver): + try: return int( + re.match(r'\d+.\d+.\d+(\.\d+)?(-(rc|pre)\d+)?(-(\w+?)(\d+))?', + ver).group(6)) + except: return None + +def fork(ver): + try: return re.match(r'\d+.\d+.\d+(\.\d+)?(-(rc|pre)\d+)?(-(\w+))?', ver).group(4) + except: return None + +def get_ver(makefile): + """ Read the version information from the specified makefile """ + part = {} + parts = "VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION".split(' ') + m = open(makefile) + for l in m.readlines(): + for p in parts: + try: part[p] = re.match(r'%s\s*=\s*(\S+)' % p, l).group(1) + except: pass + + version = "%s.%s.%s" % tuple([part[p] for p in parts[:3]]) + version += part.get("EXTRAVERSION","") + return version + +def get_localversion(): + v = '' + + for name in glob.glob('localversion*'): + try: v += open(name).readline().strip() + except: pass + + try: + c = open('.config').read() + v += re.search(r'^CONFIG_LOCALVERSION="(.+)"', c, re.M).group(1) + except: pass + + return v + +def compare_ver(a, b): + """ + Compare kernel versions a and b + + Note that -pre and -rc versions sort before the version they modify, + -pre sorts before -rc, -bk, -git, and -mm, etc. sort alphabetically. + """ + if a == b: return 0 + + c = cmp(float(tree(a)), float(tree(b))) + if c: return c + c = cmp(rev(a), rev(b)) + if c: return c + c = cmp(int(post(a) or 0), int(post(b) or 0)) + if c: return c + c = cmp(pretype(a), pretype(b)) # pre sorts before rc + if c: return c + c = cmp(prenum(a), prenum(b)) + if c: return c + c = cmp(forkname(a), forkname(b)) + if c: return c + return cmp(forknum(a), forknum(b)) + +def last(url, pat="(.*/)"): + for l in urllib.urlopen(url).readlines(): + m = re.search('(?i)<a href="%s">' % pat, l) + if m: n = m.group(1) + return n + +def latest_mm(url, pat): + url = kernel_url + '/people/akpm/patches/2.6/' + url += last(url) + part = last(url) + return part[:-1] + +def latest_ck(url, pat): + url = "http://ck.kolivas.org/patches/2.6/pre-releases/" + url += last(url) + part = last(url) + pre = part[:-1] + + url = "http://ck.kolivas.org/patches/2.6/" + url += last(url,"(2.6.*/)") + part = last(url) + rel = part[:-1] + + l = [pre, rel] + l.sort(compare_ver) + return l[-1] + +def latest_dir(url, pat): + """Find the latest link matching pat at url after sorting""" + p = [] + for l in urllib.urlopen(url).readlines(): + m = re.search('"%s"' % pat, l) + if m: p.append(m.group(1)) + + if not p: return None + + p.sort(compare_ver) + return p[-1] + +# mbligh is lazy and has a bunch of empty directories +def latest_mjb(url, pat): + url = kernel_url + '/people/mbligh/' + + # find the last Linus release and search backwards + l = [find_ver('2.6'), find_ver("2.6-pre")] + l.sort(compare_ver) + linus = l[-1] + + p = [] + for l in urllib.urlopen(url).readlines(): + m = re.search('"(2\.6\..*/)"', l) + if m: + v = m.group(1) + if compare_ver(v, linus) <= 0: + p.append(v) + + p.sort(compare_ver) + p.reverse() + + for ver in p: + mjb = latest_dir(url + ver, pat) + if mjb: return mjb + + return None + +def latest_26_tip(url, pat): + l = [find_ver('2.6'), find_ver('2.6-git'), find_ver('2.6-pre')] + l.sort(compare_ver) + return l[-1] + +def find_info(ver): + b = "%.1f" % tree(ver) + f = forkname(ver) + p = pre(ver) + + s = b + if f: + s = "%s-%s" % (b, f) + elif p: + s = "%s-pre" % b + + return version_info[s] + +def version_urls(ver): + """ Return the URL for the patch associated with the specified version """ + i = find_info(ver)[1] + if type(i) != type([]): + i = [i] + + v = { + 'full': ver, + 'tree': tree(ver), + 'base': base(ver), + 'prebase': prebase(ver) + } + + l = [] + for e in i: + l.append(e % v) + + return l + +def patch_path(ver): + return os.path.join(archive, os.path.basename(version_urls(ver)[0])) + +def download(url, f): + qprint("Downloading %s" % os.path.basename(url)) + if options["dry-run"]: + return 1 + + if not options["wget"]: + p = urllib.urlopen(url).read() + if p.find("<title>404") != -1: + return None + open(f, 'w').write(p) + else: + e = os.system("%s -c -O %s %s" % + (options["wget"], f + ".partial", url)) + if e: + return None + os.rename(f + ".partial", f) + + return 1 + +def verify(url, f, sign): + if options["no-gpg"] or options["dry-run"] or not options["gpg-path"]: + return 1 + + sf = f + sign + if not download(url + sign, sf): + error("signature download failed") + error("removing files...") + os.unlink(f) + return 0 + + qprint("Verifying signature...") + r = os.system("%s --verify %s %s" % (options["gpg-path"], sf, f)) + if r: + error("gpg returned %d" % r) + error("removing files...") + os.unlink(f) + os.unlink(sf) + return 0 + + return 1 + +def trydownload(urls, f, sign): + for url in urls: + if download(url, f): + if not sign or verify(url, f, sign): + return f + if url[-4:] == ".bz2": + f2 = f[:-4] + ".gz" + url2 = url[:-4] + ".gz" + if download(url2, f2): + if not sign or verify(url2, f2, sign): + return f2 + return None + +def get_patch(ver): + """Return the path to patch for given ver, downloading if necessary""" + f = patch_path(ver) + if os.path.exists(f): + return f + if f[-4:] == ".bz2": + f2 = f[:-4] + ".gz" + if os.path.exists(f2): + return f2 + + urls = version_urls(ver) + sign = find_info(ver)[3] + if sign == 1: sign = ".sign" + f = trydownload(urls, f, sign) + if not f: + error("patch download failed") + sys.exit(-1) + + return f + +def apply_patch(ver, reverse = 0): + """Find the patch to upgrade from the predecessor of ver to ver and + apply or reverse it.""" + p = get_patch(ver) + r = "" + if reverse: + r = " -R" + + qprint("Applying %s%s" % (os.path.basename(p), r)) + if options["dry-run"]: + return ver + + def cmd(patch, reverse, dry): + base = "patch -l -p1%s" % reverse + if dry: + base += " --dry-run" + + if p[-4:] == ".bz2": + pipe = "bzcat %s | %s" % (patch, base) + elif p[-3:] == ".gz": + pipe = "zcat %s | %s" % (patch, base) + else: + pipe = "%s < %s" % (base, patch) + + err = os.system(pipe + " > .patchdiag") + if err: + sys.stderr.write(open(".patchdiag").read()) + os.unlink(".patchdiag") + return err + + err = cmd(p, r, 1) + if err: + error("patch %s failed: %d" % (p, err)) + sys.exit(-1) + + err = cmd(p, r, 0) + if err: + error("patch %s failed while it was supposed to apply: %d" % (p, err)) + sys.exit(-1) + +def untar(tarfile): + old = os.getcwd() + os.mkdir("ketchup-tmp") + os.chdir("ketchup-tmp") + + err = os.system("bzcat %s | tar -xf -" % tarfile) + if err: + error("Unpacking failed: ", err) + sys.exit(-1) + + err = os.system("mv linux*/* linux*/.[^.]* ..; rmdir linux*") + if err: + error("Unpacking failed: ", err) + sys.exit(-1) + + os.chdir(old) + shutil.rmtree("ketchup-tmp") + +def install_nearest(ver): + t = tree(ver) + tarballs = glob.glob(archive + "/linux-%s.*.tar.bz2" % t) + list = [] + + for f in tarballs: + m = re.match(r'.*/linux-(.*).tar.bz2$', f) + v = m.group(1) + d = abs(rev(v) - rev(ver)) + list.append((d, f, v)) + list.sort() + + if not list or (options["full-tarball"] and list[0][0]): + f = "linux-%s.tar.bz2" % ver + url = "%s/v%s/%s" % (kernel_url, t, f) + f = archive + "/" + f + + sign = find_info(ver)[3] + if sign == 1: sign = ".sign" + + f = trydownload([url], f, sign) + if not f: + error("Tarball download failed") + sys.exit(-1) + + else: + f = list[0][1] + ver = list[0][2] + + qprint("Unpacking %s" % os.path.basename(f)) + if options["dry-run"]: return ver + untar(f) + + return ver + +def find_ver(ver): + if ver in version_info.keys(): + v = version_info[ver] + d = v[1] + if type(d) is type([]): + d = d[0] + for n in range(5): + return v[0](os.path.dirname(d), v[2]) + error('retrying version lookup for %s' % ver) + else: + return ver + +def transform(a, b): + if a == b: + qprint("Nothing to do!") + return + if not a: + a = install_nearest(base(b)) + t = tree(a) + if t != tree(b): + error("Can't patch %s to %s" % (tree(a), tree(b))) + sys.exit(-1) + if fork(a): + apply_patch(a, 1) + a = prebase(a) + if prebase(a) != prebase(b): + if pre(a): + apply_patch(a, 1) + a = base(a) + + if post(a) and post(a) != post(b): + apply_patch(prebase(a), 1) + + ra, rb = rev(a), rev(b) + if ra > rb: + for r in range(ra, rb, -1): + apply_patch("%s.%s" % (t, r), -1) + if ra < rb: + for r in range(ra + 1, rb + 1): + apply_patch("%s.%s" % (t, r)) + a = revbase(b) + + if post(b) and post(a) != post(b): + apply_patch(prebase(b), 0) + a = base(b) + + if pre(b): + apply_patch(prebase(b)) + a = prebase(b) + + if fork(b): + a = apply_patch(b) + +def rename_dir(v): + """Rename the current directory to linux-v, where v is the function arg""" + if rename_with_localversion: + v += get_localversion() + cwd = os.getcwd() + basedir = os.path.dirname(cwd) + newdir = os.path.join(basedir, rename_prefix + v) + if newdir == cwd: + return + if os.access(newdir, os.F_OK): + error("Cannot rename directory, destination exists: %s", newdir); + return + os.rename(cwd, newdir) + qprint('Current directory renamed to %s' % newdir) + + +# latest lookup function, canonical urls, pattern for lookup function, +# signature flag, description +version_info = { + '2.4': (latest_dir, + kernel_url + "/v2.4" + "/patch-%(base)s.bz2", + r'patch-(.*?).bz2', + 1, "old stable kernel series"), + '2.4-pre': (latest_dir, + kernel_url + "/v2.4" + "/testing/patch-%(prebase)s.bz2", + r'patch-(.*?).bz2', + 1, "old stable kernel series prereleases"), + '2.6': (latest_dir, + kernel_url + "/v2.6" + "/patch-%(prebase)s.bz2", + r'patch-(.*?).bz2', + 1, "current stable kernel series"), + '2.6-rc': (latest_dir, + kernel_url + "/v2.6" + "/testing/patch-%(prebase)s.bz2", + r'patch-(.*?).bz2', + 1, "current stable kernel series prereleases"), + '2.6-pre': (latest_dir, + kernel_url + "/v2.6" + "/testing/patch-%(prebase)s.bz2", + r'patch-(.*?).bz2', + 1, "current stable kernel series prereleases"), + '2.6-git': (latest_dir, + [kernel_url + "/v2.6" + "/snapshots/patch-%(full)s.bz2", + kernel_url + "/v2.6" + "/snapshots/old/patch-%(full)s.bz2"], + r'patch-(.*?).bz2', + 1, "current stable kernel series snapshots"), + '2.6-bk': (latest_dir, + [kernel_url + "/v2.6" + "/snapshots/patch-%(full)s.bz2", + kernel_url + "/v2.6" + "/snapshots/old/patch-%(full)s.bz2"], + r'patch-(.*?).bz2', + 1, "old stable kernel series snapshots"), + '2.6-tip': (latest_26_tip, "", "", 1, + "current stable kernel series tip"), + '2.6-mm': (latest_mm, + kernel_url + "/people/akpm/patches/" + + "%(tree)s/%(prebase)s/%(full)s/%(full)s.bz2", "", + 1, "Andrew Morton's -mm development tree"), + '2.6-tiny': (latest_dir, + "http://www.selenic.com/tiny/%(full)s.patch.bz2", + r'(2.6.*?).patch.bz2', + 1, "Matt Mackall's -tiny tree for small systems"), + '2.6-mjb': (latest_mjb, + kernel_url + "/people/mbligh/%(prebase)s/patch-%(full)s.bz2", + r'patch-(2.6.*?).bz2', + 1, "Martin Bligh's random collection 'o crap"), + '2.6-rt': (latest_dir, + ["http://people.redhat.com/mingo/" + + "realtime-preempt/patch-%(full)s", + "http://people.redhat.com/mingo/" + + "realtime-preempt/older/patch-%(full)s"], + r'patch-(2.6.*?)', + 0, "Ingo Molnar's realtime-preempt kernel"), + '2.6-ck': (latest_ck, + ["http://ck.kolivas.org/patches/2.6/" + + "%(prebase)s/%(full)s/patch-%(full)s.bz2", + "http://ck.kolivas.org/patches/2.6/pre-releases/" + + "%(prebase)s/%(full)s/patch-%(full)s.bz2"], + "", ".sig", + "Con Kolivas' patches for system responsiveness (desktop)"), + '2.6-cks': (latest_dir, + "http://ck.kolivas.org/patches/cks/patch-%(full)s.bz2", + r'patch-(2.6.*?).bz2', ".sig", + "Con Kolivas' patches for system responsiveness (server)") + } + +# Override defaults with ~/.ketchuprc which is just a Python script +rcpath = os.path.expanduser('~/.ketchuprc') +if os.path.isfile(rcpath): + try: + execfile(rcpath) + except Exception, e: + sys.exit('Failed parsing %s\nError was: %s' % (rcpath, e)) + +# Add local trees +for k,v in local_trees.items(): + version_info[k] = v + +# Environment variables override defaults and ketchuprc +kernel_url = os.environ.get("KETCHUP_URL", kernel_url) +archive = os.environ.get("KETCHUP_ARCH", archive) + +# And finally command line overrides everything +if not os.path.exists(wget): wget = "" +if not os.path.exists(gpg): gpg = "" + +options = {} +opts = [ + ('a', 'archive', archive, 'cache directory'), + ('d', 'directory', '.', 'directory to update'), + ('f', 'full-tarball', None, 'if unpacking a tarball, download the latest'), + ('g', 'gpg-path', gpg, 'path for GnuPG'), + ('G', 'no-gpg', None, 'disable GPG signature verification'), + ('k', 'kernel-url', kernel_url, 'base url for kernel.org mirror'), + ('l', 'list-trees', None, 'list supported trees'), + ('m', 'show-makefile', None, 'output version in makefile <arg>'), + ('n', 'dry-run', None, 'don\'t download or apply patches'), + ('p', 'show-previous', None, 'output version previous to <arg>'), + ('q', 'quiet', None, 'reduce output'), + ('r', 'rename-directory', None, 'rename updated directory to %s<v>' + % rename_prefix), + ('s', 'show-latest', None, 'output the latest version of <arg>'), + ('u', 'show-url', None, 'output URL for <arg>'), + ('w', 'wget', wget, 'command to use for wget'), + ] + +args = fancyopts(sys.argv[1:], opts, options, + 'ketchup [options] [ver]') + +archive = options["archive"] +kernel_url = options["kernel-url"] +if options["no-gpg"]: options["gpg-path"] = '' + +# Process args + +if not os.path.exists(options["directory"]): + qprint("Creating target directory", options["directory"]) + os.mkdir(options["directory"]) +os.chdir(options["directory"]) + +if os.path.isfile(".ketchuprc"): + try: + execfile(".ketchuprc") + except Exception, e: + sys.exit('Failed parsing .ketchuprc\nError was: %s' % (e)) + +if options["list-trees"]: + l = version_info.keys() + l.sort() + for tree in l: + if version_info[tree][3] == 0: + lprint(tree, "(unsigned)") + else: + lprint(tree, "(signed)") + lprint(" " + version_info[tree][4]) + sys.exit(0) + +if options["show-makefile"] and len(args) < 2: + if not args: + lprint(get_ver("Makefile")) + else: + lprint(get_ver(args[0])) + sys.exit(0) + +if len(args) == 0 and default_tree: + qprint("Using default tree \"%s\"" % (default_tree)) + args.append(default_tree) + +if len(args) != 1: + error("No version given on command line and no default in configuration") + sys.exit(-1) + +if options["show-latest"]: + lprint(find_ver(args[0])) + sys.exit(0) + +if options["show-url"]: + lprint(version_urls(find_ver(args[0]))[0]) + sys.exit(0) + +if options["show-previous"]: + v = find_ver(args[0]) + p = prebase(v) + if p == v: p = base(v) + if p == v: + if rev(v) > 0: p = "%.1f.%s" % (tree(v), rev(v) -1) + else: p = "unknown" + lprint(p) + sys.exit(0) + +if not os.path.exists(options["archive"]): + qprint("Creating cache directory", options["archive"]) + os.mkdir(options["archive"]) + +if precommand and os.system(precommand): + sys.exit('Precommand "%s" failed!' % precommand) + +try: + a = get_ver('Makefile') +except: + a = None + +if not a and os.listdir("."): + error("Can't find kernel version for non-empty directory") + sys.exit(-1) + +b = find_ver(args[0]) +qprint("%s -> %s" % (a, b)) +transform(a, b) +if options["rename-directory"] and not options["dry-run"]: + rename_dir(b) + +if postcommand and os.system(postcommand): + sys.exit('Postcommand "%s" failed!' % postcommand) diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/mk.linux-2.6-mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildconfigs/mk.linux-2.6-mm Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,14 @@ +XEN_LINUX_SOURCE ?= tarball +LINUX_VER ?= 2.6-mm + +XEN_LINUX_TARBALL_KETCHUP := y + +IMAGE_TARGET ?= vmlinux bzImage + +XEN_LINUX_ALLOW_INTERFACE_MISMATCH := y + +XEN_LINUX_CONFIG_UPDATE := buildconfigs/enable-xen-config + +EXTRAVERSION ?= + +include buildconfigs/mk.linux-2.6-xen diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/mk.linux-2.6-paravirt --- a/buildconfigs/mk.linux-2.6-paravirt Mon Jul 09 09:22:58 2007 -0600 +++ b/buildconfigs/mk.linux-2.6-paravirt Tue Jul 10 08:39:26 2007 -0600 @@ -8,6 +8,8 @@ IMAGE_TARGET ?= vmlinux bzImage XEN_LINUX_ALLOW_INTERFACE_MISMATCH := y -EXTRAVERSION ?= +XEN_LINUX_CONFIG_UPDATE := buildconfigs/enable-xen-config + +EXTRAVERSION ?= -paravirt include buildconfigs/mk.linux-2.6-xen diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/mk.linux-2.6-rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildconfigs/mk.linux-2.6-rc Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,14 @@ +XEN_LINUX_SOURCE ?= tarball +LINUX_VER ?= 2.6-rc + +XEN_LINUX_TARBALL_KETCHUP := y + +IMAGE_TARGET ?= vmlinux bzImage + +XEN_LINUX_ALLOW_INTERFACE_MISMATCH := y + +XEN_LINUX_CONFIG_UPDATE := buildconfigs/enable-xen-config + +EXTRAVERSION ?= + +include buildconfigs/mk.linux-2.6-xen diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/mk.linux-2.6-tip --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildconfigs/mk.linux-2.6-tip Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,14 @@ +XEN_LINUX_SOURCE ?= tarball +LINUX_VER ?= 2.6-tip + +XEN_LINUX_TARBALL_KETCHUP := y + +IMAGE_TARGET ?= vmlinux bzImage + +XEN_LINUX_ALLOW_INTERFACE_MISMATCH := y + +XEN_LINUX_CONFIG_UPDATE := buildconfigs/enable-xen-config + +EXTRAVERSION ?= + +include buildconfigs/mk.linux-2.6-xen diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/mk.linux-2.6-xen --- a/buildconfigs/mk.linux-2.6-xen Mon Jul 09 09:22:58 2007 -0600 +++ b/buildconfigs/mk.linux-2.6-xen Tue Jul 10 08:39:26 2007 -0600 @@ -74,6 +74,10 @@ endif else \ echo "No configuration method found for this kernel" ; \ fi +ifneq ($(XEN_LINUX_CONFIG_UPDATE),) + echo "Updating $(CONFIG_FILE) using $(XEN_LINUX_CONFIG_UPDATE)" + sh $(XEN_LINUX_CONFIG_UPDATE) $(CONFIG_FILE) +endif ifeq ($(XEN_TARGET_ARCH),x86_32) ifeq ($(pae),y) sed -e 's!^CONFIG_HIGHMEM4G=y$$!\# CONFIG_HIGHMEM4G is not set!;s!^\# CONFIG_HIGHMEM64G is not set$$!CONFIG_HIGHMEM64G=y!' $(CONFIG_FILE) > $(CONFIG_FILE)- && mv $(CONFIG_FILE)- $(CONFIG_FILE) diff -r 87b0b6a08dbd -r 42586a0f4407 buildconfigs/src.tarball --- a/buildconfigs/src.tarball Mon Jul 09 09:22:58 2007 -0600 +++ b/buildconfigs/src.tarball Tue Jul 10 08:39:26 2007 -0600 @@ -1,7 +1,12 @@ XEN_LINUX_MIRROR ?= http://www.kernel.or XEN_LINUX_MIRROR ?= http://www.kernel.org/pub/linux/kernel/v2.6/ XEN_LINUX_TARBALL ?= linux-$(LINUX_VER)-xen.tar.bz2 +# Update using ketchup instead of manipulating tarball manually. +XEN_LINUX_TARBALL_KETCHUP ?= n + LINUX_SRCDIR ?= linux-$(LINUX_VER) + +KETCHUP ?= python buildconfigs/ketchup vpath linux-%.tar.bz2 $(LINUX_SRC_PATH) @@ -12,6 +17,11 @@ linux-%.tar.bz2: # XXX create a pristine tree for diff -Nurp convenience +ifeq ($(XEN_LINUX_TARBALL_KETCHUP),y) +%/.valid-src: + $(KETCHUP) -d $(@D) $(LINUX_VER) + touch $@ # update timestamp to avoid rebuild +else %/.valid-src: %.tar.bz2 rm -rf tmp-linux-$* $(@D) mkdir -p tmp-linux-$* @@ -19,5 +29,5 @@ linux-%.tar.bz2: -@rm -f tmp-linux-$*/pax_global_header mv tmp-linux-$*/* $(@D) @rm -rf tmp-linux-$* - touch $(@D)/.hgskip touch $@ # update timestamp to avoid rebuild +endif diff -r 87b0b6a08dbd -r 42586a0f4407 docs/man/xm.pod.1 --- a/docs/man/xm.pod.1 Mon Jul 09 09:22:58 2007 -0600 +++ b/docs/man/xm.pod.1 Tue Jul 10 08:39:26 2007 -0600 @@ -4,7 +4,7 @@ xm - Xen management user interface =head1 SYNOPSIS -xm <subcommand> [args] +B<xm> I<subcommand> [I<args>] =head1 DESCRIPTION @@ -13,46 +13,50 @@ domains. It can also be used to list cur domains. It can also be used to list current domains, enable or pin VCPUs, and attach or detach virtual block devices. -The basic structure of every xm command is almost always: - - xm <subcommand> <domain-id> [OPTIONS] - -Where I<subcommand> is one of the sub commands listed below, I<domain-id> +The basic structure of every B<xm> command is almost always: + +=over 2 + +B<xm> I<subcommand> I<domain-id> [I<OPTIONS>] + +=back + +Where I<subcommand> is one of the subcommands listed below, I<domain-id> is the numeric domain id, or the domain name (which will be internally -translated to domain id), and I<OPTIONS> are sub command specific +translated to domain id), and I<OPTIONS> are subcommand specific options. There are a few exceptions to this rule in the cases where -the sub command in question acts on all domains, the entire machine, -or directly on the xen hypervisor. Those exceptions will be clear for -each of those sub commands. +the subcommand in question acts on all domains, the entire machine, +or directly on the Xen hypervisor. Those exceptions will be clear for +each of those subcommands. =head1 NOTES All B<xm> operations rely upon the Xen control daemon, aka B<xend>. -For any xm commands to run xend must also be running. For this reason -you should start xend as a service when your system first boots using -xen. +For any B<xm> commands to run, xend must also be running. For this +reason you should start xend as a service when your system first boots +using Xen. Most B<xm> commands require root privileges to run due to the communications channels used to talk to the hypervisor. Running as non root will return an error. Most B<xm> commands act asynchronously, so just because the B<xm> -command returned, doesn't mean the action is complete. This is +command returned doesn't mean the action is complete. This is important, as many operations on domains, like create and shutdown, can take considerable time (30 seconds or more) to bring the machine into a fully compliant state. If you want to know when one of these -actions has finished you must poll through xm list periodically. +actions has finished you must poll through B<xm list> periodically. =head1 DOMAIN SUBCOMMANDS -The following sub commands manipulate domains directly, as stated -previously most commands take domain-id as the first parameter. +The following subcommands manipulate domains directly. As stated +previously, most commands take I<domain-id> as the first parameter. =over 4 =item B<console> I<domain-id> -Attach to domain domain-id's console. If you've set up your Domains to +Attach to domain I<domain-id>'s console. If you've set up your domains to have a traditional log in console this will look much like a normal text log in screen. @@ -63,15 +67,15 @@ so running curses based interfaces over so running curses based interfaces over the console B<is not advised>. Vi tends to get very odd when using it over this interface. -=item B<create> I<[-c]> I<configfile> I<[name=value]>.. - -The create sub command requires a configfile and can optional take a +=item B<create> [B<-c>] I<configfile> [I<name>=I<value>].. + +The create sub command requires a config file and can optionally take a series of name value pairs that add to or override variables defined in the config file. See L<xmdomain.cfg> for full details of that file format, and possible options used in either the configfile or -Name=Value combinations. - -Configfile can either be an absolute path to a file, or a relative +I<name>=I<value> combinations. + +I<configfile> can either be an absolute path to a file, or a relative path to a file located in /etc/xen. Create will return B<as soon> as the domain is started. This B<does @@ -116,10 +120,10 @@ virtual networking. (This example comes =item B<destroy> I<domain-id> -Immediately terminate the domain domain-id. This doesn't give the domain -OS any chance to react, and it the equivalent of ripping the power -cord out on a physical machine. In most cases you will want to use -the B<shutdown> command instead. +Immediately terminate the domain I<domain-id>. This doesn't give the +domain OS any chance to react, and is the equivalent of ripping the +power cord out on a physical machine. In most cases you will want to +use the B<shutdown> command instead. =item B<domid> I<domain-name> @@ -129,14 +133,14 @@ Converts a domain name to a domain id us Converts a domain id to a domain name using xend's internal mapping. -=item B<help> I<[--long]> +=item B<help> [B<--long>] Displays the short help message (i.e. common commands). -The I<--long> option prints out the complete set of B<xm> subcommands, +The B<--long> option prints out the complete set of B<xm> subcommands, grouped by function. -=item B<list> I<[--long | --label]> I<[domain-id, ...]> +=item B<list> [B<--long> | B<--label>] [I<domain-id> ...] Prints information about one or more domains. If no domains are specified it prints out information about all domains. @@ -151,21 +155,23 @@ An example format for the list is as fol Mandrake10.2 167 128 1 ------ 2.5 Suse9.2 168 100 1 ------ 1.8 -Name is the name of the domain. ID the domain numeric id. Mem is the -size of the memory allocated to the domain. VCPUS is the number of -VCPUS allocated to domain. State is the run state (see below). Time -is the total run time of the domain as accounted for by Xen. +Name is the name of the domain. ID the numeric domain id. Mem is the +desired amount of memory to allocate to the domain (although it may +not be the currently allocated amount). VCPUs is the number of +virtual CPUs allocated to the domain. State is the run state (see +below). Time is the total run time of the domain as accounted for by +Xen. B<STATES> =over 4 -The State field lists 6 states for a Xen Domain, and which ones the -current Domain is in. +The State field lists 6 states for a Xen domain, and which ones the +current domain is in. =item B<r - running> -The domain is currently running on a CPU +The domain is currently running on a CPU. =item B<b - blocked> @@ -203,12 +209,12 @@ B<LONG OUTPUT> =over 4 -If I<--long> is specified, the output for xm list is not the table +If B<--long> is specified, the output for B<xm list> is not the table view shown above, but instead is an S-Expression representing all information known about all domains asked for. This is mostly only useful for external programs to parse the data. -B<Note:> there is no stable guarantees on the format of this data. +B<Note:> There is no stable guarantees on the format of this data. Use at your own risk. =back @@ -217,10 +223,10 @@ B<LABEL OUTPUT> =over 4 -If I<--label> is specified, the security labels are added to the -output of xm list and the lines are sorted by the labels (ignoring -case). The I<--long> option prints the labels by default and cannot be -combined with I<--label>. See the ACCESS CONTROL SUBCOMMAND section of +If B<--label> is specified, the security labels are added to the +output of B<xm list> and the lines are sorted by the labels (ignoring +case). The B<--long> option prints the labels by default and cannot be +combined with B<--label>. See the ACCESS CONTROL SUBCOMMAND section of this man page for more information about labels. ==back @@ -230,7 +236,7 @@ B<NOTES> =over 4 The Time column is deceptive. Virtual IO (network and block devices) -used by Domains requires coordination by Domain0, which means that +used by domains requires coordination by Domain0, which means that Domain0 is actually charged for much of the time that a DomainU is doing IO. Use of this time value to determine relative utilizations by domains is thus very suspect, as a high IO workload may show as @@ -240,11 +246,11 @@ less utilized than a high CPU workload. =item B<mem-max> I<domain-id> I<mem> -Specify the maximum amount of memory the Domain is able to use. Mem +Specify the maximum amount of memory the domain is able to use. I<mem> is specified in megabytes. The mem-max value may not correspond to the actual memory used in the -Domain, as it may balloon down it's memory to give more back to the OS. +domain, as it may balloon down its memory to give more back to the OS. =item B<mem-set> I<domain-id> I<mem> @@ -252,20 +258,20 @@ operation requires cooperation from the operation requires cooperation from the domain operating system, there is no guarantee that it will succeed. -B<Warning:> there is no good way to know in advance how small of a +B<Warning:> There is no good way to know in advance how small of a mem-set will make a domain unstable and cause it to crash. Be very careful when using this command on running domains. -=item B<migrate> I<domain-id> I<host> I<[options]> - -Migrate a domain to another Host machine. B<Xend> must be running on -other host machine, it must be running the same version of xen, it +=item B<migrate> I<domain-id> I<host> [I<OPTIONS>] + +Migrate a domain to another host machine. Xend must be running on +other host machine, it must be running the same version of Xen, it must have the migration TCP port open and accepting connections from the source host, and there must be sufficient resources for the domain to run (memory, disk, etc). -Migration is pretty complicated, and has many security implications, -please read the Xen Users Guide to ensure you understand the +Migration is pretty complicated, and has many security implications. +Please read the Xen User's Guide to ensure you understand the ramifications and limitations on migration before attempting it in production. @@ -273,13 +279,13 @@ B<OPTIONS> =over 4 -=item B<-l, --live> +=item B<-l>, B<--live> Use live migration. This will migrate the domain between hosts -without shutting down the domain. See the Xen Users Guide for more +without shutting down the domain. See the Xen User's Guide for more information. -=item B<-r, --resource> I<Mbs> +=item B<-r>, B<--resource> I<Mbs> Set maximum Mbs allowed for migrating the domain. This ensures that the network link is not saturated with migration traffic while @@ -293,7 +299,7 @@ allocated resources such as memory, but allocated resources such as memory, but will not be eligible for scheduling by the Xen hypervisor. -=item B<reboot> I<[options]> I<domain-id> +=item B<reboot> [I<OPTIONS>] I<domain-id> Reboot a domain. This acts just as if the domain had the B<reboot> command run from the console. The command returns as soon as it has @@ -301,18 +307,18 @@ domain actually reboots. domain actually reboots. The behavior of what happens to a domain when it reboots is set by the -I<on_reboot> parameter of the xmdomain.cfg file when the domain was +B<on_reboot> parameter of the xmdomain.cfg file when the domain was created. B<OPTIONS> =over 4 -=item B<-a, --all> - -Reboot all domains - -=item B<-w, --wait> +=item B<-a>, B<--all> + +Reboot all domains. + +=item B<-w>, B<--wait> Wait for reboot to complete before returning. This may take a while, as all services in the domain will have to be shut down cleanly. @@ -321,7 +327,7 @@ as all services in the domain will have =item B<restore> I<state-file> -Build a domain from an B<xm save> state file. See I<save> for more info. +Build a domain from an B<xm save> state file. See B<save> for more info. =item B<save> I<domain-id> I<state-file> @@ -334,16 +340,16 @@ with all the same limitations. Open net with all the same limitations. Open network connections may be severed upon restore, as TCP timeouts may have expired. -=item B<shutdown> I<[options]> I<domain-id> +=item B<shutdown> [I<OPTIONS>] I<domain-id> Gracefully shuts down a domain. This coordinates with the domain OS to perform graceful shutdown, so there is no guarantee that it will succeed, and may take a variable length of time depending on what services must be shutdown in the domain. The command returns -immediately after signally the domain unless that I<-w> flag is used. +immediately after signally the domain unless that B<-w> flag is used. The behavior of what happens to a domain when it reboots is set by the -I<on_shutdown> parameter of the xmdomain.cfg file when the domain was +B<on_shutdown> parameter of the xmdomain.cfg file when the domain was created. B<OPTIONS> @@ -386,7 +392,7 @@ configured VCPU count is an error. Tryi configured VCPU count is an error. Trying to set VCPUs to < 1 will be quietly ignored. -=item B<vcpu-list> I<[domain-id]> +=item B<vcpu-list> [I<domain-id>] Lists VCPU information for a specific domain. If no domain is specified, VCPU information for all domains will be provided. @@ -394,7 +400,7 @@ specified, VCPU information for all doma =item B<vcpu-pin> I<domain-id> I<vcpu> I<cpus> Pins the the VCPU to only run on the specific CPUs. The keyword -I<all> can be used to apply the I<cpus> list to all VCPUs in the +B<all> can be used to apply the I<cpus> list to all VCPUs in the domain. Normally VCPUs can float between available CPUs whenever Xen deems a @@ -408,7 +414,7 @@ CPUs. =over 4 -=item B<dmesg> I<[-c]> +=item B<dmesg> [B<-c>] Reads the Xen message buffer, similar to dmesg on a Linux system. The buffer contains informational, warning, and error messages created @@ -419,7 +425,7 @@ B<OPTIONS> =over 4 -=item B<-c, --clear> +=item B<-c>, B<--clear> Clears Xen's message buffer. @@ -431,8 +437,8 @@ reporting a Xen bug, please provide this reporting a Xen bug, please provide this information as part of the bug report. -Sample xen domain info looks as follows (lines wrapped manually to -make the man page more readable): +Sample output looks as follows (lines wrapped manually to make the man +page more readable): host : talon release : 2.6.12.6-xen0 @@ -470,36 +476,36 @@ Not all fields will be explained here, b Not all fields will be explained here, but some of the less obvious ones deserve explanation: -=item I<hw_caps> +=item B<hw_caps> A vector showing what hardware capabilities are supported by your processor. This is equivalent to, though more cryptic, the flags field in /proc/cpuinfo on a normal Linux machine. -=item I<free_memory> - -Available memory (in MB) not allocated to Xen, or any other Domains. - -=item I<xen_caps> - -The xen version, architecture. Architecture values can be one of: +=item B<free_memory> + +Available memory (in MB) not allocated to Xen, or any other domains. + +=item B<xen_caps> + +The Xen version and architecture. Architecture values can be one of: x86_32, x86_32p (i.e. PAE enabled), x86_64, ia64. -=item I<xen_changeset> - -The xen mercurial changeset id. Very useful for determining exactly +=item B<xen_changeset> + +The Xen mercurial changeset id. Very useful for determining exactly what version of code your Xen system was built from. =back =item B<log> -Print out the B<xend> log. This log file can be found in +Print out the xend log. This log file can be found in /var/log/xend.log. =item B<top> -Executes the xentop command, which provides real time monitoring of +Executes the B<xentop> command, which provides real time monitoring of domains. Xentop is a curses interface, and reasonably self explanatory. @@ -508,12 +514,40 @@ explanatory. =head1 SCHEDULER SUBCOMMANDS Xen ships with a number of domain schedulers, which can be set at boot -time with the I<sched=> parameter on the Xen command line. By -default I<sedf> is used for scheduling. +time with the B<sched=> parameter on the Xen command line. By +default B<credit> is used for scheduling. FIXME: we really need a scheduler expert to write up this section. =over 4 + +=item B<sched-credit> [ B<-d> I<domain-id> [ B<-w>[B<=>I<WEIGHT>] | B<-c>[B<=>I<CAP>] ] ] + +Set credit scheduler parameters. The credit scheduler is a +proportional fair share CPU scheduler built from the ground up to be +work conserving on SMP hosts. + +Each domain (including Domain0) is assigned a weight and a cap. + +B<PARAMETERS> + +=over 4 + +=item I<WEIGHT> + +A domain with a weight of 512 will get twice as much CPU as a domain +with a weight of 256 on a contended host. Legal weights range from 1 +to 65535 and the default is 256. + +=item I<CAP> + +The cap optionally fixes the maximum amount of CPU a domain will be +able to consume, even if the host system has idle CPU cycles. The cap +is expressed in percentage of one physical CPU: 100 is 1 physical CPU, +50 is half a CPU, 400 is 4 CPUs, etc. The default, 0, means there is +no upper cap. + +=back =item B<sched-sedf> I<period> I<slice> I<latency-hint> I<extratime> I<weight> @@ -546,7 +580,7 @@ Flag for allowing domain to run in extra =item I<weight> -Another way of setting cpu slice. +Another way of setting CPU slice. =back @@ -591,7 +625,7 @@ event. =over 4 -=item B<block-attach> I<domain-id> I<be-dev> I<fe-dev> I<mode> I<[bedomain-id]> +=item B<block-attach> I<domain-id> I<be-dev> I<fe-dev> I<mode> [I<bedomain-id>] Create a new virtual block device. This will trigger a hotplug event for the guest. @@ -619,7 +653,7 @@ devices, or by device id, such as 0x1400 =item I<mode> The access mode for the device from the guest domain. Supported modes -are I<w> (read/write) or I<r> (read-only). +are B<w> (read/write) or B<r> (read-only). =item I<bedomain-id> @@ -635,62 +669,65 @@ B<EXAMPLES> xm block-attach guestdomain file://path/to/dsl-2.0RC2.iso /dev/hdc ro -This will mount the dsl iso as /dev/hdc in the guestdomain as a read -only device. This will probably not be detected as a cdrom by the +This will mount the dsl ISO as /dev/hdc in the guestdomain as a read +only device. This will probably not be detected as a CD-ROM by the guest, but mounting /dev/hdc manually will work. =back -=item B<block-detach> I<domain-id> I<devid> - -Destroy a domain's virtual block device. devid B<must> be the device -id given to the device by domain 0. You will need to run I<xm -block-list> to determine that number. - -FIXME: this is currently B<broken>. Even though a block device is -removed from domU, it appears to still be allocated in the domain 0. - -=item B<block-list> I<[-l|--long]> I<domain-id> +=item B<block-detach> I<domain-id> I<devid> [B<--force>] + +Detach a domain's virtual block device. I<devid> may be the symbolic +name or the numeric device id given to the device by domain 0. You +will need to run B<xm block-list> to determine that number. + +Detaching the device requires the cooperation of the domain. If the +domain fails to release the device (perhaps because the domain is hung +or is still using the device), the detach will fail. The B<--force> +parameter will forcefully detach the device, but may cause IO errors +in the domain. + +=item B<block-list> [B<-l>|B<--long>] I<domain-id> List virtual block devices for a domain. The returned output is -formatted as a list or as an S-Expression if the '--long' option was given. +formatted as a list or as an S-Expression if the B<--long> option was given. =head2 NETWORK DEVICES -=item B<network-attach> I<domain-id> I<[script=scriptname]> I<[ip=ipaddr]> -I<[mac=macaddr]> I<[bridge=bridge-name]> I<[backend=bedomain-id]> - -Creates a new network device in the domain specified by domain-id. It +=item B<network-attach> I<domain-id> [B<script=>I<scriptname>] [B<ip=>I<ipaddr>] +[B<mac=>I<macaddr>] [B<bridge=>I<bridge-name>] [B<backend=>I<bedomain-id>] + +Creates a new network device in the domain specified by I<domain-id>. It takes the following optional options: B<OPTIONS> =over 4 -=item I<script=scriptname> +=item B<script=>I<scriptname> Use the specified script name to bring up the network. Defaults to -the default setting in xend-config.sxp for I<vif-script>. - -=item I<ip=ipaddr> +the default setting in xend-config.sxp for B<vif-script>. + +=item B<ip=>I<ipaddr> Passes the specified IP Address to the adapter on creation. FIXME: this currently appears to be B<broken>. I'm not sure under what circumstances this should actually work. -=item I<mac=macaddr> +=item B<mac=>I<macaddr> The MAC address that the domain will see on its Ethernet device. If the device is not specified it will be randomly generated with the 00:16:3e vendor id prefix. -=item I<bridge=bridge-name> +=item B<bridge=>I<bridge-name> The name of the bridge to attach the vif to, in case you have more -than one. This defaults to - -=item I<backend=bedomain-id> +than one. This defaults to xenbr0. + +=item B<backend=>I<bedomain-id> The backend domain id. By default this is domain 0. @@ -705,17 +742,17 @@ FIXME: this is currently B<broken>. Net FIXME: this is currently B<broken>. Network devices aren't completely removed from domain 0. -=item B<network-list> I<[-l|--long]> I<domain-id> +=item B<network-list> [B<-l>|B<--long>]> I<domain-id> List virtual network interfaces for a domain. The returned output is -formatted as a list or as an S-Expression if the '--long' option was given. +formatted as a list or as an S-Expression if the B<--long> option was given. =head2 VIRTUAL TPM DEVICES -=item B<vtpm-list> I<[-l|--long]> I<domain-id> +=item B<vtpm-list> [B<-l>|B<--long>] I<domain-id> Show the virtual TPM device for a domain. The returned output is -formatted as a list or as an S-Expression if the '--long' option was given. +formatted as a list or as an S-Expression if the B<--long> option was given. =back @@ -728,7 +765,7 @@ out entirely. =over 4 -=item B<vnet-list> I<[-l|--long]> +=item B<vnet-list> [B<-l>|B<--long>] List vnets. @@ -762,7 +799,7 @@ interpret labels: interpret labels: (1) Simple Type Enforcement: Labels are interpreted to decide access -of domains to comunication means and virtual or physical +of domains to communication means and virtual or physical resources. Communication between domains as well as access to resources are forbidden by default and can only take place if they are explicitly allowed by the security policy. The proper assignment of @@ -796,8 +833,8 @@ time with the B<cfgbootpolicy> subcomman =over 4 I<policy> is a dot-separated list of names. The last part is the file -name pre-fix for the policy xml file. The preceding name parts are -translated into the local path pointing to the policy xml file +name pre-fix for the policy XML file. The preceding name parts are +translated into the local path pointing to the policy XML file relative to the global policy root directory (/etc/xen/acm-security/policies). For example, example.chwall_ste.client_v1 denotes the policy file @@ -823,16 +860,16 @@ I<boot title> parameter to specify a uni Prints the current security policy state information of Xen. -=item B<labels> [I<policy>] [I<type>=dom|res|any] +=item B<labels> [I<policy>] [B<type=dom>|B<res>|B<any>] Lists all labels of a I<type> (domain, resource, or both) that are defined in the I<policy>. Unless specified, the default I<policy> is the currently enforced access control policy. The default for I<type> is 'dom'. The labels are arranged in alphabetical order. -=item B<addlabel> I<label> dom I<configfile> [I<policy>] - -=item B<addlabel> I<label> res I<resource> [I<policy>] +=item B<addlabel> I<label> B<dom> I<configfile> [I<policy>] + +=item B<addlabel> I<label> B<res> I<resource> [I<policy>] Adds the security label with name I<label> to a domain I<configfile> (dom) or to the global resource label file for the @@ -841,17 +878,17 @@ verifies that the I<policy> definition s verifies that the I<policy> definition supports the specified I<label> name. -=item B<rmlabel> dom I<configfile> - -=item B<rmlabel> res I<resource> - -Works the same as the I<addlabel> command (above), except that this +=item B<rmlabel> B<dom> I<configfile> + +=item B<rmlabel> B<res> I<resource> + +Works the same as the B<addlabel> command (above), except that this command will remove the label from the domain I<configfile> (dom) or the global resource label file (res). -=item B<getlabel> dom I<configfile> - -=item B<getlabel> res I<resource> +=item B<getlabel> B<dom> I<configfile> + +=item B<getlabel> B<res> I<resource> Shows the label for the given I<configfile> or I<resource> @@ -881,7 +918,7 @@ Then recompile and install xen and the s cd xen_source_dir/xen; make clean; make; cp xen.gz /boot; cd xen_source_dir/tools/security; make install; - reboot into xen + reboot into Xen =back @@ -944,10 +981,10 @@ B<ATTACHING A SECURITY LABEL TO A DOMAIN =over 4 -The I<addlabel> subcommand can attach a security label to a domain +The B<addlabel> subcommand can attach a security label to a domain configuration file, here a HomeBanking label. The example policy ensures that this domain does not share information with other -non-hombanking user domains (i.e., domains labeled as dom_Fun or +non-homebanking user domains (i.e., domains labeled as dom_Fun or dom_Boinc) and that it will not run simultaneously with domains labeled as dom_Fun. @@ -958,7 +995,7 @@ probably just a browser environment for xm addlabel dom_HomeBanking dom myconfig.xm The very simple configuration file might now look as printed -below. The I<addlabel> subcommand added the B<access_control> entry at +below. The B<addlabel> subcommand added the B<access_control> entry at the end of the file, consisting of a label name and the policy that specifies this label name: @@ -986,7 +1023,7 @@ B<ATTACHING A SECURITY LABEL TO A RESOUR =over 4 -The I<addlabel> subcommand can also be used to attach a security +The B<addlabel> subcommand can also be used to attach a security label to a resource. Following the home banking example from above, we can label a disk resource (e.g., a physical partition or a file) to make it accessible to the home banking domain. The example policy @@ -1002,7 +1039,7 @@ attaches this disk to the domain at boot disk = [ 'phy:hda6,sda2,w' ] Alternatively, the resource can be attached after booting the domain -by using the I<block-attach> subcommand. +by using the B<block-attach> subcommand. xm block-attach homebanking phy:hda6 sda2 w @@ -1010,7 +1047,7 @@ off. Any attempt to use labeled resourc off. Any attempt to use labeled resources with security turned off will result in a failure with a corresponding error message. The solution is to enable security or, if security is no longer desired, -to remove the resource label using the I<rmlabel> subcommand. +to remove the resource label using the B<rmlabel> subcommand. =back @@ -1048,7 +1085,7 @@ B<POLICY REPRESENTATIONS> =over 4 We distinguish three representations of the Xen access control policy: -the I<source XML> version, its I<binary> counterpart, and a I<mapping> +the source XML version, its binary counterpart, and a mapping representation that enables the tools to deterministically translate back and forth between label names of the XML policy and label identifiers of the binary policy. All three versions must be kept @@ -1075,8 +1112,6 @@ their binary identifiers (ssidrefs) used =back -=head1 EXAMPLES - =head1 SEE ALSO B<xmdomain.cfg>(5), B<xentop>(1) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/blktap/drivers/Makefile --- a/tools/blktap/drivers/Makefile Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/blktap/drivers/Makefile Tue Jul 10 08:39:26 2007 -0600 @@ -10,7 +10,6 @@ LIBAIO_DIR = ../../libaio/src CFLAGS += -Werror CFLAGS += -Wno-unused -CFLAGS += -fno-strict-aliasing CFLAGS += -I $(XEN_LIBXC) -I $(LIBAIO_DIR) CFLAGS += $(INCLUDES) -I. -I../../xenstore CFLAGS += -D_GNU_SOURCE diff -r 87b0b6a08dbd -r 42586a0f4407 tools/blktap/lib/Makefile --- a/tools/blktap/lib/Makefile Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/blktap/lib/Makefile Tue Jul 10 08:39:26 2007 -0600 @@ -16,7 +16,7 @@ SRCS += xenbus.c blkif.c xs_api.c CFLAGS += -Werror CFLAGS += -Wno-unused -CFLAGS += -fno-strict-aliasing -fPIC +CFLAGS += -fPIC # get asprintf(): CFLAGS += -D _GNU_SOURCE diff -r 87b0b6a08dbd -r 42586a0f4407 tools/examples/init.d/xendomains --- a/tools/examples/init.d/xendomains Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/examples/init.d/xendomains Tue Jul 10 08:39:26 2007 -0600 @@ -221,22 +221,26 @@ start() if [ "$XENDOMAINS_RESTORE" = "true" ] && contains_something "$XENDOMAINS_SAVE" then - XENDOMAINS_SAVED=`/bin/ls $XENDOMAINS_SAVE/* | grep -v 'lost+found'` mkdir -p $(dirname "$LOCKFILE") touch $LOCKFILE echo -n "Restoring Xen domains:" saved_domains=`ls $XENDOMAINS_SAVE` - for dom in $XENDOMAINS_SAVED; do - echo -n " ${dom##*/}" - xm restore $dom - if [ $? -ne 0 ]; then - rc_failed $? - echo -n '!' - else - # mv $dom ${dom%/*}/.${dom##*/} - rm $dom - fi - done + for dom in $XENDOMAINS_SAVE/*; do + if [ -f $dom ] ; then + HEADER=`head -c 16 $dom | head -n 1 2> /dev/null` + if [ $HEADER = "LinuxGuestRecord" ]; then + echo -n " ${dom##*/}" + xm restore $dom + if [ $? -ne 0 ]; then + rc_failed $? + echo -n '!' + else + # mv $dom ${dom%/*}/.${dom##*/} + rm $dom + fi + fi + fi + done echo . fi @@ -260,7 +264,6 @@ start() if [ $? -eq 0 ] || is_running $dom; then echo -n "(skip)" else - echo "(booting)" xm create --quiet --defconfig $dom if [ $? -ne 0 ]; then rc_failed $? diff -r 87b0b6a08dbd -r 42586a0f4407 tools/examples/xend-config.sxp --- a/tools/examples/xend-config.sxp Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/examples/xend-config.sxp Tue Jul 10 08:39:26 2007 -0600 @@ -191,3 +191,9 @@ # The default password for VNC console on HVM domain. # Empty string is no authentication. (vncpasswd '') + +# The default keymap to use for the VM's virtual keyboard +# when not specififed in VM's configuration +#(keymap 'en-us') + + diff -r 87b0b6a08dbd -r 42586a0f4407 tools/firmware/etherboot/README --- a/tools/firmware/etherboot/README Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/firmware/etherboot/README Tue Jul 10 08:39:26 2007 -0600 @@ -1,7 +1,8 @@ This is an Etherboot option ROM for the rtl8139 NIC. It has a few -non-standard settings, just to do with timeouts and when to give up. +non-standard settings, most to do with timeouts and when to give up, +and for stricter DHCP spec compliance. Rom-o-matic.net will provide this image at the following URL: -http://rom-o-matic.net/5.4.2/build.php?version=5.4.2&F=ignore&nic=rtl8139%3Artl8139+--+%5B0x10ec%2C0x8139%5D&ofmt=Binary+ROM+Image%28.zrom%29&arch=i386&ASK_BOOT=-1&BOOT_FIRST=BOOT_NIC&BOOT_SECOND=BOOT_NOTHING&BOOT_THIRD=BOOT_NOTHING&BOOT_INDEX=0&STATIC_CLIENT_IP=&STATIC_SUBNET_MASK=&STATIC_SERVER_IP=&STATIC_GATEWAY_IP=&STATIC_BOOTFILE=&EXIT_ON_FILE_LOAD_ERROR=on&DHCP_CLIENT_ID=&DHCP_CLIENT_ID_LEN=&DHCP_CLIENT_ID_TYPE=&DHCP_USER_CLASS=&DHCP_USER_CLASS_LEN=&ALLOW_ONLY_ENCAPSULATED=on&DEFAULT_BOOTFILE=&CONGESTED=on&BACKOFF_LIMIT=7&TIMEOUT=180&TRY_FLOPPY_FIRST=0&EXIT_IF_NO_OFFER=on&TAGGED_IMAGE=on&ELF_IMAGE=on&PXE_IMAGE=on&DOWNLOAD_PROTO_TFTP=on&COMCONSOLE=0x3F8&CONSPEED=9600&COMPARM=0x03&PXE_EXPORT=on&CONFIG_PCI=on&CONFIG_ISA=on&BUILD_ID=&PCBIOS=on&A=Get+ROM +http://rom-o-matic.net/5.4.3/build.php?version=5.4.3&F=ignore&nic=rtl8139%3Artl8139+--+%5B0x10ec%2C0x8139%5D&ofmt=Binary+ROM+Image%28.zrom%29&arch=i386&ASK_BOOT=-1&BOOT_FIRST=BOOT_NIC&BOOT_SECOND=BOOT_NOTHING&BOOT_THIRD=BOOT_NOTHING&BOOT_INDEX=0&STATIC_CLIENT_IP=&STATIC_SUBNET_MASK=&STATIC_SERVER_IP=&STATIC_GATEWAY_IP=&STATIC_BOOTFILE=&EXIT_ON_FILE_LOAD_ERROR=on&DHCP_CLIENT_ID=&DHCP_CLIENT_ID_LEN=&DHCP_CLIENT_ID_TYPE=&DHCP_USER_CLASS=&DHCP_USER_CLASS_LEN=&ALLOW_ONLY_ENCAPSULATED=on&DEFAULT_BOOTFILE=&CONGESTED=on&BACKOFF_LIMIT=7&TIMEOUT=180&TRY_FLOPPY_FIRST=0&EXIT_IF_NO_OFFER=on&TAGGED_IMAGE=on&ELF_IMAGE=on&PXE_IMAGE=on&DOWNLOAD_PROTO_TFTP=on&COMCONSOLE=0x3F8&CONSPEED=9600&COMPARM=0x03&PXE_EXPORT=on&CONFIG_PCI=on&CONFIG_ISA=on&BUILD_ID=&PCBIOS=on&PXE_DHCP_STRICT=on&A=Get+ROM diff -r 87b0b6a08dbd -r 42586a0f4407 tools/firmware/etherboot/eb-rtl8139.zrom Binary file tools/firmware/etherboot/eb-rtl8139.zrom has changed diff -r 87b0b6a08dbd -r 42586a0f4407 tools/firmware/rombios/rombios.c --- a/tools/firmware/rombios/rombios.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/firmware/rombios/rombios.c Tue Jul 10 08:39:26 2007 -0600 @@ -4675,6 +4675,10 @@ int09_function(DI, SI, BP, SP, BX, DX, C write_byte(0x0040, 0x18, mf2_flags); break; + case 0x53: /* Del */ + if ((shift_flags & 0x0c) == 0x0c) /* Ctrl + Alt */ + machine_reset(); + /* Fall through */ default: if (scancode & 0x80) return; /* toss key releases ... */ if (scancode > MAX_SCAN_CODE) { diff -r 87b0b6a08dbd -r 42586a0f4407 tools/firmware/vmxassist/vm86.c --- a/tools/firmware/vmxassist/vm86.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/firmware/vmxassist/vm86.c Tue Jul 10 08:39:26 2007 -0600 @@ -594,16 +594,24 @@ movr(struct regs *regs, unsigned prefix, TRACE((regs, regs->eip - eip, "movb %%e%s, *0x%x", rnames[r], addr)); write8(addr, val); - break; + return 1; case 0x8A: /* addr32 mov r/m8, r8 */ TRACE((regs, regs->eip - eip, "movb *0x%x, %%%s", addr, rnames[r])); setreg8(regs, r, read8(addr)); - break; + return 1; case 0x89: /* addr32 mov r16, r/m16 */ val = getreg32(regs, r); + if ((modrm & 0xC0) == 0xC0) { + if (prefix & DATA32) + setreg32(regs, modrm & 7, val); + else + setreg16(regs, modrm & 7, MASK16(val)); + return 1; + } + if (prefix & DATA32) { TRACE((regs, regs->eip - eip, "movl %%e%s, *0x%x", rnames[r], addr)); @@ -613,9 +621,17 @@ movr(struct regs *regs, unsigned prefix, "movw %%%s, *0x%x", rnames[r], addr)); write16(addr, MASK16(val)); } - break; - - case 0x8B: /* addr32 mov r/m16, r16 */ + return 1; + + case 0x8B: /* mov r/m16, r16 */ + if ((modrm & 0xC0) == 0xC0) { + if (prefix & DATA32) + setreg32(regs, r, addr); + else + setreg16(regs, r, MASK16(addr)); + return 1; + } + if (prefix & DATA32) { TRACE((regs, regs->eip - eip, "movl *0x%x, %%e%s", addr, rnames[r])); @@ -625,7 +641,7 @@ movr(struct regs *regs, unsigned prefix, "movw *0x%x, %%%s", addr, rnames[r])); setreg16(regs, r, read16(addr)); } - break; + return 1; case 0xC6: /* addr32 movb $imm, r/m8 */ if ((modrm >> 3) & 7) @@ -634,9 +650,9 @@ movr(struct regs *regs, unsigned prefix, write8(addr, val); TRACE((regs, regs->eip - eip, "movb $0x%x, *0x%x", val, addr)); - break; - } - return 1; + return 1; + } + return 0; } /* @@ -816,8 +832,8 @@ mov_to_seg(struct regs *regs, unsigned p * 1) real->protected mode. * 2) protected->real mode. */ - if ((mode != VM86_REAL_TO_PROTECTED) && - (mode != VM86_PROTECTED_TO_REAL)) + if (mode != VM86_REAL_TO_PROTECTED && + mode != VM86_PROTECTED_TO_REAL) return 0; /* Register source only. */ @@ -1037,8 +1053,8 @@ set_mode(struct regs *regs, enum vm86_mo { switch (newmode) { case VM86_REAL: - if ((mode == VM86_PROTECTED_TO_REAL) || - (mode == VM86_REAL_TO_PROTECTED)) { + if (mode == VM86_PROTECTED_TO_REAL || + mode == VM86_REAL_TO_PROTECTED) { regs->eflags &= ~EFLAGS_TF; real_mode(regs); } else if (mode != VM86_REAL) @@ -1121,7 +1137,7 @@ jmpl_indirect(struct regs *regs, int pre if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ set_mode(regs, VM86_PROTECTED); - else if (mode == VM86_PROTECTED_TO_REAL)/* jump to real mode */ + else if (mode == VM86_PROTECTED_TO_REAL) /* jump to real mode */ set_mode(regs, VM86_REAL); else panic("jmpl"); @@ -1147,7 +1163,7 @@ retl(struct regs *regs, int prefix) if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ set_mode(regs, VM86_PROTECTED); - else if (mode == VM86_PROTECTED_TO_REAL)/* jump to real mode */ + else if (mode == VM86_PROTECTED_TO_REAL) /* jump to real mode */ set_mode(regs, VM86_REAL); else panic("retl"); @@ -1382,9 +1398,7 @@ opcode(struct regs *regs) case 0x39: /* addr32 cmp r16, r/m16 */ case 0x3B: /* addr32 cmp r/m16, r16 */ - if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) - goto invalid; - if ((prefix & ADDR32) == 0) + if (mode == VM86_PROTECTED_TO_REAL || !(prefix & ADDR32)) goto invalid; if (!cmp(regs, prefix, opc)) goto invalid; @@ -1427,37 +1441,17 @@ opcode(struct regs *regs) } continue; - case 0x88: /* mov r8, r/m8 */ - case 0x8A: /* mov r/m8, r8 */ - if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) - goto invalid; - if ((prefix & ADDR32) == 0) + case 0x88: /* addr32 mov r8, r/m8 */ + case 0x8A: /* addr32 mov r/m8, r8 */ + if (mode == VM86_PROTECTED_TO_REAL || !(prefix & ADDR32)) goto invalid; if (!movr(regs, prefix, opc)) goto invalid; return OPC_EMULATED; - case 0x89: /* addr32 mov r16, r/m16 */ - if (mode == VM86_PROTECTED_TO_REAL) { - unsigned modrm = fetch8(regs); - unsigned addr = operand(prefix, regs, modrm); - unsigned val, r = (modrm >> 3) & 7; - - if (prefix & DATA32) { - val = getreg16(regs, r); - write32(addr, val); - } else { - val = getreg32(regs, r); - write16(addr, MASK16(val)); - } - TRACE((regs, regs->eip - eip, - "mov %%%s, *0x%x", rnames[r], addr)); - return OPC_EMULATED; - } - case 0x8B: /* addr32 mov r/m16, r16 */ - if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) - goto invalid; - if ((prefix & ADDR32) == 0) + case 0x89: /* mov r16, r/m16 */ + case 0x8B: /* mov r/m16, r16 */ + if (mode != VM86_PROTECTED_TO_REAL && !(prefix & ADDR32)) goto invalid; if (!movr(regs, prefix, opc)) goto invalid; @@ -1469,7 +1463,7 @@ opcode(struct regs *regs) return OPC_EMULATED; case 0x8F: /* addr32 pop r/m16 */ - if ((prefix & ADDR32) == 0) + if (!(prefix & ADDR32)) goto invalid; if (!pop(regs, prefix, opc)) goto invalid; @@ -1498,48 +1492,48 @@ opcode(struct regs *regs) return OPC_EMULATED; case 0xA1: /* mov ax, r/m16 */ - { - int addr, data; - int seg = segment(prefix, regs, regs->vds); - int offset = prefix & ADDR32? fetch32(regs) : fetch16(regs); - - if (prefix & DATA32) { - addr = address(regs, seg, offset); - data = read32(addr); - setreg32(regs, 0, data); - } else { - addr = address(regs, seg, offset); - data = read16(addr); - setreg16(regs, 0, data); - } - TRACE((regs, regs->eip - eip, "mov *0x%x, %%ax", addr)); + { + int addr, data; + int seg = segment(prefix, regs, regs->vds); + int offset = prefix & ADDR32 ? fetch32(regs) : fetch16(regs); + + if (prefix & DATA32) { + addr = address(regs, seg, offset); + data = read32(addr); + setreg32(regs, 0, data); + } else { + addr = address(regs, seg, offset); + data = read16(addr); + setreg16(regs, 0, data); } - return OPC_EMULATED; + TRACE((regs, regs->eip - eip, "mov *0x%x, %%ax", addr)); + return OPC_EMULATED; + } case 0xBB: /* mov bx, imm16 */ - { - int data; - if (prefix & DATA32) { - data = fetch32(regs); - setreg32(regs, 3, data); - } else { - data = fetch16(regs); - setreg16(regs, 3, data); - } - TRACE((regs, regs->eip - eip, "mov $0x%x, %%bx", data)); + { + int data; + if (prefix & DATA32) { + data = fetch32(regs); + setreg32(regs, 3, data); + } else { + data = fetch16(regs); + setreg16(regs, 3, data); } - return OPC_EMULATED; + TRACE((regs, regs->eip - eip, "mov $0x%x, %%bx", data)); + return OPC_EMULATED; + } case 0xC6: /* addr32 movb $imm, r/m8 */ - if ((prefix & ADDR32) == 0) + if (!(prefix & ADDR32)) goto invalid; if (!movr(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xCB: /* retl */ - if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + if (mode == VM86_REAL_TO_PROTECTED || + mode == VM86_PROTECTED_TO_REAL) { retl(regs, prefix); return OPC_INVALID; } @@ -1576,37 +1570,37 @@ opcode(struct regs *regs) return OPC_EMULATED; case 0xEA: /* jmpl */ - if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + if (mode == VM86_REAL_TO_PROTECTED || + mode == VM86_PROTECTED_TO_REAL) { jmpl(regs, prefix); return OPC_INVALID; } goto invalid; - case 0xFF: /* jmpl (indirect) */ - { - unsigned modrm = fetch8(regs); - switch((modrm >> 3) & 7) { - case 5: /* jmpl (indirect) */ - if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { - jmpl_indirect(regs, prefix, modrm); - return OPC_INVALID; - } - goto invalid; - - case 6: /* push r/m16 */ - pushrm(regs, prefix, modrm); - return OPC_EMULATED; - - default: - goto invalid; + case 0xFF: + { + unsigned modrm = fetch8(regs); + switch((modrm >> 3) & 7) { + case 5: /* jmpl (indirect) */ + if (mode == VM86_REAL_TO_PROTECTED || + mode == VM86_PROTECTED_TO_REAL) { + jmpl_indirect(regs, prefix, modrm); + return OPC_INVALID; } + goto invalid; + + case 6: /* push r/m16 */ + pushrm(regs, prefix, modrm); + return OPC_EMULATED; + + default: + goto invalid; } + } case 0xEB: /* short jump */ - if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + if (mode == VM86_REAL_TO_PROTECTED || + mode == VM86_PROTECTED_TO_REAL) { disp = (char) fetch8(regs); TRACE((regs, 2, "jmp 0x%x", regs->eip + disp)); regs->eip += disp; @@ -1629,7 +1623,7 @@ opcode(struct regs *regs) continue; case 0xF6: /* addr32 testb $imm, r/m8 */ - if ((prefix & ADDR32) == 0) + if (!(prefix & ADDR32)) goto invalid; if (!test(regs, prefix, opc)) goto invalid; diff -r 87b0b6a08dbd -r 42586a0f4407 tools/ioemu/keymaps/ja --- a/tools/ioemu/keymaps/ja Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/ioemu/keymaps/ja Tue Jul 10 08:39:26 2007 -0600 @@ -101,6 +101,7 @@ bar 0x7d shift bar 0x7d shift underscore 0x73 shift Henkan_Mode 0x79 +Katakana_Real 0x70 Katakana 0x70 Muhenkan 0x7b Henkan_Mode_Real 0x79 diff -r 87b0b6a08dbd -r 42586a0f4407 tools/ioemu/keymaps/modifiers --- a/tools/ioemu/keymaps/modifiers Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/ioemu/keymaps/modifiers Tue Jul 10 08:39:26 2007 -0600 @@ -11,8 +11,8 @@ Control_L 0x1d # Translate Super to Windows keys. # This is hardcoded. See documentation for details. -Super_R 0xdb -Super_L 0xdc +Super_R 0xdc +Super_L 0xdb # Translate Menu to the Windows Application key. Menu 0xdd diff -r 87b0b6a08dbd -r 42586a0f4407 tools/ioemu/vnc_keysym.h --- a/tools/ioemu/vnc_keysym.h Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/ioemu/vnc_keysym.h Tue Jul 10 08:39:26 2007 -0600 @@ -290,12 +290,14 @@ static name2keysym_t name2keysym[]={ /* localized keys */ {"BackApostrophe", 0xff21}, {"Muhenkan", 0xff22}, -{"Katakana", 0xff25}, +{"Katakana", 0xff27}, {"Hankaku", 0xff29}, {"Zenkaku_Hankaku", 0xff2a}, {"Henkan_Mode_Real", 0xff23}, {"Henkan_Mode_Ultra", 0xff3e}, {"backslash_ja", 0xffa5}, +{"Katakana_Real", 0xff25}, +{"Eisu_toggle", 0xff30}, /* dead keys */ {"dead_grave", 0xfe50}, diff -r 87b0b6a08dbd -r 42586a0f4407 tools/libxc/Makefile --- a/tools/libxc/Makefile Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/libxc/Makefile Tue Jul 10 08:39:26 2007 -0600 @@ -57,7 +57,6 @@ GUEST_SRCS-$(CONFIG_POWERPC) += xc_dom_p -include $(XEN_TARGET_ARCH)/Makefile CFLAGS += -Werror -Wmissing-prototypes -CFLAGS += -fno-strict-aliasing CFLAGS += $(INCLUDES) -I. -I../xenstore # Needed for posix_fadvise64() in xc_linux.c diff -r 87b0b6a08dbd -r 42586a0f4407 tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/libxc/xc_domain.c Tue Jul 10 08:39:26 2007 -0600 @@ -181,6 +181,7 @@ int xc_domain_getinfo(int xc_handle, info->blocked = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_blocked); info->running = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_running); info->hvm = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_hvm_guest); + info->debugged = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_debugged); info->shutdown_reason = (domctl.u.getdomaininfo.flags>>XEN_DOMINF_shutdownshift) & diff -r 87b0b6a08dbd -r 42586a0f4407 tools/libxc/xc_misc.c --- a/tools/libxc/xc_misc.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/libxc/xc_misc.c Tue Jul 10 08:39:26 2007 -0600 @@ -59,6 +59,8 @@ int xc_physinfo(int xc_handle, DECLARE_SYSCTL; sysctl.cmd = XEN_SYSCTL_physinfo; + + memcpy(&sysctl.u.physinfo, put_info, sizeof(*put_info)); if ( (ret = do_sysctl(xc_handle, &sysctl)) != 0 ) return ret; diff -r 87b0b6a08dbd -r 42586a0f4407 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/libxc/xenctrl.h Tue Jul 10 08:39:26 2007 -0600 @@ -153,7 +153,7 @@ typedef struct xc_dominfo { uint32_t ssidref; unsigned int dying:1, crashed:1, shutdown:1, paused:1, blocked:1, running:1, - hvm:1; + hvm:1, debugged:1; unsigned int shutdown_reason; /* only meaningful if shutdown==1 */ unsigned long nr_pages; unsigned long shared_info_frame; @@ -485,6 +485,7 @@ int xc_send_debug_keys(int xc_handle, ch int xc_send_debug_keys(int xc_handle, char *keys); typedef xen_sysctl_physinfo_t xc_physinfo_t; +typedef uint32_t xc_cpu_to_node_t; int xc_physinfo(int xc_handle, xc_physinfo_t *info); diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/lowlevel/xc/xc.c --- a/tools/python/xen/lowlevel/xc/xc.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/lowlevel/xc/xc.c Tue Jul 10 08:39:26 2007 -0600 @@ -680,33 +680,62 @@ static PyObject *pyxc_pages_to_kib(XcObj static PyObject *pyxc_physinfo(XcObject *self) { +#define MAX_CPU_ID 255 xc_physinfo_t info; char cpu_cap[128], *p=cpu_cap, *q=cpu_cap; - int i; - + int i, j, max_cpu_id; + PyObject *ret_obj, *node_to_cpu_obj; + xc_cpu_to_node_t map[MAX_CPU_ID]; + + set_xen_guest_handle(info.cpu_to_node, map); + info.max_cpu_id = MAX_CPU_ID; + if ( xc_physinfo(self->xc_handle, &info) != 0 ) return pyxc_error_to_exception(); - *q=0; - for(i=0;i<sizeof(info.hw_cap)/4;i++) + *q = 0; + for ( i = 0; i < sizeof(info.hw_cap)/4; i++ ) { - p+=sprintf(p,"%08x:",info.hw_cap[i]); - if(info.hw_cap[i]) - q=p; + p += sprintf(p, "%08x:", info.hw_cap[i]); + if ( info.hw_cap[i] ) + q = p; } - if(q>cpu_cap) - *(q-1)=0; - - return Py_BuildValue("{s:i,s:i,s:i,s:i,s:l,s:l,s:l,s:i,s:s}", - "threads_per_core", info.threads_per_core, - "cores_per_socket", info.cores_per_socket, - "sockets_per_node", info.sockets_per_node, - "nr_nodes", info.nr_nodes, - "total_memory", pages_to_kib(info.total_pages), - "free_memory", pages_to_kib(info.free_pages), - "scrub_memory", pages_to_kib(info.scrub_pages), - "cpu_khz", info.cpu_khz, - "hw_caps", cpu_cap); + if ( q > cpu_cap ) + *(q-1) = 0; + + ret_obj = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:l,s:l,s:l,s:i,s:s}", + "nr_nodes", info.nr_nodes, + "max_cpu_id", info.max_cpu_id, + "threads_per_core", info.threads_per_core, + "cores_per_socket", info.cores_per_socket, + "sockets_per_node", info.sockets_per_node, + "total_memory", pages_to_kib(info.total_pages), + "free_memory", pages_to_kib(info.free_pages), + "scrub_memory", pages_to_kib(info.scrub_pages), + "cpu_khz", info.cpu_khz, + "hw_caps", cpu_cap); + + max_cpu_id = info.max_cpu_id; + if ( max_cpu_id > MAX_CPU_ID ) + max_cpu_id = MAX_CPU_ID; + + /* Construct node-to-cpu lists. */ + node_to_cpu_obj = PyList_New(0); + + /* Make a list for each node. */ + for ( i = 0; i < info.nr_nodes; i++ ) + { + PyObject *cpus = PyList_New(0); + for ( j = 0; j <= max_cpu_id; j++ ) + if ( i == map[j]) + PyList_Append(cpus, PyInt_FromLong(j)); + PyList_Append(node_to_cpu_obj, cpus); + } + + PyDict_SetItemString(ret_obj, "node_to_cpu", node_to_cpu_obj); + + return ret_obj; +#undef MAX_CPU_ID } static PyObject *pyxc_xeninfo(XcObject *self) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/util/acmpolicy.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/util/acmpolicy.py Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,1199 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006,2007 International Business Machines Corp. +# Author: Stefan Berger <stefanb@xxxxxxxxxx> +#============================================================================ + +import os +import commands +import struct +import stat +import array +from xml.dom import minidom, Node +from xen.xend.XendLogging import log +from xen.util import security, xsconstants, bootloader, mkdir +from xen.util.xspolicy import XSPolicy +from xen.util.security import ACMError +from xen.xend.XendError import SecurityError + +ACM_POLICIES_DIR = security.policy_dir_prefix + "/" + +# Constants needed for generating a binary policy from its XML +# representation +ACM_POLICY_VERSION = 3 # Latest one +ACM_CHWALL_VERSION = 1 + +ACM_STE_VERSION = 1 + +ACM_MAGIC = 0x001debc; + +ACM_NULL_POLICY = 0 +ACM_CHINESE_WALL_POLICY = 1 +ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY = 2 +ACM_POLICY_UNDEFINED = 15 + + +ACM_SCHEMA_FILE = "/etc/xen/acm-security/policies/security_policy.xsd" + +class ACMPolicy(XSPolicy): + """ + ACMPolicy class. Implements methods for getting information from + the XML representation of the policy as well as compilation and + loading of a policy into the HV. + """ + + def __init__(self, name=None, dom=None, ref=None, xml=None): + if name: + self.name = name + self.dom = minidom.parse(self.path_from_policy_name(name)) + elif dom: + self.dom = dom + self.name = self.get_name() + elif xml: + self.dom = minidom.parseString(xml) + self.name = self.get_name() + rc = self.validate() + if rc != xsconstants.XSERR_SUCCESS: + raise SecurityError(rc) + mkdir.parents(ACM_POLICIES_DIR, stat.S_IRWXU) + if ref: + from xen.xend.XendXSPolicy import XendACMPolicy + self.xendacmpolicy = XendACMPolicy(self, {}, ref) + else: + self.xendacmpolicy = None + XSPolicy.__init__(self, name=self.name, ref=ref) + + def get_dom(self): + return self.dom + + def get_name(self): + return self.policy_dom_get_hdr_item("PolicyName") + + def get_type(self): + return xsconstants.XS_POLICY_ACM + + def get_type_name(self): + return xsconstants.ACM_POLICY_ID + + def __str__(self): + return self.get_name() + + + def validate(self): + """ + validate against the policy's schema Does not fail if the + libxml2 python lib is not installed + """ + rc = xsconstants.XSERR_SUCCESS + try: + import libxml2 + except Exception, e: + log.warn("Libxml2 python-wrapper is not installed on the system.") + return xsconstants.XSERR_SUCCESS + try: + parserctxt = libxml2.schemaNewParserCtxt(ACM_SCHEMA_FILE) + schemaparser = parserctxt.schemaParse() + valid = schemaparser.schemaNewValidCtxt() + doc = libxml2.parseDoc(self.toxml()) + if doc.schemaValidateDoc(valid) != 0: + rc = -xsconstants.XSERR_BAD_XML + except Exception, e: + log.warn("Problem with the schema: %s" % str(e)) + rc = -xsconstants.XSERR_GENERAL_FAILURE + if rc != xsconstants.XSERR_SUCCESS: + log.warn("XML did not validate against schema") + rc = self.__validate_name_and_labels() + return rc + + def __validate_name_and_labels(self): + """ no ':' allowed in the policy name and the labels """ + if ':' in self.get_name(): + return -xsconstants.XSERR_BAD_POLICY_NAME + for s in self.policy_get_resourcelabel_names(): + if ':' in s: + return -xsconstants.XSERR_BAD_LABEL + for s in self.policy_get_virtualmachinelabel_names(): + if ':' in s: + return -xsconstants.XSERR_BAD_LABEL + return xsconstants.XSERR_SUCCESS + + + def update(self, xml_new): + """ + Update the policy with the new XML. The hypervisor decides + whether the new policy can be applied. + """ + rc = -xsconstants.XSERR_XML_PROCESSING + errors = "" + acmpol_old = self + try: + acmpol_new = ACMPolicy(xml=xml_new) + except Exception: + return -xsconstants.XSERR_XML_PROCESSING, errors + + vmlabel_map = acmpol_new.policy_get_vmlabel_translation_map() + # An update requires version information in the current + # and new policy. The version number of the current policy + # must be the same as what is in the FromPolicy/Version node + # in the new one and the current policy's name must be the + # same as in FromPolicy/PolicyName + + now_vers = acmpol_old.policy_dom_get_hdr_item("Version") + now_name = acmpol_old.policy_dom_get_hdr_item("PolicyName") + req_oldvers = acmpol_new.policy_dom_get_frompol_item("Version") + req_oldname = acmpol_new.policy_dom_get_frompol_item("PolicyName") + + if now_vers == "" or \ + now_vers != req_oldvers or \ + now_name != req_oldname: + log.info("Policy rejected: %s != %s or %s != %s" % \ + (now_vers,req_oldvers,now_name,req_oldname)) + return -xsconstants.XSERR_VERSION_PREVENTS_UPDATE, errors + + if not self.isVersionUpdate(acmpol_new): + log.info("Policy rejected since new version is not an update.") + return -xsconstants.XSERR_VERSION_PREVENTS_UPDATE, errors + + if self.isloaded(): + newvmnames = \ + acmpol_new.policy_get_virtualmachinelabel_names_sorted() + oldvmnames = \ + acmpol_old.policy_get_virtualmachinelabel_names_sorted() + del_array = "" + chg_array = "" + for o in oldvmnames: + if o not in newvmnames: + old_idx = oldvmnames.index(o) + 1 # for _NULL_LABEL_ + if vmlabel_map.has_key(o): + #not a deletion, but a renaming + new = vmlabel_map[o] + new_idx = newvmnames.index(new) + 1 # for _NULL_LABEL_ + chg_array += struct.pack("ii", old_idx, new_idx) + else: + del_array += struct.pack("i", old_idx) + for v in newvmnames: + if v in oldvmnames: + old_idx = oldvmnames.index(v) + 1 # for _NULL_LABEL_ + new_idx = newvmnames.index(v) + 1 # for _NULL_LABEL_ + if old_idx != new_idx: + chg_array += struct.pack("ii", old_idx, new_idx) + + # VM labels indicated in the 'from' attribute of a VM or + # resource node but that did not exist in the old policy + # are considered bad labels. + bad_renamings = set(vmlabel_map.keys()) - set(oldvmnames) + if len(bad_renamings) > 0: + log.error("Bad VM label renamings: %s" % + list(bad_renamings)) + return -xsconstants.XSERR_BAD_LABEL, errors + + reslabel_map = acmpol_new.policy_get_reslabel_translation_map() + oldresnames = acmpol_old.policy_get_resourcelabel_names() + bad_renamings = set(reslabel_map.keys()) - set(oldresnames) + if len(bad_renamings) > 0: + log.error("Bad resource label renamings: %s" % + list(bad_renamings)) + return -xsconstants.XSERR_BAD_LABEL, errors + + #Get binary and map from the new policy + rc, map, bin_pol = acmpol_new.policy_create_map_and_bin() + if rc != xsconstants.XSERR_SUCCESS: + log.error("Could not build the map and binary policy.") + return rc, errors + + #Need to do / check the following: + # - relabel all resources where there is a 'from' field in + # the policy and mark those as unlabeled where the label + # does not appear in the new policy anymore + # - relabel all VMs where there is a 'from' field in the + # policy and mark those as unlabeled where the label + # does not appear in the new policy anymore; no running + # or paused VM may be unlabeled through this + # - check that under the new labeling conditions the VMs + # still have access to their resources as before. Unlabeled + # resources are inaccessible. If this check fails, the + # update failed. + # - Attempt changes in the hypervisor; if this step fails, + # roll back the relabeling of resources and VMs + # - Commit the relabeling of resources + + + rc, errors = security.change_acm_policy(bin_pol, + del_array, chg_array, + vmlabel_map, reslabel_map, + self, acmpol_new) + + if rc == 0: + # Replace the old DOM with the new one and save it + self.dom = acmpol_new.dom + self.compile() + log.info("ACM policy update was successful") + else: + #Not loaded in HV + self.dom = acmpol_new.dom + self.compile() + return rc, errors + + def compareVersions(self, v1, v2): + """ + Compare two policy versions given their tuples of major and + minor. + Return '0' if versions are equal, '>0' if v1 > v2 and + '<' if v1 < v2 + """ + rc = v1[0] - v2[0] + if rc == 0: + rc = v1[1] - v2[1] + return rc + + def getVersionTuple(self, item="Version"): + v_str = self.policy_dom_get_hdr_item(item) + return self.__convVersionToTuple(v_str) + + def get_version(self): + return self.policy_dom_get_hdr_item("Version") + + def isVersionUpdate(self, polnew): + if self.compareVersions(polnew.getVersionTuple(), + self.getVersionTuple()) > 0: + return True + return False + + def __convVersionToTuple(self, v_str): + """ Convert a version string, formatted according to the scheme + "%d.%d" into a tuple of (major, minor). Return (0,0) if the + string is empty. + """ + major = 0 + minor = 0 + if v_str != "": + tmp = v_str.split(".") + major = int(tmp[0]) + if len(tmp) > 1: + minor = int(tmp[1]) + return (major, minor) + + + def policy_path(self, name, prefix = ACM_POLICIES_DIR ): + path = prefix + name.replace('.','/') + _path = path.split("/") + del _path[-1] + mkdir.parents("/".join(_path), stat.S_IRWXU) + return path + + def path_from_policy_name(self, name): + return self.policy_path(name) + "-security_policy.xml" + + # + # Functions interacting with the bootloader + # + def vmlabel_to_ssidref(self, vm_label): + """ Convert a VMlabel into an ssidref given the current + policy + Return xsconstants.INVALID_SSIDREF if conversion failed. + """ + ssidref = xsconstants.INVALID_SSIDREF + names = self.policy_get_virtualmachinelabel_names_sorted() + try: + vmidx = names.index(vm_label) + 1 # for _NULL_LABEL_ + ssidref = (vmidx << 16) | vmidx + except: + pass + return ssidref + + def set_vm_bootlabel(self, vm_label): + parms="<>" + if vm_label != "": + ssidref = self.vmlabel_to_ssidref(vm_label) + if ssidref == xsconstants.INVALID_SSIDREF: + return -xsconstants.XSERR_BAD_LABEL + parms = "0x%08x:%s:%s:%s" % \ + (ssidref, xsconstants.ACM_POLICY_ID, \ + self.get_name(),vm_label) + else: + ssidref = 0 #Identifier for removal + try: + def_title = bootloader.get_default_title() + bootloader.set_kernel_attval(def_title, "ssidref", parms) + except: + return -xsconstants.XSERR_GENERAL_FAILURE + return ssidref + + # + # Utility functions related to the policy's files + # + def get_filename(self, postfix, prefix = ACM_POLICIES_DIR, dotted=False): + """ + Create the filename for the policy. The prefix is prepended + to the path. If dotted is True, then a policy name like + 'a.b.c' will remain as is, otherwise it will become 'a/b/c' + """ + name = self.get_name() + if name: + p = name.split(".") + path = "" + if dotted == True: + sep = "." + else: + sep = "/" + if len(p) > 1: + path = sep.join(p[0:len(p)-1]) + if prefix != "" or path != "": + allpath = prefix + path + sep + p[-1] + postfix + else: + allpath = p[-1] + postfix + return allpath + return None + + def __readfile(self, name): + cont = "" + filename = self.get_filename(name) + f = open(filename, "r") + if f: + cont = f.read() + f.close() + return cont + + def get_map(self): + return self.__readfile(".map") + + def get_bin(self): + return self.__readfile(".bin") + + # + # DOM-related functions + # + + def policy_dom_get(self, parent, key, createit=False): + for node in parent.childNodes: + if node.nodeType == Node.ELEMENT_NODE: + if node.nodeName == key: + return node + if createit: + self.dom_create_node(parent, key) + return self.policy_dom_get(parent, key) + + def dom_create_node(self, parent, newname, value=" "): + xml = "<a><"+newname+">"+ value +"</"+newname+"></a>" + frag = minidom.parseString(xml) + frag.childNodes[0].nodeType = Node.DOCUMENT_FRAGMENT_NODE + parent.appendChild(frag.childNodes[0]) + return frag.childNodes[0] + + def dom_get_node(self, path, createit=False): + node = None + parts = path.split("/") + doc = self.get_dom() + if len(parts) > 0: + node = self.policy_dom_get(doc.documentElement, parts[0]) + if node: + i = 1 + while i < len(parts): + _node = self.policy_dom_get(node, parts[i], createit) + if not _node: + if not createit: + break + else: + self.dom_create_node(node, parts[i]) + _node = self.policy_dom_get(node, parts[i]) + node = _node + i += 1 + return node + + # + # Header-related functions + # + def policy_dom_get_header_subnode(self, nodename): + node = self.dom_get_node("PolicyHeader/%s" % nodename) + return node + + def policy_dom_get_hdr_item(self, name, default=""): + node = self.policy_dom_get_header_subnode(name) + if node and len(node.childNodes) > 0: + return node.childNodes[0].nodeValue + return default + + def policy_dom_get_frompol_item(self, name, default="", createit=False): + node = self.dom_get_node("PolicyHeader/FromPolicy",createit) + if node: + node = self.policy_dom_get(node, name, createit) + if node and len(node.childNodes) > 0: + return node.childNodes[0].nodeValue + return default + + def get_header_fields_map(self): + header = { + 'policyname' : self.policy_dom_get_hdr_item("PolicyName"), + 'policyurl' : self.policy_dom_get_hdr_item("PolicyUrl"), + 'reference' : self.policy_dom_get_hdr_item("Reference"), + 'date' : self.policy_dom_get_hdr_item("Date"), + 'namespaceurl' : self.policy_dom_get_hdr_item("NameSpaceUrl"), + 'version' : self.policy_dom_get_hdr_item("Version") + } + return header + + def set_frompolicy_name(self, name): + """ For tools to adapt the header of the policy """ + node = self.dom_get_node("PolicyHeader/FromPolicy/PolicyName", + createit=True) + node.childNodes[0].nodeValue = name + + def set_frompolicy_version(self, version): + """ For tools to adapt the header of the policy """ + node = self.dom_get_node("PolicyHeader/FromPolicy/Version", + createit=True) + node.childNodes[0].nodeValue = version + + def set_policy_name(self, name): + """ For tools to adapt the header of the policy """ + node = self.dom_get_node("PolicyHeader/PolicyName") + node.childNodes[0].nodeValue = name + + def set_policy_version(self, version): + """ For tools to adapt the header of the policy """ + node = self.dom_get_node("PolicyHeader/Version") + node.childNodes[0].nodeValue = version + + def update_frompolicy(self, curpol): + self.set_frompolicy_name(curpol.policy_dom_get_hdr_item("PolicyName")) + version = curpol.policy_dom_get_hdr_item("Version") + self.set_frompolicy_version(version) + (maj, min) = self.__convVersionToTuple(version) + self.set_policy_version("%s.%s" % (maj, min+1)) + + # + # Get all types that are part of a node + # + + def policy_get_types(self, node): + strings = [] + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == "Type": + strings.append(node.childNodes[i].childNodes[0].nodeValue) + i += 1 + return strings + + # + # Simple Type Enforcement-related functions + # + + def policy_get_stetypes_node(self): + node = self.dom_get_node("SimpleTypeEnforcement/SimpleTypeEnforcementTypes") + return node + + def policy_get_stetypes_types(self): + strings = [] + node = self.policy_get_stetypes_node() + if node: + strings = self.policy_get_types(node) + return strings + + # + # Chinese Wall Type-related functions + # + + def policy_get_chwall_types(self): + strings = [] + node = self.dom_get_node("ChineseWall/ChineseWallTypes") + if node: + strings = self.policy_get_types(node) + return strings + + def policy_get_chwall_cfses(self): + cfs = [] + node = self.dom_get_node("ChineseWall/ConflictSets") + if node: + i = 0 + while i < len(node.childNodes): + _cfs = {} + if node.childNodes[i].nodeName == "Conflict": + _cfs['name'] = node.childNodes[i].getAttribute('name') + _cfs['chws'] = self.policy_get_types(node.childNodes[i]) + cfs.append(_cfs) + i += 1 + return cfs + + def policy_get_chwall_cfses_names_sorted(self): + """ + Return the list of all conflict set names in alphabetical + order. + """ + cfs_names = [] + node = self.dom_get_node("ChineseWall/ConflictSets") + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == "Conflict": + n = node.childNodes[i].getAttribute('name') + #it better have a name! + if n: + cfs_names.append(n) + i += 1 + cfs_names.sort() + return cfs_names + + # + # Subject Label-related functions + # + + def policy_get_bootstrap_vmlabel(self): + node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels") + if node: + vmlabel = node.getAttribute("bootstrap") + return vmlabel + + # Get the names of all virtual machine labels; returns an array + def policy_get_virtualmachinelabel_names(self): + strings = [] + node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels") + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == "VirtualMachineLabel": + name = self.policy_dom_get(node.childNodes[i], "Name") + strings.append(name.childNodes[0].nodeValue) + i += 1 + return strings + + def policy_sort_virtualmachinelabel_names(self, vmnames): + bootstrap = self.policy_get_bootstrap_vmlabel() + if bootstrap not in vmnames: + raise SecurityError(-xsconstants.XSERR_POLICY_INCONSISTENT) + vmnames.remove(bootstrap) + vmnames.sort() + vmnames.insert(0, bootstrap) + return vmnames + + def policy_get_virtualmachinelabel_names_sorted(self): + """ Get a sorted list of VMlabel names. The bootstrap VM's + label will be the first one in that list, followed + by an alphabetically sorted list of VM label names """ + vmnames = self.policy_get_virtualmachinelabel_names() + return self.policy_sort_virtualmachinelabel_names(vmnames) + + def policy_get_virtualmachinelabels(self): + """ Get a list of all virtual machine labels in this policy """ + res = [] + node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels") + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == "VirtualMachineLabel": + _res = {} + _res['type'] = xsconstants.ACM_LABEL_VM + name = self.policy_dom_get(node.childNodes[i], "Name") + _res['name'] = name.childNodes[0].nodeValue + stes = self.policy_dom_get(node.childNodes[i], + "SimpleTypeEnforcementTypes") + if stes: + _res['stes'] = self.policy_get_types(stes) + else: + _res['stes'] = [] + chws = self.policy_dom_get(node.childNodes[i], + "ChineseWallTypes") + if chws: + _res['chws'] = self.policy_get_types(chws) + else: + _res['chws'] = [] + res.append(_res) + i += 1 + return res + + def policy_get_stes_of_vmlabel(self, vmlabel): + """ Get a list of all STEs of a given VMlabel """ + return self.__policy_get_stes_of_labeltype(vmlabel, + "VirtualMachineLabel") + + def policy_get_stes_of_resource(self, reslabel): + """ Get a list of all resources of a given VMlabel """ + return self.__policy_get_stes_of_labeltype(reslabel, "ResourceLabel") + + def __policy_get_stes_of_labeltype(self, label, labeltype): + node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels") + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == labeltype: + name = self.policy_dom_get(node.childNodes[i], "Name") + if name.childNodes[0].nodeValue == label: + stes = self.policy_dom_get(node.childNodes[i], + "SimpleTypeEnforcementTypes") + if not stes: + return [] + return self.policy_get_types(stes) + i += 1 + return [] + + def policy_check_vmlabel_against_reslabels(self, vmlabel, resources): + """ + Check whether the given vmlabel is compatible with the given + resource labels. Do this by getting all the STEs of the + vmlabel and the STEs of the resources. Any STE type of the + VM label must match an STE type of the resource. + """ + vm_stes = self.policy_get_stes_of_vmlabel(vmlabel) + if len(vm_stes) == 0: + return False + for res in resources: + res_stes = self.policy_get_stes_of_resource(res) + if len( set(res_stes).union( set(vm_stes) ) ) == 0: + return False + return True + + def __policy_get_label_translation_map(self, path, labeltype): + res = {} + node = self.dom_get_node("SecurityLabelTemplate/" + path) + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == labeltype: + name = self.policy_dom_get(node.childNodes[i], "Name") + from_name = name.getAttribute("from") + if from_name: + res.update({from_name : name.childNodes[0].nodeValue}) + i += 1 + return res + + def policy_get_vmlabel_translation_map(self): + """ + Get a dictionary of virtual machine mappings from their + old VMlabel name to the new VMlabel name. + """ + return self.__policy_get_label_translation_map("SubjectLabels", + "VirtualMachineLabel") + + def policy_get_reslabel_translation_map(self): + """ + Get a dictionary of resource mappings from their + old resource label name to the new resource label name. + """ + return self.__policy_get_label_translation_map("ObjectLabels", + "ResourceLabel") + + # + # Object Label-related functions + # + def policy_get_resourcelabel_names(self): + """ + Get the names of all resource labels in an array but + only those that actually have types + """ + strings = [] + node = self.dom_get_node("SecurityLabelTemplate/ObjectLabels") + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == "ResourceLabel": + name = self.policy_dom_get(node.childNodes[i], "Name") + stes = self.policy_dom_get(node.childNodes[i], + "SimpleTypeEnforcementTypes") + if stes: + strings.append(name.childNodes[0].nodeValue) + i += 1 + return strings + + def policy_get_resourcelabels(self): + """ + Get all information about all resource labels of this policy. + """ + res = [] + node = self.dom_get_node("SecurityLabelTemplate/ObjectLabels") + if node: + i = 0 + while i < len(node.childNodes): + if node.childNodes[i].nodeName == "ResourceLabel": + _res = {} + _res['type'] = xsconstants.ACM_LABEL_RES + name = self.policy_dom_get(node.childNodes[i], "Name") + _res['name'] = name.childNodes[0].nodeValue + stes = self.policy_dom_get(node.childNodes[i], + "SimpleTypeEnforcementTypes") + if stes: + _res['stes'] = self.policy_get_types(stes) + else: + _res['stes'] = [] + _res['chws'] = [] + res.append(_res) + i += 1 + return res + + + def policy_find_reslabels_with_stetype(self, stetype): + """ + Find those resource labels that hold a given STE type. + """ + res = [] + reslabels = self.policy_get_resourcelabels() + for resl in reslabels: + if stetype in resl['stes']: + res.append(resl['name']) + return res + + + def toxml(self): + dom = self.get_dom() + if dom: + return dom.toxml() + return None + + def save(self): + ### Save the XML policy into a file ### + rc = -xsconstants.XSERR_FILE_ERROR + name = self.get_name() + if name: + path = self.path_from_policy_name(name) + if path: + f = open(path, 'w') + if f: + f.write(self.toxml()) + f.close() + rc = 0 + return rc + + def __write_to_file(self, suffix, data): + #write the data into a file with the given suffix + f = open(self.get_filename(suffix),"w") + if f: + try: + try: + f.write(data) + except Exception, e: + log.error("Error writing file: %s" % str(e)) + return -xsconstants.XSERR_FILE_ERROR + finally: + f.close() + else: + return -xsconstants.XSERR_FILE_ERROR + return xsconstants.XSERR_SUCCESS + + + def compile(self): + rc = self.save() + if rc == 0: + rc, mapfile, bin_pol = self.policy_create_map_and_bin() + + if rc == 0: + rc = self.__write_to_file(".map", mapfile) + if rc != 0: + log.error("Error writing map file") + + if rc == 0: + rc = self.__write_to_file(".bin", bin_pol) + if rc != 0: + log.error("Error writing binary policy file") + return rc + + def loadintohv(self): + """ + load this policy into the hypervisor + if successful,the policy's flags will indicate that the + policy is the one loaded into the hypervisor + """ + (ret, output) = commands.getstatusoutput( + security.xensec_tool + + " loadpolicy " + + self.get_filename(".bin")) + if ret != 0: + return -xsconstants.XSERR_POLICY_LOAD_FAILED + return xsconstants.XSERR_SUCCESS + + def isloaded(self): + """ + Determine whether this policy is the active one. + """ + security.refresh_security_policy() + if self.get_name() == security.active_policy: + return True + return False + + def destroy(self): + """ + Destroy the policy including its binary, mapping and + XML files. + This only works if the policy is not the one that's loaded + """ + if self.isloaded(): + return -xsconstants.XSERR_POLICY_LOADED + files = [ self.get_filename(".map",""), + self.get_filename(".bin",""), + self.path_from_policy_name(self.get_name())] + for f in files: + try: + os.unlink(f) + except: + pass + if self.xendacmpolicy: + self.xendacmpolicy.destroy() + XSPolicy.destroy(self) + return xsconstants.XSERR_SUCCESS + + def policy_get_domain_label(self, domid): + """ + Given a domain's ID, retrieve the label it has using + its ssidref for reverse calculation. + """ + try: + mgmt_dom = security.get_ssid(domid) + except: + return "" + return self.policy_get_domain_label_by_ssidref(int(mgmt_dom[3])) + + def policy_get_domain_label_by_ssidref(self, ssidref): + """ Given an ssidref, find the corresponding VM label """ + chwall_ref = ssidref & 0xffff + try: + allvmtypes = self.policy_get_virtualmachinelabel_names_sorted() + except: + return None + return allvmtypes[chwall_ref-1] # skip _NULL_LABEL_ + + def policy_get_domain_label_formatted(self, domid): + label = self.policy_get_domain_label(domid) + if label == "": + return "" + return "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, self.get_name(), label) + + def policy_get_domain_label_by_ssidref_formatted(self, ssidref): + label = self.policy_get_domain_label_by_ssidref(ssidref) + if label == "": + return "" + return "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, self.get_name(), label) + + def policy_create_map_and_bin(self): + """ + Create the policy's map and binary files -- compile the policy. + """ + def roundup8(len): + return ((len + 7) & ~7) + + rc = xsconstants.XSERR_SUCCESS + mapfile = "" + primpolcode = ACM_POLICY_UNDEFINED + secpolcode = ACM_POLICY_UNDEFINED + unknown_ste = set() + unknown_chw = set() + + rc = self.validate() + if rc: + return rc, "", "" + + stes = self.policy_get_stetypes_types() + if stes: + stes.sort() + + chws = self.policy_get_chwall_types() + if chws: + chws.sort() + + vms = self.policy_get_virtualmachinelabels() + bootstrap = self.policy_get_bootstrap_vmlabel() + + vmlabels = self.policy_get_virtualmachinelabel_names_sorted() + if bootstrap not in vmlabels: + log.error("Bootstrap label '%s' not found among VM labels '%s'." \ + % (bootstrap, vmlabels)) + return -xsconstants.XSERR_POLICY_INCONSISTENT, "", "" + + vms_with_chws = [] + chws_by_vm = {} + for v in vms: + if v.has_key("chws"): + vms_with_chws.append(v["name"]) + chws_by_vm[v["name"]] = v["chws"] + if bootstrap in vms_with_chws: + vms_with_chws.remove(bootstrap) + vms_with_chws.sort() + vms_with_chws.insert(0, bootstrap) + else: + vms_with_chws.sort() + + vms_with_stes = [] + stes_by_vm = {} + for v in vms: + if v.has_key("stes"): + vms_with_stes.append(v["name"]) + stes_by_vm[v["name"]] = v["stes"] + if bootstrap in vms_with_stes: + vms_with_stes.remove(bootstrap) + vms_with_stes.sort() + vms_with_stes.insert(0, bootstrap) + else: + vms_with_stes.sort() + + resnames = self.policy_get_resourcelabel_names() + resnames.sort() + stes_by_res = {} + res = self.policy_get_resourcelabels() + for r in res: + if r.has_key("stes"): + stes_by_res[r["name"]] = r["stes"] + + max_chw_ssids = 1 + len(vms_with_chws) + max_chw_types = 1 + len(vms_with_chws) + max_ste_ssids = 1 + len(vms_with_stes) + len(resnames) + max_ste_types = 1 + len(vms_with_stes) + len(resnames) + + mapfile = "POLICYREFERENCENAME %s\n" % self.get_name() + mapfile += "MAGIC %08x\n" % ACM_MAGIC + mapfile += "POLICFILE %s\n" % \ + self.path_from_policy_name(self.get_name()) + mapfile += "BINARYFILE %s\n" % self.get_filename(".bin") + mapfile += "MAX-CHWALL-TYPES %08x\n" % len(chws) + mapfile += "MAX-CHWALL-SSIDS %08x\n" % max_chw_ssids + mapfile += "MAX-CHWALL-LABELS %08x\n" % max_chw_ssids + mapfile += "MAX-STE-TYPES %08x\n" % len(stes) + mapfile += "MAX-STE-SSIDS %08x\n" % max_ste_ssids + mapfile += "MAX-STE-LABELS %08x\n" % max_ste_ssids + mapfile += "\n" + + if chws: + mapfile += \ + "PRIMARY CHWALL\n" + primpolcode = ACM_CHINESE_WALL_POLICY + if stes: + mapfile += \ + "SECONDARY STE\n" + else: + mapfile += \ + "SECONDARY NULL\n" + secpolcode = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY + else: + if stes: + mapfile += \ + "PRIMARY STE\n" + primpolcode = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY + mapfile += \ + "SECONDARY NULL\n" + + mapfile += "\n" + + if len(vms_with_chws) > 0: + mapfile += \ + "LABEL->SSID ANY CHWALL __NULL_LABEL__ %x\n" % 0 + i = 0 + for v in vms_with_chws: + mapfile += \ + "LABEL->SSID VM CHWALL %-20s %x\n" % \ + (v, i+1) + i += 1 + mapfile += "\n" + + if len(vms_with_stes) > 0 or len(resnames) > 0: + mapfile += \ + "LABEL->SSID ANY STE __NULL_LABEL__ %08x\n" % 0 + i = 0 + for v in vms_with_stes: + mapfile += \ + "LABEL->SSID VM STE %-20s %x\n" % (v, i+1) + i += 1 + j = 0 + for r in resnames: + mapfile += \ + "LABEL->SSID RES STE %-20s %x\n" % (r, j+i+1) + j += 1 + mapfile += "\n" + + if vms_with_chws: + mapfile += \ + "SSID->TYPE CHWALL %08x\n" % 0 + i = 1 + for v in vms_with_chws: + mapfile += \ + "SSID->TYPE CHWALL %08x" % i + for c in chws_by_vm[v]: + mapfile += " %s" % c + mapfile += "\n" + i += 1 + mapfile += "\n" + + if len(vms_with_stes) > 0 or len(resnames) > 0: + mapfile += \ + "SSID->TYPE STE %08x\n" % 0 + i = 1 + for v in vms_with_stes: + mapfile += \ + "SSID->TYPE STE %08x" % i + for s in stes_by_vm[v]: + mapfile += " %s" % s + mapfile += "\n" + i += 1 + + for r in resnames: + mapfile += \ + "SSID->TYPE STE %08x" % i + for s in stes_by_res[r]: + mapfile += " %s" % s + mapfile += "\n" + i += 1 + mapfile += "\n" + + if chws: + i = 0 + while i < len(chws): + mapfile += \ + "TYPE CHWALL %-20s %d\n" % (chws[i], i) + i += 1 + mapfile += "\n" + if stes: + i = 0 + while i < len(stes): + mapfile += \ + "TYPE STE %-20s %d\n" % (stes[i], i) + i += 1 + mapfile += "\n" + + mapfile += "\n" + + # Build header with policy name + length = roundup8(4 + len(self.get_name()) + 1) + polname = self.get_name(); + pr_bin = struct.pack("!i", len(polname)+1) + pr_bin += polname; + while len(pr_bin) < length: + pr_bin += "\x00" + + # Build chinese wall part + cfses_names = self.policy_get_chwall_cfses_names_sorted() + cfses = self.policy_get_chwall_cfses() + + chwformat = "!iiiiiiiii" + max_chw_cfs = len(cfses) + chw_ssid_offset = struct.calcsize(chwformat) + chw_confset_offset = chw_ssid_offset + \ + 2 * len(chws) * max_chw_types + chw_running_types_offset = 0 + chw_conf_agg_offset = 0 + + chw_bin = struct.pack(chwformat, + ACM_CHWALL_VERSION, + ACM_CHINESE_WALL_POLICY, + len(chws), + max_chw_ssids, + max_chw_cfs, + chw_ssid_offset, + chw_confset_offset, + chw_running_types_offset, + chw_conf_agg_offset) + chw_bin_body = "" + # simulate __NULL_LABEL__ + for c in chws: + chw_bin_body += struct.pack("!h",0) + # VMs that are listed and their chinese walls + for v in vms_with_chws: + for c in chws: + unknown_chw |= (set(chws_by_vm[v]) - set(chws)) + if c in chws_by_vm[v]: + chw_bin_body += struct.pack("!h",1) + else: + chw_bin_body += struct.pack("!h",0) + + # Conflict sets -- they need to be processed in alphabetical order + for cn in cfses_names: + if cn == "" or cn is None: + return -xsconstants.XSERR_BAD_CONFLICTSET, "", "" + i = 0 + while i < len(cfses): + if cfses[i]['name'] == cn: + conf = cfses[i]['chws'] + break + i += 1 + for c in chws: + if c in conf: + chw_bin_body += struct.pack("!h",1) + else: + chw_bin_body += struct.pack("!h",0) + del cfses[i] + + if len(cfses) != 0: + return -xsconstants.XSERR_BAD_CONFLICTSET, "", "" + + chw_bin += chw_bin_body + + while len(chw_bin) < roundup8(len(chw_bin)): + chw_bin += "\x00" + + # Build STE part + steformat="!iiiii" + ste_bin = struct.pack(steformat, + ACM_STE_VERSION, + ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + len(stes), + max_ste_types, + struct.calcsize(steformat)) + ste_bin_body = "" + if stes: + # Simulate __NULL_LABEL__ + for s in stes: + ste_bin_body += struct.pack("!h",0) + # VMs that are listed and their chinese walls + for v in vms_with_stes: + unknown_ste |= (set(stes_by_vm[v]) - set(stes)) + for s in stes: + if s in stes_by_vm[v]: + ste_bin_body += struct.pack("!h",1) + else: + ste_bin_body += struct.pack("!h",0) + for r in resnames: + unknown_ste |= (set(stes_by_res[r]) - set(stes)) + for s in stes: + if s in stes_by_res[r]: + ste_bin_body += struct.pack("!h",1) + else: + ste_bin_body += struct.pack("!h",0) + + ste_bin += ste_bin_body; + + while len(ste_bin) < roundup8(len(ste_bin)): + ste_bin += "\x00" + + #Write binary header: + headerformat="!iiiiiiiiii" + totallen_bin = struct.calcsize(headerformat) + \ + len(pr_bin) + len(chw_bin) + len(ste_bin) + polref_offset = struct.calcsize(headerformat) + primpoloffset = polref_offset + len(pr_bin) + if primpolcode == ACM_CHINESE_WALL_POLICY: + secpoloffset = primpoloffset + len(chw_bin) + elif primpolcode == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: + secpoloffset = primpoloffset + len(ste_bin) + else: + secpoloffset = primpoloffset + + (major, minor) = self.getVersionTuple() + hdr_bin = struct.pack(headerformat, + ACM_POLICY_VERSION, + ACM_MAGIC, + totallen_bin, + polref_offset, + primpolcode, + primpoloffset, + secpolcode, + secpoloffset, + major, minor) + + all_bin = array.array('B') + for s in [ hdr_bin, pr_bin, chw_bin, ste_bin ]: + for c in s: + all_bin.append(ord(c)) + + log.info("Compiled policy: rc = %s" % hex(rc)) + if len(unknown_ste) > 0: + log.info("The following STEs in VM/res labels were unknown:" \ + " %s" % list(unknown_ste)) + if len(unknown_chw) > 0: + log.info("The following Ch. Wall types in labels were unknown:" \ + " %s" % list(unknown_chw)) + return rc, mapfile, all_bin.tostring() diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/util/bootloader.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/util/bootloader.py Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,521 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006,2007 International Business Machines Corp. +# Author: Stefan Berger <stefanb@xxxxxxxxxx> +#============================================================================ + +import re +import os, stat +import tempfile +import shutil +import threading +from xen.xend.XendLogging import log + +__bootloader = None + +# +# Functions for modifying entries in the bootloader, i.e. adding +# a module to boot the system with a policy. +# + +def get_default_title(): + """ See description in Bootloader class below """ + return __bootloader.get_default_title() + + +def get_boot_policies(): + """ See description in Bootloader class below """ + return __bootloader.get_boot_policies() + + +def add_boot_policy(index, binpolname): + """ See description in Bootloader class below """ + return __bootloader.add_boot_policy(index, binpolname) + + +def rm_policy_from_boottitle(index, unamelist): + """ See description in Bootloader class below """ + return __bootloader.rm_policy_from_boottitle(index, unamelist) + + +def set_kernel_attval(index, att, val): + """ See description in Bootloader class below """ + return __bootloader.set_kernel_attval(index, att, val) + + +def get_kernel_val(index, att): + """ See description in Bootloader class below """ + return __bootloader.get_kernel_val(index, att) + + +def set_boot_policy(title_idx, filename): + boottitles = get_boot_policies() + if boottitles.has_key(title_idx): + rm_policy_from_boottitle(title_idx, [ boottitles[title_idx] ]) + rc = add_boot_policy(title_idx, filename) + return rc + + +def loads_default_policy(filename): + """ Determine whether the given policy is loaded by the default boot title """ + polfile = get_default_policy() + if polfile != None: + if polfile == filename or \ + "/"+polfile == filename: + return True + return False + + +def get_default_policy(): + """ Get the name of the policy loaded by the default boot title """ + title = get_default_title() + policies = get_boot_policies() + return policies.get(title) + + +def set_default_boot_policy(filename): + """ Set the boot policy in the default title to the given name. """ + title = get_default_title() + return set_boot_policy(title, filename) + + +def __is_bootdir_mounted(): + """ + Determine whether the boot partition /boot is mounted or not + """ + rc = False + file = open("/proc/mounts") + for line in file: + tmp = line.split(" ") + if tmp[1] == "/boot": + rc = True + break + return rc + +def get_prefix(): + if __is_bootdir_mounted(): + return "/" + else: + return "/boot/" + + + +class Bootloader: + """ Bootloader class that real bootloader implementations must overwrite """ + def __init__(self): + pass + + def probe(self): + """ Test whether this implementation of a bootloader is supported on the + local system """ + return True + + def get_default_title(self): + """ Get the index (starting with 0) of the default boot title + This number is read from the grub configuration file. + In case of an error '-1' is returned + @rtype: int + @return: the index of the default boot title + """ + return None + + def get_boot_policies(self): + """ Get a dictionary of policies that the system is booting with. + @rtype: dict + @return: dictionary of boot titles where the keys are the + indices of the boot titles + """ + return {} + + def add_boot_policy(self, index, binpolname): + """ Add the binary policy for automatic loading when + booting the system. Add it to the boot title at index + 'index'. + """ + return False + + def rm_policy_from_boottitle(self, index, unamelist): + """ Remove a policy from the given title. A list of possible policies + must be given to detect what module to remove + """ + return False + + def set_kernel_attval(self, index, att, val): + """ + Append an attribut/value pair to the kernel line. + @param index : The index of the title to modify + @param att : The attribute to add + @param val : The value to add. If no value or the special value + '<>' is given, then the attribute will be removed. + If an empty value is given, then only the attribute + is added in the format "att", otherwise "att=val" + is added. + """ + return False + + def get_kernel_val(self, index, att): + """ + Get an attribute's value from the kernel line. + @param index : The index of the title to get the attribute/value from + @param att : The attribute to read the value of + """ + return None + + +class Grub(Bootloader): + """ Implementation for manipulating bootloader entries in grub according + to the 'Bootloader' class interface """ + + def __init__(self): + self.__bootfile_lock = threading.RLock() + self.title_re = re.compile("\s*title\s", re.IGNORECASE) + self.module_re = re.compile("\s+module\s", re.IGNORECASE) + self.policy_re = re.compile(".*\.bin", re.IGNORECASE) + self.kernel_re = re.compile("\s*kernel\s", re.IGNORECASE) + Bootloader.__init__(self) + + def probe(self): + try: + boot_file = self.__get_bootfile() + except: + return False + return True + + + def __get_bootfile(self): + """ Get the name of the bootfile """ + boot_file = "/boot/grub/grub.conf" + alt_boot_file = "/boot/grub/menu.lst" + + if not os.path.isfile(boot_file): + #take alternate boot file instead + boot_file = alt_boot_file + + #follow symlink since menue.lst might be linked to grub.conf + if not os.path.exists(boot_file): + raise IOError("Boot file \'%s\' not found." % boot_file) + + if stat.S_ISLNK(os.lstat(boot_file)[stat.ST_MODE]): + new_name = os.readlink(boot_file) + if new_name[0] == "/": + boot_file = new_name + else: + path = boot_file.split('/') + path[len(path)-1] = new_name + boot_file = '/'.join(path) + if not os.path.exists(boot_file): + raise IOError("Boot file \'%s\' not found." % boot_file) + return boot_file + + + def __get_titles(self): + """ Get the names of all boot titles in the grub config file + @rtype: list + @return: list of names of available boot titles + """ + titles = [] + try: + boot_file = self.__get_bootfile() + except: + return [] + try: + self.__bootfile_lock.acquire() + grub_fd = open(boot_file) + for line in grub_fd: + if self.title_re.match(line): + line = line.rstrip().lstrip() + titles.append(line.lstrip('title').lstrip()) + finally: + self.__bootfile_lock.release() + return titles + + + def get_default_title(self): + """ Get the index (starting with 0) of the default boot title + This number is read from the grub configuration file. + In case of an error '-1' is returned + @rtype: int + @return: the index of the default boot title + """ + def_re = re.compile("default", re.IGNORECASE) + default = None + try: + boot_file = self.__get_bootfile() + except: + return default + try: + self.__bootfile_lock.acquire() + grub_fd = open(boot_file) + for line in grub_fd: + line = line.rstrip() + if def_re.match(line): + line = line.rstrip() + line = line.lstrip("default=") + default = int(line) + break + finally: + self.__bootfile_lock.release() + return default + + + def get_boot_policies(self): + """ Get a dictionary of policies that the system is booting with. + @rtype: dict + @return: dictionary of boot titles where the keys are the + indices of the boot titles + """ + policies = {} + within_title = 0 + idx = -1 + try: + boot_file = self.__get_bootfile() + except: + return policies + try: + self.__bootfile_lock.acquire() + + grub_fd = open(boot_file) + for line in grub_fd: + if self.title_re.match(line): + within_title = 1 + idx = idx + 1 + if within_title and self.module_re.match(line): + if self.policy_re.match(line): + start = line.find("module") + pol = line[start+6:] + pol = pol.lstrip().rstrip() + if pol[0] == '/': + pol = pol[1:] + if pol[0:5] == "boot/": + pol = pol[5:] + policies[idx] = pol + finally: + self.__bootfile_lock.release() + return policies + + + def add_boot_policy(self, index, binpolname): + """ Add the binary policy for automatic loading when + booting the system. Add it to the boot title at index + 'index'. + """ + ctr = 0 + module_line = "" + within_title = 0 + found = False + try: + boot_file = self.__get_bootfile() + except: + return False + try: + self.__bootfile_lock.acquire() + grub_fd = open(boot_file) + (tmp_fd, tmp_grub) = tempfile.mkstemp() + for line in grub_fd: + if self.title_re.match(line): + if module_line != "" and not found: + os.write(tmp_fd, module_line) + found = True + + if ctr == index: + within_title = 1 + else: + within_title = 0 + ctr = ctr + 1 + elif within_title and self.module_re.match(line): + start = line.find("module") + l = line[start+6:len(line)] + l = l.lstrip() + if l[0] == '/': + prefix = "/" + else: + prefix = "" + prefix = get_prefix() + module_line = "\tmodule %s%s\n" % (prefix,binpolname) + else: + if module_line != "" and not found: + os.write(tmp_fd, module_line) + found = True + + os.write(tmp_fd, line) + + if module_line != "" and not found: + os.write(tmp_fd, module_line) + found = True + + shutil.move(boot_file, boot_file+"_save") + shutil.copyfile(tmp_grub, boot_file) + os.close(tmp_fd) + try: + os.remove(tmp_grub) + except: + pass + finally: + self.__bootfile_lock.release() + return found + + + def rm_policy_from_boottitle(self, index, unamelist): + """ Remove a policy from the given title. A list of possible policies + must be given to detect what module to remove + """ + found = False + ctr = 0 + within_title = 0 + + prefix = get_prefix() + namelist = [prefix+name for name in unamelist] + + try: + boot_file = self.__get_bootfile() + except: + return False + try: + self.__bootfile_lock.acquire() + + grub_fd = open(boot_file) + (tmp_fd, tmp_grub) = tempfile.mkstemp() + for line in grub_fd: + omit_line = False + if self.title_re.match(line): + if ctr == index: + within_title = 1 + else: + within_title = 0 + ctr = ctr + 1 + if within_title and self.module_re.match(line): + if self.policy_re.match(line): + start = line.find("module") + pol = line[start+6:len(line)] + pol = pol.lstrip().rstrip() + if pol in namelist: + omit_line = True + found = True + if not omit_line: + os.write(tmp_fd, line) + if found: + shutil.move(boot_file, boot_file+"_save") + shutil.copyfile(tmp_grub, boot_file) + os.close(tmp_fd) + try: + os.remove(tmp_grub) + except: + pass + finally: + self.__bootfile_lock.release() + return found + + + def set_kernel_attval(self, index, att, val): + """ + Append an attribut/value pair to the kernel line. + @param index : The index of the title to modify + @param att : The attribute to add + @param val : The value to add. If no value or the special value + '<>' is given, then the attribute will be removed. + If an empty value is given, then only the attribute + is added in the format "att", otherwise "att=val" + is added. + """ + found = False + ctr = 0 + within_title = 0 + try: + boot_file = self.__get_bootfile() + except: + False + try: + self.__bootfile_lock.acquire() + + grub_fd = open(boot_file) + (tmp_fd, tmp_grub) = tempfile.mkstemp() + for line in grub_fd: + if self.title_re.match(line): + if ctr == index: + within_title = 1 + else: + within_title = 0 + ctr = ctr + 1 + if within_title and self.kernel_re.match(line): + nitems = [] + items = line.split(" ") + i = 0 + while i < len(items): + el = items[i].split("=",1) + if el[0] != att: + nitems.append(items[i].rstrip("\n")) + i += 1 + if val == "": + nitems.append("%s" % (att)) + elif val != None and val != "<>": + nitems.append("%s=%s" % (att,val)) + line = " ".join(nitems) + "\n" + os.write(tmp_fd, line) + shutil.move(boot_file, boot_file+"_save") + shutil.copyfile(tmp_grub, boot_file) + os.close(tmp_fd) + try: + os.remove(tmp_grub) + except: + pass + finally: + self.__bootfile_lock.release() + return found + + + def get_kernel_val(self, index, att): + """ + Get an attribute's value from the kernel line. + @param index : The index of the title to get the attribute/value from + @param att : The attribute to read the value of + """ + ctr = 0 + within_title = 0 + try: + boot_file = self.__get_bootfile() + except: + return None + try: + self.__bootfile_lock.acquire() + + grub_fd = open(boot_file) + for line in grub_fd: + if self.title_re.match(line): + if ctr == index: + within_title = 1 + else: + within_title = 0 + ctr = ctr + 1 + if within_title and self.kernel_re.match(line): + line = line.rstrip().lstrip() + items = line.split(" ") + i = 0 + while i < len(items): + el = items[i].split("=",1) + if el[0] == att: + if len(el) == 1: + return "<>" + return el[1] + i += 1 + finally: + self.__bootfile_lock.release() + return None # Not found + + +__bootloader = Bootloader() + +grub = Grub() +if grub.probe() == True: + __bootloader = grub diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/util/security.py --- a/tools/python/xen/util/security.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/util/security.py Tue Jul 10 08:39:26 2007 -0600 @@ -15,17 +15,22 @@ # Copyright (C) 2006 International Business Machines Corp. # Author: Reiner Sailer # Author: Bryan D. Payne <bdpayne@xxxxxxxxxx> +# Author: Stefan Berger <stefanb@xxxxxxxxxx> #============================================================================ import commands import logging -import sys, os, string, re -import traceback -import shutil +import os, string, re +import threading +import struct +import stat from xen.lowlevel import acm from xen.xend import sxp +from xen.xend import XendConstants from xen.xend.XendLogging import log -from xen.util import dictio +from xen.xend.XendError import VmError +from xen.util import dictio, xsconstants +from xen.xend.XendConstants import * #global directories and tools for security management policy_dir_prefix = "/etc/xen/acm-security/policies" @@ -60,6 +65,10 @@ policy_name_re = re.compile(".*[chwall|s #other global variables NULL_SSIDREF = 0 +#general Rlock for map files; only one lock for all mapfiles +__mapfile_lock = threading.RLock() +__resfile_lock = threading.RLock() + log = logging.getLogger("xend.util.security") # Our own exception definition. It is masked (pass) if raised and @@ -75,12 +84,18 @@ def err(msg): def err(msg): """Raise ACM exception. """ - sys.stderr.write("ACMError: " + msg + "\n") raise ACMError(msg) active_policy = None + + +def mapfile_lock(): + __mapfile_lock.acquire() + +def mapfile_unlock(): + __mapfile_lock.release() def refresh_security_policy(): @@ -106,6 +121,39 @@ def on(): return (active_policy not in ['INACTIVE', 'NULL']) +def calc_dom_ssidref_from_info(info): + """ + Calculate a domain's ssidref from the security_label in its + info. + This function is called before the domain is started and + makes sure that: + - the type of the policy is the same as indicated in the label + - the name of the policy is the same as indicated in the label + - calculates an up-to-date ssidref for the domain + The latter is necessary since the domain's ssidref could have + changed due to changes to the policy. + """ + import xen.xend.XendConfig + if isinstance(info, xen.xend.XendConfig.XendConfig): + if info.has_key('security_label'): + seclab = info['security_label'] + tmp = seclab.split(":") + if len(tmp) != 3: + raise VmError("VM label '%s' in wrong format." % seclab) + typ, policyname, vmlabel = seclab.split(":") + if typ != xsconstants.ACM_POLICY_ID: + raise VmError("Policy type '%s' not supported." % typ) + refresh_security_policy() + if active_policy != policyname: + raise VmError("Active policy '%s' different than " + "what in VM's label ('%s')." % + (active_policy, policyname)) + ssidref = label2ssidref(vmlabel, policyname, "dom") + return ssidref + else: + return 0 + raise VmError("security.calc_dom_ssidref_from_info: info of type '%s'" + "not supported." % type(info)) # Assumes a 'security' info [security access_control ...] [ssidref ...] def get_security_info(info, field): @@ -144,7 +192,6 @@ def get_security_info(info, field): return 0 else: return None - def get_security_printlabel(info): @@ -250,32 +297,37 @@ def ssidref2label(ssidref_var): else: err("Instance type of ssidref not supported (must be of type 'str' or 'int')") - (primary, secondary, f, pol_exists) = getmapfile(None) - if not f: - if (pol_exists): - err("Mapping file for policy \'" + policyname + "\' not found.\n" + - "Please use makepolicy command to create mapping file!") - else: - err("Policy file for \'" + active_policy + "\' not found.") - - #2. get labelnames for both ssidref parts - pri_ssid = ssidref & 0xffff - sec_ssid = ssidref >> 16 - pri_null_ssid = NULL_SSIDREF & 0xffff - sec_null_ssid = NULL_SSIDREF >> 16 - pri_labels = [] - sec_labels = [] - labels = [] - - for line in f: - l = line.split() - if (len(l) < 5) or (l[0] != "LABEL->SSID"): - continue - if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid): - pri_labels.append(l[3]) - if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid): - sec_labels.append(l[3]) - f.close() + try: + mapfile_lock() + + (primary, secondary, f, pol_exists) = getmapfile(None) + if not f: + if (pol_exists): + err("Mapping file for policy not found.\n" + + "Please use makepolicy command to create mapping file!") + else: + err("Policy file for \'" + active_policy + "\' not found.") + + #2. get labelnames for both ssidref parts + pri_ssid = ssidref & 0xffff + sec_ssid = ssidref >> 16 + pri_null_ssid = NULL_SSIDREF & 0xffff + sec_null_ssid = NULL_SSIDREF >> 16 + pri_labels = [] + sec_labels = [] + labels = [] + + for line in f: + l = line.split() + if (len(l) < 5) or (l[0] != "LABEL->SSID"): + continue + if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid): + pri_labels.append(l[3]) + if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid): + sec_labels.append(l[3]) + f.close() + finally: + mapfile_unlock() #3. get the label that is in both lists (combination must be a single label) if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != sec_null_ssid): @@ -297,7 +349,7 @@ def ssidref2label(ssidref_var): -def label2ssidref(labelname, policyname, type): +def label2ssidref(labelname, policyname, typ): """ returns ssidref corresponding to labelname; maps current policy to default directory @@ -307,42 +359,51 @@ def label2ssidref(labelname, policyname, err("Cannot translate labels for \'" + policyname + "\' policy.") allowed_types = ['ANY'] - if type == 'dom': + if typ == 'dom': allowed_types.append('VM') - elif type == 'res': + elif typ == 'res': allowed_types.append('RES') else: err("Invalid type. Must specify 'dom' or 'res'.") - (primary, secondary, f, pol_exists) = getmapfile(policyname) - - #2. get labelnames for ssidref parts and find a common label - pri_ssid = [] - sec_ssid = [] - for line in f: - l = line.split() - if (len(l) < 5) or (l[0] != "LABEL->SSID"): - continue - if primary and (l[1] in allowed_types) and (l[2] == primary) and (l[3] == labelname): - pri_ssid.append(int(l[4], 16)) - if secondary and (l[1] in allowed_types) and (l[2] == secondary) and (l[3] == labelname): - sec_ssid.append(int(l[4], 16)) - f.close() - if (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0): - pri_ssid.append(NULL_SSIDREF) - elif (type == 'res') and (secondary == "CHWALL") and (len(sec_ssid) == 0): - sec_ssid.append(NULL_SSIDREF) - - #3. sanity check and composition of ssidref - if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and (secondary != "NULL")): - err("Label \'" + labelname + "\' not found.") - elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1): - err("Label \'" + labelname + "\' not unique in policy (policy error)") - if secondary == "NULL": - return pri_ssid[0] - else: - return (sec_ssid[0] << 16) | pri_ssid[0] - + try: + mapfile_lock() + (primary, secondary, f, pol_exists) = getmapfile(policyname) + + #2. get labelnames for ssidref parts and find a common label + pri_ssid = [] + sec_ssid = [] + for line in f: + l = line.split() + if (len(l) < 5) or (l[0] != "LABEL->SSID"): + continue + if primary and (l[1] in allowed_types) and \ + (l[2] == primary) and \ + (l[3] == labelname): + pri_ssid.append(int(l[4], 16)) + if secondary and (l[1] in allowed_types) and \ + (l[2] == secondary) and \ + (l[3] == labelname): + sec_ssid.append(int(l[4], 16)) + f.close() + if (typ == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0): + pri_ssid.append(NULL_SSIDREF) + elif (typ == 'res') and (secondary == "CHWALL") and \ + (len(sec_ssid) == 0): + sec_ssid.append(NULL_SSIDREF) + + #3. sanity check and composition of ssidref + if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and \ + (secondary != "NULL")): + err("Label \'" + labelname + "\' not found.") + elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1): + err("Label \'" + labelname + "\' not unique in policy (policy error)") + if secondary == "NULL": + return pri_ssid[0] + else: + return (sec_ssid[0] << 16) | pri_ssid[0] + finally: + mapfile_unlock() def refresh_ssidref(config): @@ -381,8 +442,9 @@ def refresh_ssidref(config): err("Illegal field in access_control") #verify policy is correct if active_policy != policyname: - err("Policy \'" + policyname + "\' in label does not match active policy \'" - + active_policy +"\'!") + err("Policy \'" + str(policyname) + + "\' in label does not match active policy \'" + + str(active_policy) +"\'!") new_ssidref = label2ssidref(labelname, policyname, 'dom') if not new_ssidref: @@ -470,6 +532,25 @@ def get_decision(arg1, arg2): err("Cannot determine decision (Invalid parameter).") +def hv_chg_policy(bin_pol, del_array, chg_array): + """ + Change the binary policy in the hypervisor + The 'del_array' and 'chg_array' give hints about deleted ssidrefs + and changed ssidrefs which can be due to deleted VM labels + or reordered VM labels + """ + rc = -xsconstants.XSERR_GENERAL_FAILURE + errors = "" + if not on(): + err("No policy active.") + try: + rc, errors = acm.chgpolicy(bin_pol, del_array, chg_array) + except Exception, e: + pass + if (len(errors) > 0): + rc = -xsconstants.XSERR_HV_OP_FAILED + return rc, errors + def make_policy(policy_name): policy_file = string.join(string.split(policy_name, "."), "/") @@ -479,8 +560,6 @@ def make_policy(policy_name): (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file) if ret: err("Creating policy failed:\n" + output) - - def load_policy(policy_name): global active_policy @@ -538,8 +617,8 @@ def list_labels(policy_name, condition): def get_res_label(resource): - """Returns resource label information (label, policy) if it exists. - Otherwise returns null label and policy. + """Returns resource label information (policytype, label, policy) if + it exists. Otherwise returns null label and policy. """ def default_res_label(): ssidref = NULL_SSIDREF @@ -547,23 +626,19 @@ def get_res_label(resource): label = ssidref2label(ssidref) else: label = None - return (label, 'NULL') - - (label, policy) = default_res_label() - - # load the resource label file - res_label_cache = {} - try: - res_label_cache = dictio.dict_read("resources", res_label_filename) - except: - log.info("Resource label file not found.") - return default_res_label() - - # find the resource information - if res_label_cache.has_key(resource): - (policy, label) = res_label_cache[resource] - - return (label, policy) + return (xsconstants.ACM_POLICY_ID, 'NULL', label) + + + tmp = get_resource_label(resource) + if len(tmp) == 2: + policytype = xsconstants.ACM_POLICY_ID + policy, label = tmp + elif len(tmp) == 3: + policytype, policy, label = tmp + else: + policytype, policy, label = default_res_label() + + return (policytype, label, policy) def get_res_security_details(resource): @@ -582,7 +657,7 @@ def get_res_security_details(resource): (label, ssidref, policy) = default_security_details() # find the entry associated with this resource - (label, policy) = get_res_label(resource) + (policytype, label, policy) = get_res_label(resource) if policy == 'NULL': log.info("Resource label for "+resource+" not in file, using DEFAULT.") return default_security_details() @@ -596,8 +671,29 @@ def get_res_security_details(resource): return (label, ssidref, policy) - -def unify_resname(resource): +def security_label_to_details(seclab): + """ Convert a Xen-API type of security label into details """ + def default_security_details(): + ssidref = NULL_SSIDREF + if on(): + label = ssidref2label(ssidref) + else: + label = None + policy = active_policy + return (label, ssidref, policy) + + (policytype, policy, label) = seclab.split(":") + + # is this resource label for the running policy? + if policy == active_policy: + ssidref = label2ssidref(label, policy, 'res') + else: + log.info("Resource label not for active policy, using DEFAULT.") + return default_security_details() + + return (label, ssidref, policy) + +def unify_resname(resource, mustexist=True): """Makes all resource locations absolute. In case of physical resources, '/dev/' is added to local file names""" @@ -606,28 +702,53 @@ def unify_resname(resource): # sanity check on resource name try: - (type, resfile) = resource.split(":", 1) + (typ, resfile) = resource.split(":", 1) except: err("Resource spec '%s' contains no ':' delimiter" % resource) - if type == "tap": + if typ == "tap": try: (subtype, resfile) = resfile.split(":") except: err("Resource spec '%s' contains no tap subtype" % resource) - if type in ["phy", "tap"]: + import os + if typ in ["phy", "tap"]: if not resfile.startswith("/"): resfile = "/dev/" + resfile + if mustexist: + stats = os.lstat(resfile) + if stat.S_ISLNK(stats[stat.ST_MODE]): + resolved = os.readlink(resfile) + if resolved[0] != "/": + resfile = os.path.join(os.path.dirname(resfile), resolved) + resfile = os.path.abspath(resfile) + else: + resfile = resolved + stats = os.lstat(resfile) + if not (stat.S_ISBLK(stats[stat.ST_MODE])): + err("Invalid resource") + + if typ in [ "file", "tap" ]: + if mustexist: + stats = os.lstat(resfile) + if stat.S_ISLNK(stats[stat.ST_MODE]): + resfile = os.readlink(resfile) + stats = os.lstat(resfile) + if not stat.S_ISREG(stats[stat.ST_MODE]): + err("Invalid resource") #file: resources must specified with absolute path - if (not resfile.startswith("/")) or (not os.path.exists(resfile)): - err("Invalid resource.") + #vlan resources don't start with '/' + if typ != "vlan": + if (not resfile.startswith("/")) or \ + (mustexist and not os.path.exists(resfile)): + err("Invalid resource.") # from here on absolute file names with resources - if type == "tap": - type = type + ":" + subtype - resource = type + ":" + resfile + if typ == "tap": + typ = typ + ":" + subtype + resource = typ + ":" + resfile return resource @@ -662,9 +783,481 @@ def res_security_check(resource, domain_ else: # Note, we can't canonicalise the resource here, because people using # xm without ACM are free to use relative paths. - (label, policy) = get_res_label(resource) + (policytype, label, policy) = get_res_label(resource) if policy != 'NULL': raise ACMError("Security is off, but '"+resource+"' is labeled") rtnval = 0 return rtnval + +def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label): + """Checks if the given resource can be used by the given domain + label. Returns 1 if the resource can be used, otherwise 0. + """ + rtnval = 1 + # if security is on, ask the hypervisor for a decision + if on(): + typ, dpolicy, domain_label = xapi_dom_label.split(":") + if not dpolicy or not domain_label: + raise VmError("VM security label in wrong format.") + if active_policy != rpolicy: + raise VmError("Resource's policy '%s' != active policy '%s'" % + (rpolicy, active_policy)) + domac = ['access_control'] + domac.append(['policy', active_policy]) + domac.append(['label', domain_label]) + domac.append(['type', 'dom']) + decision = get_decision(domac, ['ssidref', str(rssidref)]) + + log.info("Access Control Decision : %s" % decision) + # provide descriptive error messages + if decision == 'DENIED': + if rlabel == ssidref2label(NULL_SSIDREF): + #raise ACMError("Resource is not labeled") + rtnval = 0 + else: + #raise ACMError("Permission denied for resource because label '"+rlabel+"' is not allowed") + rtnval = 0 + + # security is off, make sure resource isn't labeled + else: + # Note, we can't canonicalise the resource here, because people using + # xm without ACM are free to use relative paths. + if rpolicy != 'NULL': + #raise ACMError("Security is off, but resource is labeled") + rtnval = 0 + + return rtnval + + +def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi): + """Assign a resource label to a resource + @param resource: The name of a resource, i.e., "phy:/dev/hda", or + "tap:qcow:/path/to/file.qcow" + + @param reslabel_xapi: A resource label foramtted as in all other parts of + the Xen-API, i.e., ACM:xm-test:blue" + @rtype: int + @return Success (0) or failure value (< 0) + """ + olabel = "" + if reslabel_xapi == "": + return rm_resource_label(resource, oldlabel_xapi) + typ, policyref, label = reslabel_xapi.split(":") + if typ != xsconstants.ACM_POLICY_ID: + return -xsconstants.XSERR_WRONG_POLICY_TYPE + if not policyref or not label: + return -xsconstants.XSERR_BAD_LABEL_FORMAT + if oldlabel_xapi not in [ "" ]: + tmp = oldlabel_xapi.split(":") + if len(tmp) != 3: + return -xsconstants.XSERR_BAD_LABEL_FORMAT + otyp, opolicyref, olabel = tmp + # Only ACM is supported + if otyp != xsconstants.ACM_POLICY_ID: + return -xsconstants.XSERR_WRONG_POLICY_TYPE + return set_resource_label(resource, typ, policyref, label, olabel) + +def is_resource_in_use(resource): + """ Investigate all running domains whether they use this device """ + from xen.xend import XendDomain + dominfos = XendDomain.instance().list('all') + lst = [] + for dominfo in dominfos: + if is_resource_in_use_by_dom(dominfo, resource): + lst.append(dominfo) + return lst + +def devices_equal(res1, res2): + """ Determine whether two devices are equal """ + return (unify_resname(res1) == unify_resname(res2)) + +def is_resource_in_use_by_dom(dominfo, resource): + """ Determine whether a resources is in use by a given domain + @return True or False + """ + if not dominfo.domid: + return False + if dominfo._stateGet() not in [ DOM_STATE_RUNNING ]: + return False + devs = dominfo.info['devices'] + uuids = devs.keys() + for uuid in uuids: + dev = devs[uuid] + if len(dev) >= 2 and dev[1].has_key('uname'): + # dev[0] is type, i.e. 'vbd' + if devices_equal(dev[1]['uname'], resource): + log.info("RESOURCE IN USE: Domain %d uses %s." % + (dominfo.domid, resource)) + return True + return False + + +def get_domain_resources(dominfo): + """ Collect all resources of a domain in a map where each entry of + the map is a list. + Entries are strored in the following formats: + tap:qcow:/path/xyz.qcow + """ + resources = { 'vbd' : [], 'tap' : []} + devs = dominfo.info['devices'] + uuids = devs.keys() + for uuid in uuids: + dev = devs[uuid] + typ = dev[0] + if typ in [ 'vbd', 'tap' ]: + resources[typ].append(dev[1]['uname']) + + return resources + + +def resources_compatible_with_vmlabel(xspol, dominfo, vmlabel): + """ + Check whether the resources' labels are compatible with the + given VM label. This is a function to be used when for example + a running domain is to get the new label 'vmlabel' + """ + if not xspol: + return False + + try: + __resfile_lock.acquire() + try: + access_control = dictio.dict_read("resources", + res_label_filename) + except: + return False + return __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel, + access_control) + finally: + __resfile_lock.release() + return False + + +def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel, + access_control): + """ + Check whether the resources' labels are compatible with the + given VM label. The access_control parameter provides a + dictionary of the resource name to resource label mappings + under which the evaluation should be done. + """ + resources = get_domain_resources(dominfo) + reslabels = [] # all resource labels + polname = xspol.get_name() + for key in resources.keys(): + for res in resources[key]: + try: + tmp = access_control[res] + if len(tmp) != 3: + return False + + if polname != tmp[1]: + return False + label = tmp[2] + if not label in reslabels: + reslabels.append(label) + except: + return False + # Check that all resource labes have a common STE type with the + # vmlabel + rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels) + return rc; + +def set_resource_label(resource, policytype, policyref, reslabel, \ + oreslabel = None): + """Assign a label to a resource + If the old label (oreslabel) is given, then the resource must have + that old label. + A resource label may be changed if + - the resource is not in use + @param resource : The name of a resource, i.e., "phy:/dev/hda" + @param policyref : The name of the policy + @param reslabel : the resource label within the policy + @param oreslabel : optional current resource label + + @rtype: int + @return Success (0) or failure value (< 0) + """ + try: + resource = unify_resname(resource, mustexist=False) + except Exception: + return -xsconstants.XSERR_BAD_RESOURCE_FORMAT + + domains = is_resource_in_use(resource) + if len(domains) > 0: + return -xsconstants.XSERR_RESOURCE_IN_USE + + try: + __resfile_lock.acquire() + access_control = {} + try: + access_control = dictio.dict_read("resources", res_label_filename) + except: + pass + if oreslabel: + if not access_control.has_key(resource): + return -xsconstants.XSERR_BAD_LABEL + tmp = access_control[resource] + if len(tmp) != 3: + return -xsconstants.XSERR_BAD_LABEL + if tmp[2] != oreslabel: + return -xsconstants.XSERR_BAD_LABEL + if reslabel != "": + new_entry = { resource : tuple([policytype, policyref, reslabel])} + access_control.update(new_entry) + else: + if access_control.has_key(resource): + del access_control[resource] + dictio.dict_write(access_control, "resources", res_label_filename) + finally: + __resfile_lock.release() + return xsconstants.XSERR_SUCCESS + +def rm_resource_label(resource, oldlabel_xapi): + """Remove a resource label from a physical resource + @param resource: The name of a resource, i.e., "phy:/dev/hda" + + @rtype: int + @return Success (0) or failure value (< 0) + """ + tmp = oldlabel_xapi.split(":") + if len(tmp) != 3: + return -xsconstants.XSERR_BAD_LABEL_FORMAT + otyp, opolicyref, olabel = tmp + # Only ACM is supported + if otyp != xsconstants.ACM_POLICY_ID and \ + otyp != xsconstants.INVALID_POLICY_PREFIX + xsconstants.ACM_POLICY_ID: + return -xsconstants.XSERR_WRONG_POLICY_TYPE + return set_resource_label(resource, "", "", "", olabel) + +def get_resource_label_xapi(resource): + """Get the assigned resource label of a physical resource + in the format used by then Xen-API, i.e., "ACM:xm-test:blue" + + @rtype: string + @return the string representing policy type, policy name and label of + the resource + """ + res = get_resource_label(resource) + return format_resource_label(res) + +def format_resource_label(res): + if res: + if len(res) == 2: + return xsconstants.ACM_POLICY_ID + ":" + res[0] + ":" + res[1] + if len(res) == 3: + return ":".join(res) + return "" + +def get_resource_label(resource): + """Get the assigned resource label of a given resource + @param resource: The name of a resource, i.e., "phy:/dev/hda" + + @rtype: list + @return tuple of (policy name, resource label), i.e., (xm-test, blue) + """ + try: + resource = unify_resname(resource, mustexist=False) + except Exception: + return [] + + reslabel_map = get_labeled_resources() + + if reslabel_map.has_key(resource): + return list(reslabel_map[resource]) + else: + #Try to resolve each label entry + for key, value in reslabel_map.items(): + try: + if resource == unify_resname(key): + return list(value) + except: + pass + + return [] + + +def get_labeled_resources_xapi(): + """ Get a map of all labeled resource with the labels formatted in the + xen-api resource label format. + """ + reslabel_map = get_labeled_resources() + for key, labeldata in reslabel_map.items(): + reslabel_map[key] = format_resource_label(labeldata) + return reslabel_map + + +def get_labeled_resources(): + """Get a map of all labeled resources + @rtype: list + @return list of labeled resources + """ + try: + __resfile_lock.acquire() + try: + access_control = dictio.dict_read("resources", res_label_filename) + except: + return {} + finally: + __resfile_lock.release() + return access_control + + +def relabel_domains(relabel_list): + """ + Relabel the given domains to have a new ssidref. + @param relabel_list: a list containing tuples of domid, ssidref + example: [ [0, 0x00020002] ] + """ + rel_rules = "" + for r in relabel_list: + log.info("Relabeling domain with domid %d to new ssidref 0x%08x", + r[0], r[1]) + rel_rules += struct.pack("ii", r[0], r[1]) + try: + rc, errors = acm.relabel_domains(rel_rules) + except Exception, e: + log.info("Error after relabel_domains: %s" % str(e)) + rc = -xsconstants.XSERR_GENERAL_FAILURE + errors = "" + if (len(errors) > 0): + rc = -xsconstants.XSERR_HV_OP_FAILED + return rc, errors + + +def change_acm_policy(bin_pol, del_array, chg_array, + vmlabel_map, reslabel_map, cur_acmpol, new_acmpol): + """ + Change the ACM policy of the system by relabeling + domains and resources first and doing some access checks. + Then update the policy in the hypervisor. If this is all successful, + relabel the domains permanently and commit the relabed resources. + + Need to do / check the following: + - relabel all resources where there is a 'from' field in + the policy. [ NOT DOING THIS: and mark those as unlabeled where the label + does not appear in the new policy anymore (deletion) ] + - relabel all VMs where there is a 'from' field in the + policy and mark those as unlabeled where the label + does not appear in the new policy anymore; no running + or paused VM may be unlabeled through this + - check that under the new labeling conditions the VMs + still have access to their resources as before. Unlabeled + resources are inaccessible. If this check fails, the + update failed. + - Attempt changes in the hypervisor; if this step fails, + roll back the relabeling of resources and VMs + - Make the relabeling of resources and VMs permanent + """ + rc = xsconstants.XSERR_SUCCESS + + domain_label_map = {} + new_policyname = new_acmpol.get_name() + new_policytype = new_acmpol.get_type_name() + cur_policyname = cur_acmpol.get_name() + cur_policytype = cur_acmpol.get_type_name() + polnew_reslabels = new_acmpol.policy_get_resourcelabel_names() + errors="" + + try: + __resfile_lock.acquire() + mapfile_lock() + + # Get all domains' dominfo. + from xen.xend import XendDomain + dominfos = XendDomain.instance().list('all') + + log.info("----------------------------------------------") + # relabel resources + + access_control = {} + try: + access_control = dictio.dict_read("resources", res_label_filename) + finally: + pass + for key, labeldata in access_control.items(): + if len(labeldata) == 2: + policy, label = labeldata + policytype = xsconstants.ACM_POLICY_ID + elif len(labeldata) == 3: + policytype, policy, label = labeldata + else: + return -xsconstants.XSERR_BAD_LABEL_FORMAT, "" + + if policytype != cur_policytype or \ + policy != cur_policyname: + continue + + # label been renamed or deleted? + if reslabel_map.has_key(label) and cur_policyname == policy: + label = reslabel_map[label] + elif label not in polnew_reslabels: + policytype = xsconstants.INVALID_POLICY_PREFIX + policytype + # Update entry + access_control[key] = \ + tuple([ policytype, new_policyname, label ]) + + # All resources have new labels in the access_control map + # There may still be labels in there that are invalid now. + + # Do this in memory without writing to disk: + # - Relabel all domains independent of whether they are running + # or not + # - later write back to config files + polnew_vmlabels = new_acmpol.policy_get_virtualmachinelabel_names() + + for dominfo in dominfos: + sec_lab = dominfo.get_security_label() + if not sec_lab: + continue + policytype, policy, vmlabel = sec_lab.split(":") + name = dominfo.getName() + + if policytype != cur_policytype or \ + policy != cur_policyname: + continue + + new_vmlabel = vmlabel + if vmlabel_map.has_key(vmlabel): + new_vmlabel = vmlabel_map[vmlabel] + if new_vmlabel not in polnew_vmlabels: + policytype = xsconstants.INVALID_POLICY_PREFIX + policytype + new_seclab = "%s:%s:%s" % \ + (policytype, new_policyname, new_vmlabel) + + domain_label_map[dominfo] = [ sec_lab, new_seclab ] + + if dominfo._stateGet() in (DOM_STATE_PAUSED, DOM_STATE_RUNNING): + compatible = __resources_compatible_with_vmlabel(new_acmpol, + dominfo, + new_vmlabel, + access_control) + log.info("Domain %s with new label '%s' can access its " + "resources? : %s" % + (name, new_vmlabel, str(compatible))) + log.info("VM labels in new domain: %s" % + new_acmpol.policy_get_virtualmachinelabel_names()) + if not compatible: + return (-xsconstants.XSERR_RESOURCE_ACCESS, "") + + rc, errors = hv_chg_policy(bin_pol, del_array, chg_array) + if rc == 0: + # Write the relabeled resources back into the file + dictio.dict_write(access_control, "resources", res_label_filename) + # Properly update all VMs to their new labels + for dominfo, labels in domain_label_map.items(): + sec_lab, new_seclab = labels + if sec_lab != new_seclab: + log.info("Updating domain %s to new label '%s'." % \ + (new_seclab, sec_lab)) + # This better be working! + dominfo.set_security_label(new_seclab, + sec_lab, + new_acmpol) + finally: + log.info("----------------------------------------------") + mapfile_unlock() + __resfile_lock.release() + + return rc, errors diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/util/xsconstants.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/util/xsconstants.py Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,104 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2007 International Business Machines Corp. +# Author: Stefan Berger <stefanb@xxxxxxxxxx> +#============================================================================ + +XS_INST_NONE = 0 +XS_INST_BOOT = (1 << 0) +XS_INST_LOAD = (1 << 1) + +XS_POLICY_NONE = 0 +XS_POLICY_ACM = (1 << 0) + +# Some internal variables used by the Xen-API +ACM_LABEL_VM = (1 << 0) +ACM_LABEL_RES = (1 << 1) + +# Base for XS error codes for collision avoidance with other error codes +XSERR_BASE = 0x1000 + +# XS error codes as used by the Xen-API +XSERR_SUCCESS = 0 +XSERR_GENERAL_FAILURE = 1 + XSERR_BASE +XSERR_BAD_XML = 2 + XSERR_BASE # XML is wrong (not according to schema) +XSERR_XML_PROCESSING = 3 + XSERR_BASE +XSERR_POLICY_INCONSISTENT = 4 + XSERR_BASE # i.e., bootstrap name not a VM label +XSERR_FILE_ERROR = 5 + XSERR_BASE +XSERR_BAD_RESOURCE_FORMAT = 6 + XSERR_BASE # badly formatted resource +XSERR_BAD_LABEL_FORMAT = 7 + XSERR_BASE +XSERR_RESOURCE_NOT_LABELED = 8 + XSERR_BASE +XSERR_RESOURCE_ALREADY_LABELED = 9 + XSERR_BASE +XSERR_WRONG_POLICY_TYPE = 10 + XSERR_BASE +XSERR_BOOTPOLICY_INSTALLED = 11 + XSERR_BASE +XSERR_NO_DEFAULT_BOOT_TITLE = 12 + XSERR_BASE +XSERR_POLICY_LOAD_FAILED = 13 + XSERR_BASE +XSERR_POLICY_LOADED = 14 + XSERR_BASE +XSERR_POLICY_TYPE_UNSUPPORTED = 15 + XSERR_BASE +XSERR_BAD_CONFLICTSET = 16 + XSERR_BASE +XSERR_RESOURCE_IN_USE = 17 + XSERR_BASE +XSERR_BAD_POLICY_NAME = 18 + XSERR_BASE +XSERR_VERSION_PREVENTS_UPDATE = 19 + XSERR_BASE +XSERR_BAD_LABEL = 20 + XSERR_BASE +XSERR_VM_WRONG_STATE = 21 + XSERR_BASE +XSERR_POLICY_NOT_LOADED = 22 + XSERR_BASE +XSERR_RESOURCE_ACCESS = 23 + XSERR_BASE +XSERR_HV_OP_FAILED = 24 + XSERR_BASE +XSERR_BOOTPOLICY_INSTALL_ERROR = 25 + XSERR_BASE +XSERR_LAST = 25 + XSERR_BASE ## KEEP LAST + +XSERR_MESSAGES = [ + '', + 'General Failure', + 'XML is malformed', + 'Error while processing XML', + 'Policy has inconsistencies', + 'A file access error occurred', + 'The resource format is not valid', + 'The label format is not valid', + 'The resource is not labeld', + 'The resource is already labeld', + 'The policy type is wrong', + 'The system boot policy is installed', + 'Could not find the default boot title', + 'Loading of the policy failed', + 'The policy is loaded', + 'The policy type is unsupported', + 'There is a bad conflict set', + 'The resource is in use', + 'The policy has an invalid name', + 'The version of the policy prevents an update', + 'The label is bad', + 'Operation not premittend - the VM is in the wrong state', + 'The policy is not loaded', + 'Error accessing resource', + 'Operation failed in hypervisor', + 'Boot policy installation error' +] + +def xserr2string(err): + if err == XSERR_SUCCESS: + return "Success" + if err >= XSERR_GENERAL_FAILURE and \ + err <= XSERR_LAST: + return XSERR_MESSAGES[err - XSERR_BASE] + return "Unknown XSERR code '%s'." % (hex(err)) + +# Policy identifiers used in labels +ACM_POLICY_ID = "ACM" + +INVALID_POLICY_PREFIX = "INV_" + +INVALID_SSIDREF = 0xFFFFFFFF diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/util/xspolicy.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/util/xspolicy.py Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,66 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006,2007 International Business Machines Corp. +# Author: Stefan Berger <stefanb@xxxxxxxxxx> +#============================================================================ + +import threading +import xsconstants + +class XSPolicy: + """ + The base policy class for all policies administered through + XSPolicyAdmin. + """ + + def __init__(self, name=None, ref=None): + self.lock = threading.Lock() + self.ref = ref + self.name = name + if ref: + from xen.xend.XendXSPolicy import XendXSPolicy + self.xendxspolicy = XendXSPolicy(self, {}, ref) + else: + self.xendxspolicy = None + + def grab_lock(self): + self.lock.acquire() + + def unlock(self): + self.lock.release() + + def get_ref(self): + return self.ref + + def destroy(self): + if self.xendxspolicy: + self.xendxspolicy.destroy() + + # All methods below should be overwritten by the inheriting class + + def isloaded(self): + return False + + def loadintohv(self): + return xsconstants.XSERR_POLICY_LOAD_FAILED + + def get_type(self): + return xsconstants.XS_POLICY_NONE + + def get_type_name(self): + return "" + + def update(self, repr_new): + return -xsconstants.XSERR_GENERAL_FAILURE, "" diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendAPI.py --- a/tools/python/xen/xend/XendAPI.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendAPI.py Tue Jul 10 08:39:26 2007 -0600 @@ -40,11 +40,13 @@ from XendVMMetrics import XendVMMetrics from XendVMMetrics import XendVMMetrics from XendPIF import XendPIF from XendPBD import XendPBD +from XendXSPolicy import XendXSPolicy, XendACMPolicy from XendAPIConstants import * from xen.util.xmlrpclib2 import stringify from xen.util.blkif import blkdev_name_to_number +from xen.util import xsconstants AUTH_NONE = 'none' @@ -467,6 +469,8 @@ classes = { 'console' : valid_console, 'SR' : valid_sr, 'task' : valid_task, + 'XSPolicy' : valid_object("XSPolicy"), + 'ACMPolicy' : valid_object("ACMPolicy"), 'debug' : valid_debug, 'network' : valid_object("network"), 'PIF' : valid_object("PIF"), @@ -481,6 +485,8 @@ autoplug_classes = { 'VM_metrics' : XendVMMetrics, 'PBD' : XendPBD, 'PIF_metrics' : XendPIFMetrics, + 'XSPolicy' : XendXSPolicy, + 'ACMPolicy' : XendACMPolicy, } class XendAPI(object): @@ -1170,7 +1176,8 @@ class XendAPI(object): 'HVM_boot_params', 'platform', 'PCI_bus', - 'other_config'] + 'other_config', + 'security_label'] VM_methods = [('clone', 'VM'), ('start', None), @@ -1230,7 +1237,8 @@ class XendAPI(object): 'HVM_boot_params', 'platform', 'PCI_bus', - 'other_config'] + 'other_config', + 'security_label'] def VM_get(self, name, session, vm_ref): return xen_api_success( @@ -1601,7 +1609,22 @@ class XendAPI(object): if dom: return xen_api_success([dom.get_uuid()]) return xen_api_success([]) - + + def VM_get_security_label(self, session, vm_ref): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + label = dom.get_security_label() + return xen_api_success(label) + + def VM_set_security_label(self, session, vm_ref, sec_label, old_label): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + (rc, errors, oldlabel, new_ssidref) = \ + dom.set_security_label(sec_label, old_label) + if rc != xsconstants.XSERR_SUCCESS: + return xen_api_error(['SECURITY_ERROR', rc]) + if rc == 0: + rc = new_ssidref + return xen_api_success(rc) + def VM_create(self, session, vm_struct): xendom = XendDomain.instance() domuuid = XendTask.log_progress(0, 100, @@ -1655,6 +1678,7 @@ class XendAPI(object): 'domid': domid is None and -1 or domid, 'is_control_domain': xeninfo.info['is_control_domain'], 'metrics': xeninfo.get_metrics(), + 'security_label': xeninfo.get_security_label(), 'crash_dumps': [] } return xen_api_success(record) @@ -1952,7 +1976,8 @@ class XendAPI(object): 'runtime_properties'] VIF_attr_rw = ['device', 'MAC', - 'MTU'] + 'MTU', + 'security_label'] VIF_attr_inst = VIF_attr_rw @@ -2054,7 +2079,10 @@ class XendAPI(object): except Exception, exn: log.exception(exn) return xen_api_success({}) - + + def VIF_get_security_label(self, session, vif_ref): + return self._VIF_get(vif_ref, 'security_label') + # Xen API: Class VIF_metrics # ---------------------------------------------------------------- @@ -2098,7 +2126,8 @@ class XendAPI(object): 'virtual_size', 'sharable', 'read_only', - 'other_config'] + 'other_config', + 'security_label'] VDI_attr_inst = VDI_attr_ro + VDI_attr_rw VDI_methods = [('destroy', None)] @@ -2206,13 +2235,24 @@ class XendAPI(object): xennode = XendNode.instance() return xen_api_success(xennode.get_vdi_by_name_label(name)) + def VDI_set_security_label(self, session, vdi_ref, sec_lab, old_lab): + vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref) + rc = vdi.set_security_label(sec_lab, old_lab) + if rc < 0: + return xen_api_error(['SECURITY_ERROR', rc]) + return xen_api_success(rc) + + def VDI_get_security_label(self, session, vdi_ref): + vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref) + return xen_api_success(vdi.get_security_label()) # Xen API: Class VTPM # ---------------------------------------------------------------- VTPM_attr_rw = [ ] VTPM_attr_ro = ['VM', - 'backend'] + 'backend', + 'runtime_properties' ] VTPM_attr_inst = VTPM_attr_rw @@ -2289,6 +2329,18 @@ class XendAPI(object): vtpms = [d.get_vtpms() for d in XendDomain.instance().list('all')] vtpms = reduce(lambda x, y: x + y, vtpms) return xen_api_success(vtpms) + + def VTPM_get_runtime_properties(self, _, vtpm_ref): + xendom = XendDomain.instance() + dominfo = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) + device = dominfo.get_dev_config_by_uuid('vtpm', vtpm_ref) + + try: + device_sxps = dominfo.getDeviceSxprs('vtpm') + device_dict = dict(device_sxps[0][1]) + return xen_api_success(device_dict) + except: + return xen_api_success({}) # Xen API: Class console # ---------------------------------------------------------------- diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendConfig.py Tue Jul 10 08:39:26 2007 -0600 @@ -22,6 +22,7 @@ import types from xen.xend import sxp from xen.xend import uuid +from xen.xend import XendOptions from xen.xend import XendAPIStore from xen.xend.XendError import VmError from xen.xend.XendDevices import XendDevices @@ -29,6 +30,8 @@ from xen.xend.XendConstants import DOM_S from xen.xend.XendConstants import DOM_STATE_HALTED from xen.xend.server.netif import randomMAC from xen.util.blkif import blkdev_name_to_number +from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance +from xen.util import xsconstants log = logging.getLogger("xend.XendConfig") log.setLevel(logging.WARN) @@ -159,6 +162,7 @@ XENAPI_CFG_TYPES = { 'platform': dict, 'tools_version': dict, 'other_config': dict, + 'security_label': str, } # List of legacy configuration keys that have no equivalent in the @@ -167,7 +171,6 @@ LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [ LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [ # roundtripped (dynamic, unmodified) 'shadow_memory', - 'security', 'vcpu_avail', 'cpu_weight', 'cpu_cap', @@ -318,7 +321,6 @@ class XendConfig(dict): 'memory_static_max': 0, 'memory_dynamic_max': 0, 'devices': {}, - 'security': None, 'on_xend_start': 'ignore', 'on_xend_stop': 'ignore', 'cpus': [], @@ -392,6 +394,9 @@ class XendConfig(dict): def _platform_sanity_check(self): if self.is_hvm(): + if 'keymap' not in self['platform'] and XendOptions.instance().get_keymap(): + self['platform']['keymap'] = XendOptions.instance().get_keymap() + if 'device_model' not in self['platform']: self['platform']['device_model'] = DEFAULT_DM @@ -421,9 +426,10 @@ class XendConfig(dict): self._memory_sanity_check() self['cpu_time'] = dominfo['cpu_time']/1e9 - # TODO: i don't know what the security stuff expects here if dominfo.get('ssidref'): - self['security'] = [['ssidref', dominfo['ssidref']]] + ssidref = int(dominfo.get('ssidref')) + self['security_label'] = XSPolicyAdminInstance().ssidref_to_vmlabel(ssidref) + self['shutdown_reason'] = dominfo['shutdown_reason'] # parse state into Xen API states @@ -630,8 +636,26 @@ class XendConfig(dict): except ValueError, e: raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e)) - if 'security' in cfg and isinstance(cfg['security'], str): - cfg['security'] = sxp.from_string(cfg['security']) + if 'security' in cfg and not cfg.get('security_label'): + secinfo = cfg['security'] + if isinstance(secinfo, list): + # The xm command sends a list formatted like this: + # [['access_control', ['policy', 'xm-test'],['label', 'red']], + # ['ssidref', 196611]] + policy = "" + label = "" + policytype = xsconstants.ACM_POLICY_ID + for idx in range(0, len(secinfo)): + if secinfo[idx][0] == "access_control": + for aidx in range(1, len(secinfo[idx])): + if secinfo[idx][aidx][0] == "policy": + policy = secinfo[idx][aidx][1] + if secinfo[idx][aidx][0] == "label": + label = secinfo[idx][aidx][1] + if label != "" and policy != "": + cfg['security_label'] = "%s:%s:%s" % \ + (policytype, policy, label) + del cfg['security'] old_state = sxp.child_value(sxp_cfg, 'state') if old_state: @@ -774,7 +798,6 @@ class XendConfig(dict): self[sxp_arg] = val _set_cfg_if_exists('shadow_memory') - _set_cfg_if_exists('security') _set_cfg_if_exists('features') _set_cfg_if_exists('on_xend_stop') _set_cfg_if_exists('on_xend_start') @@ -886,6 +909,9 @@ class XendConfig(dict): continue if self.has_key(legacy) and self[legacy] not in (None, []): sxpr.append([legacy, self[legacy]]) + + if self.has_key('security_label'): + sxpr.append(['security_label', self['security_label']]) sxpr.append(['image', self.image_sxpr()]) sxpr.append(['status', domain._stateGet()]) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendDomain.py --- a/tools/python/xen/xend/XendDomain.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendDomain.py Tue Jul 10 08:39:26 2007 -0600 @@ -49,7 +49,7 @@ from xen.xend.XendAPIConstants import * from xen.xend.xenstore.xstransact import xstransact from xen.xend.xenstore.xswatch import xswatch -from xen.util import mkdir, security +from xen.util import mkdir from xen.xend import uuid xc = xen.lowlevel.xc.xc() @@ -486,7 +486,6 @@ class XendDomain: """ self.domains_lock.acquire() try: - security.refresh_ssidref(config) dominfo = XendDomainInfo.restore(config) return dominfo finally: @@ -1113,6 +1112,10 @@ class XendDomain: raise XendInvalidDomain(str(domid)) if dominfo.getDomid() == DOM0_ID: raise XendError("Cannot unpause privileged domain %s" % domid) + if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING): + raise VMBadState("Domain '%s' is not started" % domid, + POWER_STATE_NAMES[DOM_STATE_PAUSED], + POWER_STATE_NAMES[dominfo._stateGet()]) log.info("Domain %s (%d) unpaused.", dominfo.getName(), int(dominfo.getDomid())) dominfo.unpause() @@ -1138,6 +1141,10 @@ class XendDomain: raise XendInvalidDomain(str(domid)) if dominfo.getDomid() == DOM0_ID: raise XendError("Cannot pause privileged domain %s" % domid) + if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): + raise VMBadState("Domain '%s' is not started" % domid, + POWER_STATE_NAMES[DOM_STATE_RUNNING], + POWER_STATE_NAMES[dominfo._stateGet()]) log.info("Domain %s (%d) paused.", dominfo.getName(), int(dominfo.getDomid())) dominfo.pause() @@ -1253,7 +1260,11 @@ class XendDomain: raise XendInvalidDomain(str(domid)) if dominfo.getDomid() == DOM0_ID: - raise XendError("Cannot save privileged domain %i" % domid) + raise XendError("Cannot save privileged domain %s" % str(domid)) + if dominfo._stateGet() != DOM_STATE_RUNNING: + raise VMBadState("Domain is not running", + POWER_STATE_NAMES[DOM_STATE_RUNNING], + POWER_STATE_NAMES[dominfo._stateGet()]) oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC if hasattr(os, "O_LARGEFILE"): @@ -1399,10 +1410,15 @@ class XendDomain: dominfo = self.domain_lookup_nr(domid) if not dominfo: raise XendInvalidDomain(str(domid)) - try: - return xc.sched_credit_domain_get(dominfo.getDomid()) - except Exception, ex: - raise XendError(str(ex)) + + if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): + try: + return xc.sched_credit_domain_get(dominfo.getDomid()) + except Exception, ex: + raise XendError(str(ex)) + else: + return {'weight' : dominfo.getWeight(), + 'cap' : dominfo.getCap()} def domain_sched_credit_set(self, domid, weight = None, cap = None): """Set credit scheduler parameters for a domain. @@ -1436,12 +1452,15 @@ class XendDomain: assert type(weight) == int assert type(cap) == int - rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap) + rc = 0 + if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): + rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap) if rc == 0: if set_weight: dominfo.setWeight(weight) if set_cap: dominfo.setCap(cap) + self.managed_config_save(dominfo) return rc except Exception, ex: log.exception(ex) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendDomainInfo.py Tue Jul 10 08:39:26 2007 -0600 @@ -489,6 +489,9 @@ class XendDomainInfo: def send_sysrq(self, key): """ Send a Sysrq equivalent key via xenstored.""" + if self._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): + raise XendError("Domain '%s' is not started" % self.info['name_label']) + asserts.isCharConvertible(key) self.storeDom("control/sysrq", '%c' % key) @@ -503,9 +506,18 @@ class XendDomainInfo: dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) dev_config_dict = self.info['devices'][dev_uuid][1] log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config_dict)) - dev_config_dict['devid'] = devid = \ - self._createDevice(dev_type, dev_config_dict) - self._waitForDevice(dev_type, devid) + + if self.domid is not None: + try: + dev_config_dict['devid'] = devid = \ + self._createDevice(dev_type, dev_config_dict) + self._waitForDevice(dev_type, devid) + except VmError, ex: + raise ex + else: + devid = None + + xen.xend.XendDomain.instance().managed_config_save(self) return self.getDeviceController(dev_type).sxpr(devid) def device_configure(self, dev_sxp, devid = None): @@ -818,6 +830,9 @@ class XendDomainInfo: f('image/%s/%s' % (n, v), True) else: f('image/%s' % n, v) + + if self.info.has_key('security_label'): + f('security_label', self.info['security_label']) to_store.update(self._vcpuDomDetails()) @@ -988,9 +1003,6 @@ class XendDomainInfo: xen.xend.XendDomain.instance().managed_config_save(self) log.info("Set VCPU count on domain %s to %d", self.info['name_label'], vcpus) - - def getLabel(self): - return security.get_security_info(self.info, 'label') def getMemoryTarget(self): """Get this domain's target memory size, in KB.""" @@ -1435,11 +1447,20 @@ class XendDomainInfo: # allocation of 1MB. We free up 2MB here to be on the safe side. balloon.free(2*1024) # 2MB should be plenty - self.domid = xc.domain_create( - domid = 0, - ssidref = security.get_security_info(self.info, 'ssidref'), - handle = uuid.fromString(self.info['uuid']), - hvm = int(hvm)) + ssidref = security.calc_dom_ssidref_from_info(self.info) + if ssidref == 0 and security.on(): + raise VmError('VM is not properly labeled.') + + try: + self.domid = xc.domain_create( + domid = 0, + ssidref = ssidref, + handle = uuid.fromString(self.info['uuid']), + hvm = int(hvm)) + except Exception, e: + # may get here if due to ACM the operation is not permitted + if security.on(): + raise VmError('Domain in conflict set with running domain?') if self.domid < 0: raise VmError('Creating domain failed: name=%s' % @@ -1954,24 +1975,6 @@ class XendDomainInfo: image_sxpr = self.info.image_sxpr() if image_sxpr: to_store['image'] = sxp.to_string(image_sxpr) - - if self._infoIsSet('security'): - secinfo = self.info['security'] - to_store['security'] = sxp.to_string(secinfo) - for idx in range(0, len(secinfo)): - if secinfo[idx][0] == 'access_control': - to_store['security/access_control'] = sxp.to_string( - [secinfo[idx][1], secinfo[idx][2]]) - for aidx in range(1, len(secinfo[idx])): - if secinfo[idx][aidx][0] == 'label': - to_store['security/access_control/label'] = \ - secinfo[idx][aidx][1] - if secinfo[idx][aidx][0] == 'policy': - to_store['security/access_control/policy'] = \ - secinfo[idx][aidx][1] - if secinfo[idx][0] == 'ssidref': - to_store['security/ssidref'] = str(secinfo[idx][1]) - if not self._readVm('xend/restart_count'): to_store['xend/restart_count'] = str(0) @@ -2090,15 +2093,6 @@ class XendDomainInfo: info["maxmem_kb"] = XendNode.instance() \ .physinfo_dict()['total_memory'] * 1024 - #manually update ssidref / security fields - if security.on() and info.has_key('ssidref'): - if (info['ssidref'] != 0) and self.info.has_key('security'): - security_field = self.info['security'] - if not security_field: - #create new security element - self.info.update({'security': - [['ssidref', str(info['ssidref'])]]}) - #ssidref field not used any longer if 'ssidref' in info: info.pop('ssidref') @@ -2182,7 +2176,133 @@ class XendDomainInfo: return self.info.get('tools_version', {}) def get_metrics(self): return self.metrics.get_uuid(); - + + + def get_security_label(self): + domid = self.getDomid() + + from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance + xspol = XSPolicyAdminInstance().get_loaded_policy() + + if domid == 0: + if xspol: + label = xspol.policy_get_domain_label_formatted(domid) + else: + label = "" + else: + label = self.info.get('security_label', '') + return label + + def set_security_label(self, seclab, old_seclab, xspol=None): + """ + Set the security label of a domain from its old to + a new value. + @param seclab New security label formatted in the form + <policy type>:<policy name>:<vm label> + @param old_seclab The current security label that the + VM must have. + @param xspol An optional policy under which this + update should be done. If not given, + then the current active policy is used. + @return Returns return code, a string with errors from + the hypervisor's operation, old label of the + domain + """ + rc = 0 + errors = "" + old_label = "" + new_ssidref = 0 + domid = self.getDomid() + res_labels = None + + from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance + from xen.util import xsconstants + + state = self._stateGet() + # Relabel only HALTED or RUNNING or PAUSED domains + if domid != 0 and \ + state not in \ + [ DOM_STATE_HALTED, DOM_STATE_RUNNING, DOM_STATE_PAUSED, \ + DOM_STATE_SUSPENDED ]: + log.warn("Relabeling domain not possible in state '%s'" % + DOM_STATES[state]) + return (-xsconstants.XSERR_VM_WRONG_STATE, "", "", 0) + + # Remove security label. Works only for halted domains + if not seclab or seclab == "": + if state not in [ DOM_STATE_HALTED ]: + return (-xsconstants.XSERR_VM_WRONG_STATE, "", "", 0) + + if self.info.has_key('security_label'): + old_label = self.info['security_label'] + # Check label against expected one. + if old_label != old_seclab: + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + del self.info['security_label'] + xen.xend.XendDomain.instance().managed_config_save(self) + return (xsconstants.XSERR_SUCCESS, "", "", 0) + + tmp = seclab.split(":") + if len(tmp) != 3: + return (-xsconstants.XSERR_BAD_LABEL_FORMAT, "", "", 0) + typ, policy, label = tmp + + poladmin = XSPolicyAdminInstance() + if not xspol: + xspol = poladmin.get_policy_by_name(policy) + + if state in [ DOM_STATE_RUNNING, DOM_STATE_PAUSED ]: + #if domain is running or paused try to relabel in hypervisor + if not xspol: + return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0) + + if typ != xspol.get_type_name() or \ + policy != xspol.get_name(): + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + + if typ == xsconstants.ACM_POLICY_ID: + new_ssidref = xspol.vmlabel_to_ssidref(label) + if new_ssidref == xsconstants.INVALID_SSIDREF: + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + + # Check that all used resources are accessible under the + # new label + if not security.resources_compatible_with_vmlabel(xspol, + self, label): + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + + #Check label against expected one. + old_label = self.get_security_label() + if old_label != old_seclab: + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + + # relabel domain in the hypervisor + rc, errors = security.relabel_domains([[domid, new_ssidref]]) + log.info("rc from relabeling in HV: %d" % rc) + else: + return (-xsconstants.XSERR_POLICY_TYPE_UNSUPPORTED, "", "", 0) + + if rc == 0: + # HALTED, RUNNING or PAUSED + if domid == 0: + if xspol: + ssidref = poladmin.set_domain0_bootlabel(xspol, label) + else: + return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0) + else: + if self.info.has_key('security_label'): + old_label = self.info['security_label'] + # Check label against expected one, unless wildcard + if old_label != old_seclab: + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + + self.info['security_label'] = seclab + try: + xen.xend.XendDomain.instance().managed_config_save(self) + except: + pass + return (rc, errors, old_label, new_ssidref) + def get_on_shutdown(self): after_shutdown = self.info.get('actions_after_shutdown') if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT: diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendError.py --- a/tools/python/xen/xend/XendError.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendError.py Tue Jul 10 08:39:26 2007 -0600 @@ -174,6 +174,23 @@ class NetworkError(XendAPIError): def __str__(self): return 'NETWORK_ERROR: %s %s' % (self.error, self.network) + +from xen.util.xsconstants import xserr2string + +class SecurityError(XendAPIError): + def __init__(self, error, message=None): + XendAPIError.__init__(self) + self.error = error + if not message: + self.message = xserr2string(-error) + else: + self.message = message + + def get_api_error(self): + return ['SECURITY_ERROR', self.error, self.message] + + def __str__(self): + return 'SECURITY_ERROR: %s:%s' % (self.error, self.message) XEND_ERROR_AUTHENTICATION_FAILED = ('ELUSER', 'Authentication Failed') XEND_ERROR_SESSION_INVALID = ('EPERMDENIED', 'Session Invalid') @@ -188,4 +205,5 @@ XEND_ERROR_VTPM_INVALID = ('EVT XEND_ERROR_VTPM_INVALID = ('EVTPMINVALID', 'VTPM Invalid') XEND_ERROR_VDI_INVALID = ('EVDIINVALID', 'VDI Invalid') XEND_ERROR_SR_INVALID = ('ESRINVALID', 'SR Invalid') +XEND_ERROR_XSPOLICY_INVALID = ('EXSPOLICYINVALID', 'XS Invalid') XEND_ERROR_TODO = ('ETODO', 'Lazy Programmer Error') diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendNode.py --- a/tools/python/xen/xend/XendNode.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendNode.py Tue Jul 10 08:39:26 2007 -0600 @@ -533,18 +533,70 @@ class XendNode: ['version', ver], ['machine', mch]] + def list_to_rangepairs(self,cmap): + cmap.sort() + pairs = [] + x = y = 0 + for i in range(0,len(cmap)): + try: + if ((cmap[y+1] - cmap[i]) > 1): + pairs.append((cmap[x],cmap[y])) + x = y = i+1 + else: + y = y + 1 + # if we go off the end, then just add x to y + except IndexError: + pairs.append((cmap[x],cmap[y])) + + return pairs + + def format_pairs(self,pairs): + if not pairs: + return "no cpus" + out = "" + for f,s in pairs: + if (f==s): + out += '%d'%f + else: + out += '%d-%d'%(f,s) + out += ',' + # trim trailing ',' + return out[:-1] + + def list_to_strrange(self,list): + return self.format_pairs(self.list_to_rangepairs(list)) + + def format_node_to_cpu(self, pinfo): + str='' + whitespace='' + try: + node_to_cpu=pinfo['node_to_cpu'] + for i in range(0, pinfo['nr_nodes']): + str+='%snode%d:%s\n' % (whitespace, + i, + self.list_to_strrange(node_to_cpu[i])) + whitespace='%25s' % '' + except: + str='none\n' + return str[:-1]; + + def count_cpus(self, pinfo): + count=0 + node_to_cpu=pinfo['node_to_cpu'] + for i in range(0, pinfo['nr_nodes']): + count+=len(node_to_cpu[i]) + return count; + def physinfo(self): info = self.xc.physinfo() - info['nr_cpus'] = (info['nr_nodes'] * - info['sockets_per_node'] * - info['cores_per_socket'] * - info['threads_per_core']) + info['nr_cpus'] = self.count_cpus(info) info['cpu_mhz'] = info['cpu_khz'] / 1000 # physinfo is in KiB, need it in MiB info['total_memory'] = info['total_memory'] / 1024 info['free_memory'] = info['free_memory'] / 1024 + info['node_to_cpu'] = self.format_node_to_cpu(info) ITEM_ORDER = ['nr_cpus', 'nr_nodes', @@ -555,6 +607,7 @@ class XendNode: 'hw_caps', 'total_memory', 'free_memory', + 'node_to_cpu' ] return [[k, info[k]] for k in ITEM_ORDER] diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendOptions.py --- a/tools/python/xen/xend/XendOptions.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendOptions.py Tue Jul 10 08:39:26 2007 -0600 @@ -277,6 +277,9 @@ class XendOptions: def get_vncpasswd_default(self): return self.get_config_string('vncpasswd', self.vncpasswd_default) + + def get_keymap(self): + return self.get_config_value('keymap', None) class XendOptionsFile(XendOptions): diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendVDI.py --- a/tools/python/xen/xend/XendVDI.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/XendVDI.py Tue Jul 10 08:39:26 2007 -0600 @@ -23,6 +23,7 @@ import os from xen.util.xmlrpclib2 import stringify from xmlrpclib import dumps, loads +from xen.util import security, xsconstants KB = 1024 MB = 1024 * 1024 @@ -160,6 +161,17 @@ class XendVDI(AutoSaveObject): def get_location(self): raise NotImplementedError() + + def set_security_label(self, sec_lab, old_lab): + image = self.get_location() + rc = security.set_resource_label_xapi(image, sec_lab, old_lab) + if rc != xsconstants.XSERR_SUCCESS: + raise SecurityError(rc) + return rc + + def get_security_label(self): + image = self.get_location() + return security.get_resource_label_xapi(image) class XendQCoWVDI(XendVDI): diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendXSPolicy.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/XendXSPolicy.py Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,222 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (c) 2007 IBM Corporation +# Copyright (c) 2006 Xensource +#============================================================================ + +import logging +from xen.xend.XendBase import XendBase +from xen.xend.XendError import * +from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance +from xen.util import xsconstants, security +import base64 + +log = logging.getLogger("xend.XendXSPolicy") +log.setLevel(logging.TRACE) + + +class XendXSPolicy(XendBase): + """ Administration class for an XSPolicy. """ + + def getClass(self): + return "XSPolicy" + + def getMethods(self): + methods = ['activate_xspolicy'] + return XendBase.getMethods() + methods + + def getFuncs(self): + funcs = [ 'get_xstype', + 'set_xspolicy', + 'get_xspolicy', + 'rm_xsbootpolicy', + 'get_resource_label', + 'set_resource_label', + 'get_labeled_resources' ] + return XendBase.getFuncs() + funcs + + getClass = classmethod(getClass) + getMethods = classmethod(getMethods) + getFuncs = classmethod(getFuncs) + + def __init__(self, xspol, record, uuid): + """ xspol = actual XSPolicy object """ + self.xspol = xspol + XendBase.__init__(self, uuid, record) + + def get_record(self): + xspol_record = { + 'uuid' : self.get_uuid(), + 'flags' : XSPolicyAdminInstance().get_policy_flags(self.xspol), + 'repr' : self.xspol.toxml(), + 'type' : self.xspol.get_type(), + } + return xspol_record + + def get_xstype(self): + return XSPolicyAdminInstance().isXSEnabled() + + def set_xspolicy(self, xstype, xml, flags, overwrite): + ref = "" + xstype = int(xstype) + flags = int(flags) + + polstate = { 'xs_ref': "", 'repr' : "", 'type' : 0, + 'flags' : 0 , 'version': 0 , 'errors' : "", 'xserr' : 0 } + if xstype == xsconstants.XS_POLICY_ACM: + poladmin = XSPolicyAdminInstance() + try: + (xspol, rc, errors) = poladmin.add_acmpolicy_to_system( + xml, flags, + overwrite) + if rc != 0: + polstate.update( { 'xserr' : rc, + 'errors': base64.b64encode(errors) } ) + else: + ref = xspol.get_ref() + polstate = { + 'xs_ref' : ref, + 'flags' : poladmin.get_policy_flags(xspol), + 'type' : xstype, + 'repr' : "", + 'version': xspol.get_version(), + 'errors' : base64.b64encode(errors), + 'xserr' : rc, + } + except Exception, e: + raise + else: + raise SecurityError(-xsconstants.XSERR_POLICY_TYPE_UNSUPPORTED) + return polstate + + def activate_xspolicy(self, flags): + flags = int(flags) + rc = -xsconstants.XSERR_GENERAL_FAILURE + poladmin = XSPolicyAdminInstance() + try: + rc = poladmin.activate_xspolicy(self.xspol, flags) + except Exception, e: + log.info("Activate_policy: %s" % str(e)) + if rc != flags: + raise SecurityError(rc) + return flags + + def get_xspolicy(self): + polstate = { 'xs_ref' : "", + 'repr' : "", + 'type' : 0, + 'flags' : 0, + 'version': "", + 'errors' : "", + 'xserr' : 0 } + poladmin = XSPolicyAdminInstance() + refs = poladmin.get_policies_refs() + # Will return one or no policy + if refs and len(refs) > 0: + ref = refs[0] + xspol = XSPolicyAdminInstance().policy_from_ref(ref) + try: + xspol.grab_lock() + + polstate = { + 'xs_ref' : ref, + 'repr' : xspol.toxml(), + 'type' : xspol.get_type(), + 'flags' : poladmin.get_policy_flags(xspol), + 'version': xspol.get_version(), + 'errors' : "", + 'xserr' : 0, + } + finally: + if xspol: + xspol.unlock() + return polstate + + def rm_xsbootpolicy(self): + rc = XSPolicyAdminInstance().rm_bootpolicy() + if rc != xsconstants.XSERR_SUCCESS: + raise SecurityError(rc) + + def get_labeled_resources(self): + return security.get_labeled_resources_xapi() + + def set_resource_label(self, resource, sec_lab, old_lab): + rc = security.set_resource_label_xapi(resource, sec_lab, old_lab) + if rc != xsconstants.XSERR_SUCCESS: + raise SecurityError(rc) + + def get_resource_label(self, resource): + res = security.get_resource_label_xapi(resource) + return res + + get_xstype = classmethod(get_xstype) + get_xspolicy = classmethod(get_xspolicy) + set_xspolicy = classmethod(set_xspolicy) + rm_xsbootpolicy = classmethod(rm_xsbootpolicy) + set_resource_label = classmethod(set_resource_label) + get_resource_label = classmethod(get_resource_label) + get_labeled_resources = classmethod(get_labeled_resources) + + +class XendACMPolicy(XendXSPolicy): + """ Administration class of an ACMPolicy """ + + def getClass(self): + return "ACMPolicy" + + def getAttrRO(self): + attrRO = [ 'xml', + 'map', + 'binary', + 'header' ] + return XendXSPolicy.getAttrRO() + attrRO + + getClass = classmethod(getClass) + getAttrRO = classmethod(getAttrRO) + + def __init__(self, acmpol, record, uuid): + """ acmpol = actual ACMPolicy object """ + self.acmpol = acmpol + XendXSPolicy.__init__(self, acmpol, record, uuid) + + def get_record(self): + polstate = { + 'uuid' : self.get_uuid(), + 'flags' : XSPolicyAdminInstance().get_policy_flags(self.acmpol), + 'repr' : self.acmpol.toxml(), + 'type' : self.acmpol.get_type(), + } + return polstate + + def get_header(self): + header = { + 'policyname' : "", 'policyurl' : "", 'reference' : "", + 'date' : "", 'namespaceurl' : "", 'version' : "", + } + try: + header = self.acmpol.get_header_fields_map() + except: + pass + return header + + def get_xml(self): + return self.acmpol.toxml() + + def get_map(self): + return self.acmpol.get_map() + + def get_binary(self): + polbin = self.acmpol.get_bin() + return base64.b64encode(polbin) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/XendXSPolicyAdmin.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/XendXSPolicyAdmin.py Tue Jul 10 08:39:26 2007 -0600 @@ -0,0 +1,314 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006,2007 International Business Machines Corp. +# Author: Stefan Berger <stefanb@xxxxxxxxxx> +#============================================================================ +import os +import shutil + +from xml.dom import minidom, Node + +from xen.xend.XendLogging import log +from xen.xend import uuid +from xen.util import security, xsconstants, dictio, bootloader +from xen.util.xspolicy import XSPolicy +from xen.util.acmpolicy import ACMPolicy +from xen.xend.XendError import SecurityError + +XS_MANAGED_POLICIES_FILE = "/etc/xen/acm-security/policies/managed_policies" + +class XSPolicyAdmin: + """ The class that handles the managed policies in the system. + Handles adding and removing managed policies. All managed + policies are handled using a reference (UUID) which is + assigned to the policy by this class. + """ + + def __init__(self, maxpolicies): + """ Create a management class for managing the system's + policies. + + @param maxpolicies: The max. number of policies allowed + on the system (currently '1') + """ + self.maxpolicies = maxpolicies + try: + self.policies = dictio.dict_read("managed_policies", + XS_MANAGED_POLICIES_FILE) + except Exception, e: + self.policies = {} + + self.xsobjs = {} + for ref, data in self.policies.items(): + name = data[0] + typ = data[1] + try: + if typ == xsconstants.ACM_POLICY_ID: + self.xsobjs[ref] = ACMPolicy(name=name, ref=ref) + else: + del self.policies[ref] + except Exception, e: + log.error("XSPolicyAdmin: Could not find policy '%s': %s" % + (name, str(e))) + del self.policies[ref] + log.debug("XSPolicyAdmin: Known policies: %s" % self.policies) + + def isXSEnabled(self): + """ Check whether 'security' is enabled on this system. + This currently only checks for ACM-enablement. + """ + rc = 0 + if security.on(): + rc |= xsconstants.XS_POLICY_ACM + return rc + + def add_acmpolicy_to_system(self, xmltext, flags, overwrite): + """ Add an ACM policy's xml representation to the system. The + policy will automatically be compiled + flags: + XS_INST_BOOT : make policy the one to boot the system with + by default; if there's a policy already installed, + refuse to install this policy unless its one with + the same name + XS_INST_LOAD : load the policy immediately; if this does not work + refuse to install this policy + overwrite: + If any policy is installed and this is False, refuse to install + this policy + If flags is True, then any existing policy will be removed from + the system and the new one will be installed + """ + errors = "" + loadedpol = self.get_loaded_policy() + if loadedpol: + # This is meant as an update to a currently loaded policy + if flags & xsconstants.XS_INST_LOAD == 0: + raise SecurityError(-xsconstants.XSERR_POLICY_LOADED) + rc, errors = loadedpol.update(xmltext) + if rc == 0: + self.rm_bootpolicy() + irc = self.activate_xspolicy(loadedpol, flags) + return (loadedpol, rc, errors) + + try: + dom = minidom.parseString(xmltext.encode("utf-8")) + except: + raise SecurityError(-xsconstants.XSERR_BAD_XML) + + ref = uuid.createString() + + acmpol = ACMPolicy(dom=dom, ref=ref) + + #First some basic tests that do not modify anything: + + if flags & xsconstants.XS_INST_BOOT and not overwrite: + filename = acmpol.get_filename(".bin","",dotted=True) + if bootloader.get_default_policy != None and \ + not bootloader.loads_default_policy(filename): + raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED) + + if not overwrite and len(self.policies) >= self.maxpolicies: + raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED) + + if overwrite: + #This should only give one key since only one policy is + #allowed. + keys = self.policies.keys() + for k in keys: + self.rm_bootpolicy() + rc = self.rm_policy_from_system(k, force=overwrite) + if rc != xsconstants.XSERR_SUCCESS: + raise SecurityError(rc) + + rc = acmpol.compile() + if rc != 0: + raise SecurityError(rc) + + if flags & xsconstants.XS_INST_LOAD: + rc = acmpol.loadintohv() + if rc != 0: + raise SecurityError(rc) + + if flags & xsconstants.XS_INST_BOOT: + rc = self.make_boot_policy(acmpol) + if rc != 0: + # If it cannot be installed due to unsupported + # bootloader, let it be ok. + pass + + if dom: + new_entry = { ref : tuple([acmpol.get_name(), + xsconstants.ACM_POLICY_ID]) } + self.policies.update(new_entry) + self.xsobjs[ref] = acmpol + dictio.dict_write(self.policies, + "managed_policies", + XS_MANAGED_POLICIES_FILE) + return (acmpol, xsconstants.XSERR_SUCCESS, errors) + + def make_boot_policy(self, acmpol): + spolfile = acmpol.get_filename(".bin") + dpolfile = "/boot/" + acmpol.get_filename(".bin","",dotted=True) + if not os.path.isfile(spolfile): + log.error("binary policy file does not exist.") + return -xsconstants.XSERR_FILE_ERROR + try: + shutil.copyfile(spolfile, dpolfile) + except: + return -xsconstants.XSERR_FILE_ERROR + + try: + filename = acmpol.get_filename(".bin","",dotted=True) + if bootloader.set_default_boot_policy(filename) != True: + return xsconstants.XSERR_BOOTPOLICY_INSTALL_ERROR + except: + return xsconstants.XSERR_FILE_ERROR + return xsconstants.XSERR_SUCCESS + + def activate_xspolicy(self, xspol, flags): + rc = xsconstants.XSERR_SUCCESS + if flags & xsconstants.XS_INST_LOAD: + rc = xspol.loadintohv() + if rc == xsconstants.XSERR_SUCCESS and \ + flags & xsconstants.XS_INST_BOOT: + rc = self.make_boot_policy(xspol) + if rc == xsconstants.XSERR_SUCCESS: + rc = flags + return rc + + def rm_policy_from_system(self, ref, force=False): + if self.policies.has_key(ref): + acmpol = self.xsobjs[ref] + rc = acmpol.destroy() + if rc == xsconstants.XSERR_SUCCESS or force: + del self.policies[ref] + del self.xsobjs[ref] + dictio.dict_write(self.policies, + "managed_policies", + XS_MANAGED_POLICIES_FILE) + rc = xsconstants.XSERR_SUCCESS + return rc + + def rm_bootpolicy(self): + """ Remove any (ACM) boot policy from the grub configuration file + """ + rc = 0 + title = bootloader.get_default_title() + if title != None: + polnames = [] + for (k, v) in self.xsobjs.items(): + polnames.append(v.get_filename(".bin","",dotted=True)) + bootloader.rm_policy_from_boottitle(title, polnames) + else: + rc = -xsconstants.XSERR_NO_DEFAULT_BOOT_TITLE + return rc + + def get_policy_flags(self, acmpol): + """ Get the currently active flags of a policy, i.e., whether the + system is using this policy as its boot policy for the default + boot title. + """ + flags = 0 + + filename = acmpol.get_filename(".bin","", dotted=True) + if bootloader.loads_default_policy(filename): + flags |= xsconstants.XS_INST_BOOT + + if acmpol.isloaded(): + flags |= xsconstants.XS_INST_LOAD + return flags + + def get_policies(self): + """ Get all managed policies. """ + return self.xsobjs.values() + + def get_policies_refs(self): + """ Get all managed policies' references. """ + return self.xsobjs.keys() + + def has_ref(self, ref): + """ Check whether there is a policy with the given reference """ + return self.xsobjs.has_key(ref) + + def policy_from_ref(self, ref): + """ Get the policy's object given its reference """ + if ref in self.xsobjs.keys(): + return self.xsobjs[ref] + return None + + def ref_from_polname(self, polname): + """ Get the reference of the policy given its name """ + ref = None + for (k, v) in self.xsobjs.items(): + if v.get_name() == polname: + ref = k + break + return ref + + def lock_policy(self, ref): + """ get exclusive access to a policy """ + self.xsobjs[ref].grab_lock() + + def unlock_policy(self, ref): + """ release exclusive access to a policy """ + self.xsobjs[ref].unlock() + + def get_loaded_policy(self): + for pol in self.xsobjs.values(): + if pol.isloaded(): + return pol + return None + + def get_policy_by_name(self, name): + for pol in self.xsobjs.values(): + if pol.get_name() == name: + return pol + return None + + def get_domain0_bootlabel(self): + """ Get the domain0 bootlabel from the default boot title """ + title = "" + def_title = bootloader.get_default_title() + line = bootloader.get_kernel_val(def_title, "ssidref") + if line: + parms = line.split(":",1) + if len(parms) > 1: + title = parms[1] + return title + + def set_domain0_bootlabel(self, xspol, label): + """ Set the domain-0 bootlabel under the given policy """ + return xspol.set_vm_bootlabel(label) + + def rm_domain0_bootlabel(self): + """ Remove the domain-0 bootlabel from the default boot title """ + def_title = bootloader.get_default_title() + return bootloader.set_kernel_attval(def_title, "ssidref", None) + + def ssidref_to_vmlabel(self, ssidref): + """ Given an ssidref, return the vmlabel under the current policy """ + vmlabel = "" + pol = self.get_loaded_policy() + if pol: + vmlabel = pol.policy_get_domain_label_by_ssidref_formatted(ssidref) + return vmlabel + +poladmin = None + +def XSPolicyAdminInstance(maxpolicies=1): + global poladmin + if poladmin == None: + poladmin = XSPolicyAdmin(maxpolicies) + return poladmin diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/server/SrvDomain.py --- a/tools/python/xen/xend/server/SrvDomain.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/server/SrvDomain.py Tue Jul 10 08:39:26 2007 -0600 @@ -155,7 +155,8 @@ class SrvDomain(SrvDir): def op_domain_sched_credit_set(self, _, req): fn = FormFn(self.xd.domain_sched_credit_set, [['dom', 'int'], - ['weight', 'int']]) + ['weight', 'int'], + ['cap', 'int']]) val = fn(req.args, {'dom': self.dom.domid}) return val diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/server/blkif.py --- a/tools/python/xen/xend/server/blkif.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/server/blkif.py Tue Jul 10 08:39:26 2007 -0600 @@ -73,10 +73,17 @@ class BlkifController(DevController): back['uuid'] = uuid if security.on(): - (label, ssidref, policy) = security.get_res_security_details(uname) - back.update({'acm_label' : label, - 'acm_ssidref': str(ssidref), - 'acm_policy' : policy}) + (label, ssidref, policy) = \ + security.get_res_security_details(uname) + domain_label = self.vm.get_security_label() + if domain_label: + rc = security.res_security_check_xapi(label, ssidref, policy, + domain_label) + if rc == 0: + raise VmError("VM's access to block device '%s' denied." % + uname) + else: + raise VmError("VM must have a security label.") devid = blkif.blkdev_name_to_number(dev) if devid is None: diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/server/netif.py --- a/tools/python/xen/xend/server/netif.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/server/netif.py Tue Jul 10 08:39:26 2007 -0600 @@ -107,6 +107,7 @@ class NetifController(DevController): uuid = config.get('uuid') ipaddr = config.get('ip') model = config.get('model') + accel = config.get('accel') if not typ: typ = xoptions.netback_type @@ -131,6 +132,8 @@ class NetifController(DevController): back['uuid'] = uuid if model: back['model'] = model + if accel: + back['accel'] = accel config_path = "device/%s/%d/" % (self.deviceClass, devid) for x in back: @@ -157,10 +160,10 @@ class NetifController(DevController): config_path = "device/%s/%d/" % (self.deviceClass, devid) devinfo = () for x in ( 'script', 'ip', 'bridge', 'mac', - 'type', 'vifname', 'rate', 'uuid', 'model' ): + 'type', 'vifname', 'rate', 'uuid', 'model', 'accel'): y = self.vm._readVm(config_path + x) devinfo += (y,) - (script, ip, bridge, mac, typ, vifname, rate, uuid, model) = devinfo + (script, ip, bridge, mac, typ, vifname, rate, uuid, model, accel) = devinfo if script: result['script'] = script @@ -180,5 +183,7 @@ class NetifController(DevController): result['uuid'] = uuid if model: result['model'] = model + if accel: + result['accel'] = accel return result diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xend/server/vfbif.py Tue Jul 10 08:39:26 2007 -0600 @@ -76,6 +76,11 @@ class VfbifController(DevController): args += [ "--listen", vnclisten ] if config.has_key("keymap"): args += ["-k", "%s" % config["keymap"]] + else: + xoptions = xen.xend.XendOptions.instance() + if xoptions.get_keymap(): + args += ["-k", "%s" % xoptions.get_keymap()] + spawn_detached(args[0], args + std_args, os.environ) elif t == "sdl": args = [xen.util.auxbin.pathTo("xen-sdlfb")] diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xm/create.py Tue Jul 10 08:39:26 2007 -0600 @@ -318,7 +318,8 @@ gopts.var('vfb', val="type={vnc,sdl},vnc given DISPLAY and XAUTHORITY, which default to the current user's ones.""") -gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME", +gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT," + \ + "backend=DOM,vifname=NAME,rate=RATE,model=MODEL,accel=ACCEL", fn=append_value, default=[], use="""Add a network interface with the given MAC address and bridge. The vif is configured by calling the given configuration script. @@ -330,6 +331,9 @@ gopts.var('vif', val="type=TYPE,mac=MAC, If backend is not specified the default backend driver domain is used. If vifname is not specified the backend virtual interface will have name vifD.N where D is the domain id and N is the interface id. + If rate is not specified the default rate is used. + If model is not specified the default model is used. + If accel is not specified an accelerator plugin module is not used. This option may be repeated to add more than one vif. Specifying vifs will increase the number of interfaces as needed.""") @@ -710,7 +714,7 @@ def configure_vifs(config_devs, vals): def f(k): if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type', - 'vifname', 'rate', 'model']: + 'vifname', 'rate', 'model', 'accel']: err('Invalid vif option: ' + k) config_vif.append([k, d[k]]) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/python/xen/xm/main.py Tue Jul 10 08:39:26 2007 -0600 @@ -700,13 +700,7 @@ def xm_save(args): if serverType == SERVER_XEN_API: server.xenapi.VM.save(get_single_vm(dom), savefile, checkpoint) else: - try: - dominfo = parse_doms_info(server.xend.domain(dom)) - except xmlrpclib.Fault, ex: - raise ex - - domid = dominfo['domid'] - server.xend.domain.save(domid, savefile, checkpoint) + server.xend.domain.save(dom, savefile, checkpoint) def xm_restore(args): arg_check(args, "restore", 1, 2) @@ -1529,7 +1523,7 @@ def xm_sched_credit(args): doms = filter(lambda x : domid_match(domid, x), [parse_doms_info(dom) - for dom in getDomains(None, 'running')]) + for dom in getDomains(None, 'all')]) if weight is None and cap is None: if domid is not None and doms == []: @@ -1545,7 +1539,7 @@ def xm_sched_credit(args): server.xenapi.VM.get_metrics( get_single_vm(d['name']))) else: - info = server.xend.domain.sched_credit_get(d['domid']) + info = server.xend.domain.sched_credit_get(d['name']) except xmlrpclib.Fault: pass @@ -1557,8 +1551,8 @@ def xm_sched_credit(args): info['cap'] = int(info['cap']) info['name'] = d['name'] - info['domid'] = int(d['domid']) - print( ("%(name)-32s %(domid)5d %(weight)6d %(cap)4d") % info) + info['domid'] = str(d['domid']) + print( ("%(name)-32s %(domid)5s %(weight)6d %(cap)4d") % info) else: if domid is None: # place holder for system-wide scheduler parameters @@ -1566,14 +1560,24 @@ def xm_sched_credit(args): usage('sched-credit') if serverType == SERVER_XEN_API: - server.xenapi.VM.add_to_VCPUs_params_live( - get_single_vm(domid), - "weight", - weight) - server.xenapi.VM.add_to_VCPUs_params_live( - get_single_vm(domid), - "cap", - cap) + if doms[0]['domid']: + server.xenapi.VM.add_to_VCPUs_params_live( + get_single_vm(domid), + "weight", + weight) + server.xenapi.VM.add_to_VCPUs_params_live( + get_single_vm(domid), + "cap", + cap) + else: + server.xenapi.VM.add_to_VCPUs_params( + get_single_vm(domid), + "weight", + weight) + server.xenapi.VM.add_to_VCPUs_params( + get_single_vm(domid), + "cap", + cap) else: result = server.xend.domain.sched_credit_set(domid, weight, cap) if result != 0: diff -r 87b0b6a08dbd -r 42586a0f4407 tools/security/policies/security_policy.xsd --- a/tools/security/policies/security_policy.xsd Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/security/policies/security_policy.xsd Tue Jul 10 08:39:26 2007 -0600 @@ -22,7 +22,7 @@ <xsd:element name="Reference" type="xsd:string" minOccurs="0" maxOccurs="1" /> <xsd:element name="Date" minOccurs="0" maxOccurs="1" type="xsd:string"></xsd:element> <xsd:element name="NameSpaceUrl" minOccurs="0" maxOccurs="1" type="xsd:string"></xsd:element> - <xsd:element name="Version" minOccurs="0" maxOccurs="1" type="VersionFormat"/> + <xsd:element name="Version" minOccurs="1" maxOccurs="1" type="VersionFormat"/> <xsd:element ref="FromPolicy" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> @@ -91,23 +91,23 @@ <xsd:sequence> <xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" /> </xsd:sequence> - <xsd:attribute name="name" type="xsd:string" use="optional"></xsd:attribute> + <xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute> </xsd:complexType> </xsd:element> <xsd:element name="VirtualMachineLabel"> <xsd:complexType> <xsd:sequence> - <xsd:element ref="Name"></xsd:element> + <xsd:element name="Name" type="NameWithFrom"></xsd:element> <xsd:element ref="SimpleTypeEnforcementTypes" minOccurs="0" maxOccurs="unbounded" /> - <xsd:element ref="ChineseWallTypes" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="ChineseWallTypes" type="SingleChineseWallType" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="ResourceLabel"> <xsd:complexType> <xsd:sequence> - <xsd:element ref="Name"></xsd:element> - <xsd:element ref="SimpleTypeEnforcementTypes" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="Name" type="NameWithFrom"></xsd:element> + <xsd:element name="SimpleTypeEnforcementTypes" type="SingleSimpleTypeEnforcementType" /> </xsd:sequence> </xsd:complexType> </xsd:element> @@ -131,4 +131,21 @@ <xsd:pattern value="[0-9]{1,8}.[0-9]{1,8}"></xsd:pattern> </xsd:restriction> </xsd:simpleType> + <xsd:complexType name="NameWithFrom"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="from" type="xsd:string" use="optional"></xsd:attribute> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:complexType name="SingleSimpleTypeEnforcementType"> + <xsd:sequence> + <xsd:element maxOccurs="1" minOccurs="1" ref="Type" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="SingleChineseWallType"> + <xsd:sequence> + <xsd:element maxOccurs="1" minOccurs="1" ref="Type" /> + </xsd:sequence> + </xsd:complexType> </xsd:schema> diff -r 87b0b6a08dbd -r 42586a0f4407 tools/security/xensec_ezpolicy --- a/tools/security/xensec_ezpolicy Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/security/xensec_ezpolicy Tue Jul 10 08:39:26 2007 -0600 @@ -1102,8 +1102,10 @@ def org2dict(): for i in iterchildren(app.win.orgs.GetRootItem()): d = [] for j in iterchildren(i): - d.append(str(app.win.orgspanel.orgs.GetItemText(j))) - o.append([str(app.win.orgspanel.orgs.GetItemText(i)) , d]) + d.append( + str(app.win.orgspanel.orgs.GetItemText(j).encode("utf-8"))) + o.append([str(app.win.orgspanel.orgs.GetItemText(i).encode("utf-8")), + d]) dic['orgs'] = o c=[] for i in app.win.conspanel.conflictsets: @@ -1175,12 +1177,14 @@ def printPolicy(fd, types, cons): continue #name is optional but must be set if i[0]: - rer_name = str(i[0]) + rer_name = i[0] else: - rer_name = str("RER") - fd.write(""" <Conflict name=\"%s\">\n""" % rer_name) + rer_name = "RER" + fd.write(""" <Conflict name=\"""" + + rer_name.encode("utf-8") + """\">\n""") for j in i[1]: - fd.write(""" <Type>%s</Type>\n""" % str(j)) + typ = j.encode("utf-8") + fd.write(""" <Type>%s</Type>\n""" % typ) fd.write(""" </Conflict>\n""") fd.write(""" </ConflictSets>\n""") diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xcutils/Makefile --- a/tools/xcutils/Makefile Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xcutils/Makefile Tue Jul 10 08:39:26 2007 -0600 @@ -15,7 +15,7 @@ PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xe INCLUDES += -I $(XEN_LIBXC) -I $(XEN_XENSTORE) -CFLAGS += -Werror -fno-strict-aliasing +CFLAGS += -Werror CFLAGS += $(INCLUDES) # Make gcc generate dependencies. diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenmon/xenbaked.c --- a/tools/xenmon/xenbaked.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenmon/xenbaked.c Tue Jul 10 08:39:26 2007 -0600 @@ -444,7 +444,7 @@ struct t_rec **init_rec_ptrs(struct t_bu */ unsigned int get_num_cpus(void) { - xc_physinfo_t physinfo; + xc_physinfo_t physinfo = { 0 }; int xc_handle = xc_interface_open(); int ret; diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstat/libxenstat/src/xenstat.c --- a/tools/xenstat/libxenstat/src/xenstat.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenstat/libxenstat/src/xenstat.c Tue Jul 10 08:39:26 2007 -0600 @@ -135,7 +135,7 @@ xenstat_node *xenstat_get_node(xenstat_h { #define DOMAIN_CHUNK_SIZE 256 xenstat_node *node; - xc_physinfo_t physinfo; + xc_physinfo_t physinfo = { 0 }; xc_domaininfo_t domaininfo[DOMAIN_CHUNK_SIZE]; unsigned int new_domains; unsigned int i; diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/Makefile --- a/tools/xenstore/Makefile Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenstore/Makefile Tue Jul 10 08:39:26 2007 -0600 @@ -11,15 +11,11 @@ BASECFLAGS += -Wp,-MD,.$(@F).d BASECFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d BASECFLAGS+= $(PROFILE) -#BASECFLAGS+= -I$(XEN_ROOT)/tools BASECFLAGS+= -I$(XEN_ROOT)/tools/libxc BASECFLAGS+= -I. CFLAGS += $(BASECFLAGS) LDFLAGS += $(PROFILE) -L$(XEN_LIBXC) -TESTDIR = testsuite/tmp -TESTFLAGS= -DTESTING -TESTENV = XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm xenstore-chmod CLIENTS += xenstore-write @@ -34,12 +30,6 @@ XENSTORED_OBJS += $(XENSTORED_OBJS_y) .PHONY: all all: libxenstore.so libxenstore.a xenstored $(CLIENTS) xs_tdb_dump xenstore-control xenstore-ls - -test_interleaved_transactions: test_interleaved_transactions.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@ - -.PHONY: testcode -testcode: xs_test xenstored_test xs_random xenstored: $(XENSTORED_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl $(SOCKET_LIBS) -o $@ @@ -56,34 +46,8 @@ xenstore-ls: xsls.o libxenstore.so xenstore-ls: xsls.o libxenstore.so $(CC) $(CFLAGS) $(LDFLAGS) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore $(SOCKET_LIBS) -o $@ -xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o tdb.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ - xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ - -xs_test xs_random xs_stress xs_crashme: LDFLAGS+=-lpthread -xs_test: xs_test.o xs_lib.o utils.o -xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o -xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o -xs_crashme: xs_crashme.o xs_lib.o talloc.o utils.o - -speedtest: speedtest.o xs.o xs_lib.o utils.o talloc.o - -.PHONY: check-speed -check-speed: speedtest xenstored_test $(TESTDIR) - $(TESTENV) time ./speedtest 100 - -xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o xs_crashme.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS) - -xenstored_%_test.o: xenstored_%.c - $(COMPILE.c) -o $@ $< - -xs_test_lib.o: xs.c - $(COMPILE.c) -o $@ $< - -talloc_test.o: talloc.c - $(COMPILE.c) -o $@ $< libxenstore.so: libxenstore.so.$(MAJOR) ln -sf $< $@ @@ -97,66 +61,12 @@ libxenstore.a: xs.o xs_lib.o $(AR) rcs libxenstore.a $^ .PHONY: clean -clean: testsuite-clean +clean: rm -f *.a *.o *.opic *.so* rm -f xenstored xs_random xs_stress xs_crashme - rm -f xs_test xenstored_test xs_tdb_dump xenstore-control xenstore-ls + rm -f xs_tdb_dump xenstore-control xenstore-ls rm -f $(CLIENTS) $(RM) $(PROG_DEP) - -.PHONY: print-dir -print-dir: - @echo -n tools/xenstore: - -.PHONY: print-end -print-end: - @echo - -.PHONY: check -check: print-dir testsuite-fast randomcheck-fast print-end - -.PHONY: fullcheck -fullcheck: testsuite-run randomcheck stresstest - -$(TESTDIR): - mkdir $@ - -.PHONY: testsuite-run -testsuite-run: xenstored_test xs_test $(TESTDIR) - $(TESTENV) testsuite/test.sh && echo - -.PHONY: testsuite-fast -testsuite-fast: xenstored_test xs_test $(TESTDIR) - @$(TESTENV) testsuite/test.sh --fast - -.PHONY: testsuite-clean -testsuite-clean: - rm -rf $(TESTDIR) - -# Make this visible so they can see repeat tests without --fast if they -# fail. -RANDSEED=$(shell date +%s) -.PHONY: randomcheck -randomcheck: xs_random xenstored_test $(TESTDIR) - $(TESTENV) ./xs_random --simple --fast /tmp/xs_random 200000 $(RANDSEED) && echo - $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) && echo -# $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED) - -.PHONY: crashme -crashme: xs_crashme xenstored_test $(TESTDIR) - rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* /tmp/trace - export $(TESTENV); ./xs_crashme 5000 $(RANDSEED) 2>/dev/null - if [ -n "`cat /tmp/xs_crashme.vglog*`" ]; then echo Valgrind complained; cat /tmp/xs_crashme.vglog*; exit 1; fi - rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* /tmp/trace - -.PHONY: randomcheck-fast -randomcheck-fast: xs_random xenstored_test $(TESTDIR) - @$(TESTENV) ./xs_random --fast /tmp/xs_random 2000 $(RANDSEED) - -.PHONY: stresstest -stresstest: xs_stress xenstored_test $(TESTDIR) - rm -rf $(TESTDIR)/store $(TESTDIR)/transactions - export $(TESTENV); PID=`./xenstored_test --output-pid --trace-file=/tmp/trace`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret .PHONY: TAGS TAGS: diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/fake_libxc.c --- a/tools/xenstore/fake_libxc.c Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - Fake libxc which doesn't require hypervisor but talks to xs_test. - Copyright (C) 2005 Rusty Russell IBM Corporation - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <unistd.h> -#include <assert.h> -#include <signal.h> -#include "utils.h" -#include "xenstored_core.h" -#include "xenstored_domain.h" -#include "xenstored_test.h" -#include <xenctrl.h> - -static int sigfd; -static int xs_test_pid; -static evtchn_port_t port; - -/* The event channel maps to a signal, shared page to an mmapped file. */ -void xc_evtchn_notify(int xce_handle, int local_port) -{ - assert(local_port == port); - if (kill(xs_test_pid, SIGUSR2) != 0) - barf_perror("fake event channel failed"); -} - -void *xc_map_foreign_range(int xc_handle, uint32_t dom __attribute__((unused)), - int size, int prot, - unsigned long mfn __attribute__((unused))) -{ - void *ret; - - ret = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0); - if (ret == MAP_FAILED) - return NULL; - - /* xs_test tells us pid and port by putting it in buffer, we reply. */ - xs_test_pid = *(int *)(ret + 32); - port = *(int *)(ret + 36); - *(int *)(ret + 32) = getpid(); - return ret; -} - -int xc_interface_open(void) -{ - int fd; - char page[getpagesize()]; - - fd = open("/tmp/xcmap", O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd < 0) - return fd; - - memset(page, 0, sizeof(page)); - if (!xs_write_all(fd, page, sizeof(page))) - barf_perror("Failed to write /tmp/xcmap page"); - - return fd; -} - -int xc_interface_close(int xc_handle) -{ - close(xc_handle); - return 0; -} - -int xc_domain_getinfo(int xc_handle __attribute__((unused)), - uint32_t first_domid, unsigned int max_doms, - xc_dominfo_t *info) -{ - assert(max_doms == 1); - info->domid = first_domid; - - info->dying = 0; - info->shutdown = 0; - info->paused = 0; - info->blocked = 0; - info->running = 1; - - info->shutdown_reason = 0; - - if ( info->shutdown && (info->shutdown_reason == SHUTDOWN_crash) ) - { - info->shutdown = 0; - info->crashed = 1; - } - - return 1; -} - -static void send_to_fd(int signo __attribute__((unused))) -{ - int saved_errno = errno; - write(sigfd, &port, sizeof(port)); - errno = saved_errno; -} - -void fake_block_events(void) -{ - signal(SIGUSR2, SIG_IGN); -} - -void fake_ack_event(void) -{ - signal(SIGUSR2, send_to_fd); -} - -int xc_evtchn_open(void) -{ - int fds[2]; - - if (pipe(fds) != 0) - return -1; - - if (signal(SIGUSR2, send_to_fd) == SIG_ERR) { - int saved_errno = errno; - close(fds[0]); - close(fds[1]); - errno = saved_errno; - return -1; - } - sigfd = fds[1]; - return fds[0]; -} diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/speedtest.c --- a/tools/xenstore/speedtest.c Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - Xen Store Daemon Speed test - Copyright (C) 2005 Rusty Russell IBM Corporation - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <stdio.h> -#include <stdarg.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include "utils.h" -#include "xs.h" -#include "list.h" -#include "talloc.h" - -static void do_command(const char *cmd) -{ - int ret; - - ret = system(cmd); - if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) - barf_perror("Failed '%s': %i", cmd, ret); -} - -static int start_daemon(void) -{ - int fds[2], pid; - - do_command(talloc_asprintf(NULL, "rm -rf testsuite/tmp/*")); - - /* Start daemon. */ - pipe(fds); - if ((pid = fork())) { - /* Child writes PID when its ready: we wait for that. */ - char buffer[20]; - close(fds[1]); - if (read(fds[0], buffer, sizeof(buffer)) < 0) - barf("Failed to summon daemon"); - close(fds[0]); - } else { - dup2(fds[1], STDOUT_FILENO); - close(fds[0]); -#if 0 - execlp("valgrind", "valgrind", "-q", "--suppressions=testsuite/vg-suppressions", "xenstored_test", "--output-pid", - "--no-fork", "--trace-file=/tmp/trace", NULL); -#else - execlp("./xenstored_test", "xenstored_test", "--output-pid", "--no-fork", NULL); -// execlp("strace", "strace", "-o", "/tmp/out", "./xenstored_test", "--output-pid", "--no-fork", NULL); -#endif - exit(1); - } - return pid; -} - -static void kill_daemon(int pid) -{ - int saved_errno = errno; - kill(pid, SIGTERM); - errno = saved_errno; -} - -#define NUM_ENTRIES 50 - -/* We create the given number of trees, each with NUM_ENTRIES, using - * transactions. */ -int main(int argc, char *argv[]) -{ - int i, j, pid, print; - struct xs_handle *h; - - if (argc != 2) - barf("Usage: speedtest <numdomains>"); - - pid = start_daemon(); - h = xs_daemon_open(); - print = atoi(argv[1]) / 76; - if (!print) - print = 1; - for (i = 0; i < atoi(argv[1]); i ++) { - char name[64]; - - if (i % print == 0) - write(1, ".", 1); - if (!xs_transaction_start(h)) { - kill_daemon(pid); - barf_perror("Starting transaction"); - } - sprintf(name, "/%i", i); - if (!xs_mkdir(h, name)) { - kill_daemon(pid); - barf_perror("Making directory %s", name); - } - - for (j = 0; j < NUM_ENTRIES; j++) { - sprintf(name, "/%i/%i", i, j); - if (!xs_write(h, name, name, strlen(name))) { - kill_daemon(pid); - barf_perror("Making directory %s", name); - } - } - if (!xs_transaction_end(h, false)) { - kill_daemon(pid); - barf_perror("Ending transaction"); - } - } - write(1, "\n", 1); - - kill_daemon(pid); - wait(NULL); - return 0; -} - - diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/01simple.test --- a/tools/xenstore/testsuite/01simple.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -# Create an entry, read it. -write /test contents -expect contents -read /test diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/02directory.test --- a/tools/xenstore/testsuite/02directory.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -# Root directory has only tool dir in it. -expect tool -dir / - -# Create a file. -write /test contents - -# Directory shows it. -expect test -expect tool -dir / - -# Make a new directory, check it's there -mkdir /dir -expect dir -expect test -expect tool -dir / - -# Check it's empty. -dir /dir - -# Create a file, check it exists. -write /dir/test2 contents2 -expect test2 -dir /dir -expect contents2 -read /dir/test2 - -# Creating dir over the top should succeed. -mkdir /dir -mkdir /dir/test2 - -# Mkdir implicitly creates directories. -mkdir /dir/1/2/3/4 -expect test2 -expect 1 -dir /dir -expect 2 -dir /dir/1 -expect 3 -dir /dir/1/2 -expect 4 -dir /dir/1/2/3 -dir /dir/1/2/3/4 diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/03write.test --- a/tools/xenstore/testsuite/03write.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -# Write succeeds -write /test contents -expect contents -read /test - -# Overwrite succeeds. -write /test contents2 -expect contents2 -read /test - -# Write should implicitly create directories -write /dir/test contents -expect test -dir /dir -expect contents -read /dir/test -write /dir/1/2/3/4 contents4 -expect test -expect 1 -dir /dir -expect 2 -dir /dir/1 -expect 3 -dir /dir/1/2 -expect 4 -dir /dir/1/2/3 -expect contents4 -read /dir/1/2/3/4 diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/04rm.test --- a/tools/xenstore/testsuite/04rm.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -# Remove non-existant is OK, as long as parent exists -rm /test -expect rm failed: No such file or directory -rm /dir/test - -# Create file and remove it -write /test contents -rm /test -expect tool -dir / - -# Create directory and remove it. -mkdir /dir -rm /dir - -# Create directory, create file, remove all. -mkdir /dir -write /dir/test contents -rm /dir - diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/05filepermissions.test --- a/tools/xenstore/testsuite/05filepermissions.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -# Fail to get perms on non-existent file. -expect getperm failed: No such file or directory -getperm /test -expect getperm failed: No such file or directory -getperm /dir/test - -# Create file: inherits from root (0 READ) -write /test contents -expect 0 READ -getperm /test -setid 1 -expect 0 READ -getperm /test -expect contents -read /test -expect write failed: Permission denied -write /test contents - -# Take away read access to file. -setid 0 -setperm /test 0 NONE -setid 1 -expect getperm failed: Permission denied -getperm /test -expect read failed: Permission denied -read /test -expect write failed: Permission denied -write /test contents - -# Grant everyone write access to file. -setid 0 -setperm /test 0 WRITE -setid 1 -expect getperm failed: Permission denied -getperm /test -expect read failed: Permission denied -read /test -write /test contents2 -setid 0 -expect contents2 -read /test - -# Grant everyone both read and write access. -setperm /test 0 READ/WRITE -setid 1 -expect 0 READ/WRITE -getperm /test -expect contents2 -read /test -write /test contents3 -expect contents3 -read /test - -# Change so that user 1 owns it, noone else can do anything. -setid 0 -setperm /test 1 NONE -setid 1 -expect 1 NONE -getperm /test -expect contents3 -read /test -write /test contents4 - -# User 2 can do nothing. -setid 2 -expect setperm failed: Permission denied -setperm /test 2 NONE -expect getperm failed: Permission denied -getperm /test -expect read failed: Permission denied -read /test -expect write failed: Permission denied -write /test contents4 - -# Tools can always access things. -setid 0 -expect 1 NONE -getperm /test -expect contents4 -read /test -write /test contents5 diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/06dirpermissions.test --- a/tools/xenstore/testsuite/06dirpermissions.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -# Root directory: owned by tool, everyone has read access. -expect 0 READ -getperm / - -# Create directory: inherits from root. -mkdir /dir -expect 0 READ -getperm /dir -setid 1 -expect 0 READ -getperm /dir -dir /dir -expect write failed: Permission denied -write /dir/test contents2 - -# Remove everyone's read access to directoy. -setid 0 -setperm /dir 0 NONE -setid 1 -expect dir failed: Permission denied -dir /dir -expect read failed: Permission denied -read /dir/test create contents2 -expect write failed: Permission denied -write /dir/test contents2 - -# Grant everyone write access to directory. -setid 0 -setperm /dir 0 WRITE -setid 1 -expect getperm failed: Permission denied -getperm /dir -expect dir failed: Permission denied -dir /dir -write /dir/test contents -setid 0 -expect 1 WRITE -getperm /dir/test -setperm /dir/test 0 NONE -expect contents -read /dir/test - -# Grant everyone both read and write access. -setperm /dir 0 READ/WRITE -setid 1 -expect 0 READ/WRITE -getperm /dir -expect test -dir /dir -write /dir/test2 contents -expect contents -read /dir/test2 -setperm /dir/test2 1 NONE - -# Change so that user 1 owns it, noone else can do anything. -setid 0 -setperm /dir 1 NONE -expect 1 NONE -getperm /dir -expect test -expect test2 -dir /dir -write /dir/test3 contents - -# User 2 can do nothing. Can't even tell if file exists. -setid 2 -expect setperm failed: Permission denied -setperm /dir 2 NONE -expect getperm failed: Permission denied -getperm /dir -expect dir failed: Permission denied -dir /dir -expect read failed: Permission denied -read /dir/test -expect read failed: Permission denied -read /dir/test2 -expect read failed: Permission denied -read /dir/test3 -expect read failed: Permission denied -read /dir/test4 -expect write failed: Permission denied -write /dir/test contents -expect write failed: Permission denied -write /dir/test4 contents - -# Tools can always access things. -setid 0 -expect 1 NONE -getperm /dir -expect test -expect test2 -expect test3 -dir /dir -write /dir/test4 contents - -# Inherited by child. -mkdir /dir/subdir -expect 1 NONE -getperm /dir/subdir -write /dir/subfile contents -expect 1 NONE -getperm /dir/subfile - -# But for domains, they own it. -setperm /dir/subdir 2 READ/WRITE -expect 2 READ/WRITE -getperm /dir/subdir -setid 3 -write /dir/subdir/subfile contents -expect 3 READ/WRITE -getperm /dir/subdir/subfile - -# Inheritence works through multiple directories, too. -write /dir/subdir/1/2/3/4 contents -expect 3 READ/WRITE -getperm /dir/subdir/1/2/3/4 -mkdir /dir/subdir/a/b/c/d -expect 3 READ/WRITE -getperm /dir/subdir/a/b/c/d diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/07watch.test --- a/tools/xenstore/testsuite/07watch.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -# Watch something, write to it, check watch has fired. -write /test contents - -1 watch /test token -2 write /test contents2 -expect 1:/test:token -1 waitwatch -1 close - -# Check that reads don't set it off. -1 watch /test token -expect 2:contents2 -2 read /test -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -# mkdir, setperm and rm should (also tests watching dirs) -mkdir /dir -1 watch /dir token -2 mkdir /dir/newdir -expect 1:/dir/newdir:token -1 waitwatch -2 setperm /dir/newdir 0 READ -expect 1:/dir/newdir:token -1 waitwatch -2 rm /dir/newdir -expect 1:/dir/newdir:token -1 waitwatch -1 close -2 close - -# Changed in b594bb976a743d509f1ffabb5bc698874ab90d8f -## We don't get a watch from our own commands. -#watch /dir token -#mkdir /dir/newdir -#expect waitwatch failed: Connection timed out -#waitwatch -#close - -# ignore watches while doing commands, should work. -watch /dir token -1 write /dir/test contents -expect contents -read /dir/test -expect /dir/test:token -waitwatch -close - -# watch priority test: all simultaneous -1 watch /dir token1 -3 watch /dir token3 -2 watch /dir token2 -write /dir/test contents -expect 3:/dir/test:token3 -3 waitwatch -expect 2:/dir/test:token2 -2 waitwatch -expect 1:/dir/test:token1 -1 waitwatch -1 close -2 close -3 close - -# If one dies (without acking), the other should still get ack. -1 watch /dir token1 -2 watch /dir token2 -write /dir/test contents -expect 2:/dir/test:token2 -2 waitwatch -2 close -expect 1:/dir/test:token1 -1 waitwatch -1 close - -# If one dies (without reading at all), the other should still get ack. -1 watch /dir token1 -2 watch /dir token2 -write /dir/test contents -2 close -expect 1:/dir/test:token1 -1 waitwatch -1 close -2 close - -# unwatch -1 watch /dir token1 -1 unwatch /dir token1 -1 watch /dir token2 -2 write /dir/test2 contents -expect 1:/dir/test2:token2 -1 waitwatch -1 unwatch /dir token2 -1 close -2 close - -# unwatch while watch pending. Other watcher still gets the event. -1 watch /dir token1 -2 watch /dir token2 -write /dir/test contents -2 unwatch /dir token2 -expect 1:/dir/test:token1 -1 waitwatch -1 close -2 close - -# unwatch while watch pending. Should clear this so we get next event. -1 watch /dir token1 -write /dir/test contents -1 unwatch /dir token1 -1 watch /dir/test token2 -write /dir/test contents2 -expect 1:/dir/test:token2 -1 waitwatch - -# check we only get notified once. -1 watch /test token -2 write /test contents2 -expect 1:/test:token -1 waitwatch -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -# watches are queued in order. -1 watch / token -2 write /test1 contents -2 write /test2 contents -2 write /test3 contents -expect 1:/test1:token -1 waitwatch -expect 1:/test2:token -1 waitwatch -expect 1:/test3:token -1 waitwatch -1 close - -# Creation of subpaths should be covered correctly. -1 watch / token -2 write /test/subnode contents2 -2 write /test/subnode/subnode contents2 -expect 1:/test/subnode:token -1 waitwatch -expect 1:/test/subnode/subnode:token -1 waitwatch -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -# Watch event must have happened before we registered interest. -1 watch / token -2 write /test/subnode contents2 -1 watchnoack / token2 0 -expect 1:/test/subnode:token -1 waitwatch -expect 1:/:token2 -1 waitwatch -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -# Rm fires notification on child. -1 watch /test/subnode token -2 rm /test -expect 1:/test/subnode:token -1 waitwatch - -# Watch should not double-send after we ack, even if we did something in between. -1 watch /test2 token -2 write /test2/foo contents2 -expect 1:/test2/foo:token -1 waitwatch -expect 1:contents2 -1 read /test2/foo -expect 1: waitwatch failed: Connection timed out -1 waitwatch diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/08transaction.slowtest --- a/tools/xenstore/testsuite/08transaction.slowtest Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -# Test transaction clashes. - -mkdir /test -write /test/entry1 contents - -# Start transaction, do read-only op, transaction succeeds -1 start -1 write /test/entry1 contents2 -expect contents -read /test/entry1 -1 commit -expect contents2 -read /test/entry1 - -# Start transaction, abort other transaction, transaction succeeds. -1 start -1 write /test/entry1 contents3 -start -write /test/entry1 contents -abort -1 commit -expect contents3 -read /test/entry1 - -# Start transaction, do write op, transaction fails -1 start -1 write /test/entry1 contents4 -write /test/entry1 contents -expect 1: commit failed: Resource temporarily unavailable -1 commit -expect contents -read /test/entry1 - -# Start transaction, do other transaction, transaction fails -1 start -1 write /test/entry1 contents4 -start -write /test/entry1 contents5 -commit -expect 1: commit failed: Resource temporarily unavailable -1 commit -expect contents5 -read /test/entry1 diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/08transaction.test --- a/tools/xenstore/testsuite/08transaction.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -# Test transactions. - -mkdir /test - -# Simple transaction: create a file inside transaction. -1 start -1 write /test/entry1 contents -2 dir /test -expect 1:entry1 -1 dir /test -1 commit -expect 2:contents -2 read /test/entry1 - -rm /test/entry1 - -# Create a file and abort transaction. -1 start -1 write /test/entry1 contents -2 dir /test -expect 1:entry1 -1 dir /test -1 abort -2 dir /test - -write /test/entry1 contents -# Delete in transaction, commit -1 start -1 rm /test/entry1 -expect 2:entry1 -2 dir /test -1 dir /test -1 commit -2 dir /test - -# Delete in transaction, abort. -write /test/entry1 contents -1 start -1 rm /test/entry1 -expect 2:entry1 -2 dir /test -1 dir /test -1 abort -expect 2:entry1 -2 dir /test - -# Events inside transactions don't trigger watches until (successful) commit. -mkdir /test/dir -1 watch /test token -2 start -2 mkdir /test/dir/sub -expect 1: waitwatch failed: Connection timed out -1 waitwatch -2 close -1 close - -1 watch /test token -2 start -2 mkdir /test/dir/sub -2 abort -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -1 watch /test token -2 start -2 mkdir /test/dir/sub -2 commit -expect 1:/test/dir/sub:token -1 waitwatch -1 close - -# Rm inside transaction works like rm outside: children get notified. -1 watch /test/dir/sub token -2 start -2 rm /test/dir -2 commit -expect 1:/test/dir/sub:token -1 waitwatch -1 close - -# Multiple events from single transaction don't trigger assert -1 watch /test token -2 start -2 write /test/1 contents -2 write /test/2 contents -2 commit -expect 1:/test/1:token -1 waitwatch -expect 1:/test/2:token -1 waitwatch -1 close diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/09domain.test --- a/tools/xenstore/testsuite/09domain.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -# Test domain communication. - -# Create a domain, write an entry. -expect handle is 1 -introduce 1 100 7 /my/home -1 write /entry1 contents -expect entry1 -expect tool -dir / -close - -# Release that domain. -release 1 -close - -# Introduce and release by same connection. -expect handle is 2 -introduce 1 100 7 /my/home -release 1 diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/10domain-homedir.test --- a/tools/xenstore/testsuite/10domain-homedir.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -# Test domain "implicit" paths. - -# Create a domain, write an entry using implicit path, read using implicit -mkdir /home -expect handle is 1 -introduce 1 100 7 /home -1 write entry1 contents -expect contents -read /home/entry1 -expect entry1 -dir /home - -# Place a watch using a relative path: expect relative answer. -1 mkdir foo -1 watch foo token -write /home/foo/bar contents -expect 1:foo/bar:token -1 waitwatch diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/11domain-watch.test --- a/tools/xenstore/testsuite/11domain-watch.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -# Test watching from a domain. - -# Watch something, write to it, check watch has fired. -write /test contents -mkdir /dir - -expect handle is 1 -introduce 1 100 7 /my/home -1 watch /test token -write /test contents2 -expect 1:/test:token -1 waitwatch -1 unwatch /test token -release 1 -1 close - -# ignore watches while doing commands, should work. -expect handle is 1 -introduce 1 100 7 /my/home -1 watch /dir token -write /dir/test contents -1 write /dir/test2 contents2 -1 write /dir/test3 contents3 -1 write /dir/test4 contents4 -expect 1:/dir/test:token -1 waitwatch -release 1 -1 close - -# unwatch -expect handle is 1 -introduce 1 100 7 /my/home -1 watch /dir token1 -1 unwatch /dir token1 -1 watch /dir token2 -write /dir/test2 contents -expect 1:/dir/test2:token2 -1 waitwatch -1 unwatch /dir token2 -release 1 -1 close - -# unwatch while watch pending. -expect handle is 1 -introduce 1 100 7 /my/home -1 watch /dir token1 -write /dir/test2 contents -1 unwatch /dir token1 -release 1 -1 close diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/12readonly.test --- a/tools/xenstore/testsuite/12readonly.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -# Test that read only connection can't alter store. - -write /test contents - -readonly -expect test -expect tool -dir / - -expect contents -read /test -expect 0 READ -getperm /test -watch /test token -unwatch /test token -start -commit -start -abort - -# These don't work -expect write failed: Permission denied -write /test2 contents -expect write failed: Permission denied -write /test contents -expect setperm failed: Permission denied -setperm /test 100 NONE -expect setperm failed: Permission denied -setperm /test 100 NONE -expect introduce failed: Permission denied -introduce 1 100 7 /home - -# Check that watches work like normal. -watch / token -1 readwrite -1 write /test contents -expect /test:token -waitwatch diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/13watch-ack.test --- a/tools/xenstore/testsuite/13watch-ack.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -# This demonstrates a bug where an xs_acknowledge_watch returns -# EINVAL, because the daemon doesn't track what watch event it sent -# and relies on it being the "first" watch which has an event. -# Watches firing after the first event is sent out will change this. - -# Create three things to watch. -mkdir /test -mkdir /test/1 -mkdir /test/2 -mkdir /test/3 - -# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2. -1 watch /test/1 token1 -1 watch /test/2 token2 -1 watch /test/3 token3 -2 write /test/2 contents2 -expect 1:/test/2:token2 -1 waitwatch -3 write /test/1 contents1 -4 write /test/3 contents3 -1 close diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/14complexperms.test --- a/tools/xenstore/testsuite/14complexperms.test Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -# We should not be able to tell the difference between a node which -# doesn't exist, and a node we don't have permission on, if we don't -# have permission on it directory. - -mkdir /dir -setperm /dir 0 NONE - -# First when it doesn't exist -setid 1 -expect *Permission denied -dir /dir/file -expect *Permission denied -read /dir/file -expect *Permission denied -write /dir/file value -expect *Permission denied -mkdir /dir/file -expect *Permission denied -rm /dir/file -expect *Permission denied -rm /dir -expect *Permission denied -getperm /dir/file -expect *Permission denied -setperm /dir/file 0 NONE -# We get no watch event when there's no permission. It's a corner case. -watchnoack /dir/file token -1 write /dir/file contents -1 rm /dir/file -expect waitwatch failed: Connection timed out -waitwatch -unwatch /dir/file token -expect *No such file or directory -unwatch /dir/file token -expect *Permission denied -introduce 2 100 7 /dir/file - -# Now it exists -setid 0 -write /dir/file contents - -setid 1 -expect *Permission denied -dir /dir/file -expect *Permission denied -read /dir/file -expect *Permission denied -write /dir/file value -expect *Permission denied -mkdir /dir/file -expect *Permission denied -rm /dir/file -expect *Permission denied -rm /dir -expect *Permission denied -getperm /dir/file -expect *Permission denied -setperm /dir/file 0 NONE -watchnoack /dir/file token -1 write /dir/file contents -1 rm /dir/file -expect waitwatch failed: Connection timed out -waitwatch -unwatch /dir/file token -expect *No such file or directory -unwatch /dir/file token -expect *Permission denied -introduce 2 100 7 /dir/file diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/test.sh --- a/tools/xenstore/testsuite/test.sh Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -#! /bin/sh - -set -e -set -m - -run_test() -{ - rm -rf $XENSTORED_ROOTDIR - mkdir $XENSTORED_ROOTDIR - if [ $VALGRIND -eq 1 ]; then - valgrind --suppressions=testsuite/vg-suppressions -q ./xenstored_test --output-pid --trace-file=testsuite/tmp/trace --no-fork > /tmp/pid 2> testsuite/tmp/xenstored_errors & - while [ ! -s /tmp/pid ]; do sleep 0; done - PID=`cat /tmp/pid` - rm /tmp/pid - else - # We don't get error messages from this, though. - PID=`./xenstored_test --output-pid --trace-file=testsuite/tmp/trace` - fi - if ./xs_test $2 $1; then - if [ -s testsuite/tmp/xenstored_errors ]; then - kill $PID - echo Errors: - cat testsuite/tmp/xenstored_errors - return 1 - fi - kill $PID - sleep 1 - return 0 - else - # In case daemon is wedged. - kill $PID - sleep 1 - return 1 - fi -} - -if [ x$1 = x--fast ]; then - VALGRIND=0 - SLOWTESTS="" - shift -else - if type valgrind >/dev/null 2>&1; then - VALGRIND=1 - else - echo "WARNING: valgrind not available" >&2 - VALGRIND=0 - fi - SLOWTESTS=testsuite/[0-9]*.slowtest -fi - -MATCH=${1:-"*"} -for f in testsuite/[0-9]*.test $SLOWTESTS; do - case `basename $f` in $MATCH) RUN=1;; esac - [ -n "$RUN" ] || continue - - if run_test $f -x >/tmp/out; then - echo -n . - else - cat /tmp/out - # That will have filled the screen, repeat message. - echo Test $f failed - exit 1 - fi -done diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/testsuite/vg-suppressions --- a/tools/xenstore/testsuite/vg-suppressions Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -{ - Glibc goes boom from _start (Debian glibc 2.3.5-3) - Memcheck:Cond - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so -} diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xenstored_core.c --- a/tools/xenstore/xenstored_core.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenstore/xenstored_core.c Tue Jul 10 08:39:26 2007 -0600 @@ -39,7 +39,6 @@ #include <assert.h> #include <setjmp.h> -//#define DEBUG #include "utils.h" #include "list.h" #include "talloc.h" @@ -53,7 +52,6 @@ #include "hashtable.h" - extern int xce_handle; /* in xenstored_domain.c */ static bool verbose = false; @@ -81,50 +79,6 @@ int quota_nb_watch_per_domain = 128; int quota_nb_watch_per_domain = 128; int quota_max_entry_size = 2048; /* 2K */ int quota_max_transaction = 10; - -#ifdef TESTING -static bool failtest = false; - -/* We override talloc's malloc. */ -void *test_malloc(size_t size) -{ - /* 1 in 20 means only about 50% of connections establish. */ - if (failtest && (random() % 32) == 0) - return NULL; - return malloc(size); -} - -static void stop_failtest(int signum __attribute__((unused))) -{ - failtest = false; -} - -/* Need these before we #define away write_all/mkdir in testing.h */ -bool test_write_all(int fd, void *contents, unsigned int len); -bool test_write_all(int fd, void *contents, unsigned int len) -{ - if (failtest && (random() % 8) == 0) { - if (len) - len = random() % len; - write(fd, contents, len); - errno = ENOSPC; - return false; - } - return xs_write_all(fd, contents, len); -} - -int test_mkdir(const char *dir, int perms); -int test_mkdir(const char *dir, int perms) -{ - if (failtest && (random() % 8) == 0) { - errno = ENOSPC; - return -1; - } - return mkdir(dir, perms); -} -#endif /* TESTING */ - -#include "xenstored_test.h" TDB_CONTEXT *tdb_context(struct connection *conn) { @@ -1163,12 +1117,10 @@ static void do_debug(struct connection * { int num; -#ifndef TESTING if (conn->id != 0) { send_error(conn, EACCES); return; } -#endif num = xs_count_strings(in->buffer, in->used); @@ -1179,18 +1131,10 @@ static void do_debug(struct connection * } xprintf("debug: %s", in->buffer + get_string(in, 0)); } + if (streq(in->buffer, "check")) check_store(); -#ifdef TESTING - /* For testing, we allow them to set id. */ - if (streq(in->buffer, "setid")) { - conn->id = atoi(in->buffer + get_string(in, 0)); - } else if (streq(in->buffer, "failtest")) { - if (get_string(in, 0) < in->used) - srandom(atoi(in->buffer + get_string(in, 0))); - failtest = true; - } -#endif /* TESTING */ + send_ack(conn, XS_DEBUG); } @@ -1319,10 +1263,8 @@ static void handle_input(struct connecti return; if (in->hdr.msg.len > PATH_MAX) { -#ifndef TESTING syslog(LOG_ERR, "Client tried to feed us %i", in->hdr.msg.len); -#endif goto bad_client; } @@ -1414,39 +1356,7 @@ static void accept_connection(int sock, close(fd); } -#ifdef TESTING -/* Valgrind can check our writes better if we don't use mmap */ -#define TDB_FLAGS TDB_NOMMAP -/* Useful for running under debugger. */ -void dump_connection(void) -{ - struct connection *i; - - list_for_each_entry(i, &connections, list) { - printf("Connection %p:\n", i); - printf(" state = %s\n", - list_empty(&i->out_list) ? "OK" : "BUSY"); - if (i->id) - printf(" id = %i\n", i->id); - if (!i->in->inhdr || i->in->used) - printf(" got %i bytes of %s\n", - i->in->used, i->in->inhdr ? "header" : "data"); -#if 0 - if (i->out) - printf(" sending message %s (%s) out\n", - sockmsg_string(i->out->hdr.msg.type), - i->out->buffer); - if (i->transaction) - dump_transaction(i); - if (i->domain) - dump_domain(i); -#endif - dump_watches(i); - } -} -#else #define TDB_FLAGS 0 -#endif /* We create initial nodes manually. */ static void manual_node(const char *name, const char *child) @@ -1693,10 +1603,6 @@ static void corrupt(struct connection *c log("corruption detected by connection %i: err %s: %s", conn ? (int)conn->id : -1, strerror(saved_errno), str); -#ifdef TESTING - /* Allow them to attach debugger. */ - sleep(30); -#endif check_store(); } @@ -1740,11 +1646,10 @@ static void daemonize(void) if (pid != 0) exit(0); -#ifndef TESTING /* Relative paths for socket names */ /* Move off any mount points we might be in. */ if (chdir("/") == -1) barf_perror("Failed to chdir"); -#endif + /* Discard our parent's old-fashioned umask prejudices. */ umask(0); } @@ -1941,10 +1846,6 @@ int main(int argc, char *argv[]) signal(SIGHUP, trigger_reopen_log); -#ifdef TESTING - signal(SIGUSR1, stop_failtest); -#endif - if (xce_handle != -1) evtchn_fd = xc_evtchn_fd(xce_handle); diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xenstored_domain.c --- a/tools/xenstore/xenstored_domain.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenstore/xenstored_domain.c Tue Jul 10 08:39:26 2007 -0600 @@ -23,14 +23,12 @@ #include <stdlib.h> #include <stdarg.h> -//#define DEBUG #include "utils.h" #include "talloc.h" #include "xenstored_core.h" #include "xenstored_domain.h" #include "xenstored_transaction.h" #include "xenstored_watch.h" -#include "xenstored_test.h" #include <xenctrl.h> @@ -217,10 +215,8 @@ void handle_event(void) if (port == virq_port) domain_cleanup(); -#ifndef TESTING if (xc_evtchn_unmask(xce_handle, port) == -1) barf_perror("Failed to write to event fd"); -#endif } bool domain_can_read(struct connection *conn) diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xenstored_test.h --- a/tools/xenstore/xenstored_test.h Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - Testing replcements for Xen Store Daemon. - Copyright (C) 2005 Rusty Russell IBM Corporation - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#ifndef _XENSTORED_TEST_H -#define _XENSTORED_TEST_H - -#ifdef TESTING -bool test_write_all(int fd, void *contents, unsigned int len); -#define xs_write_all test_write_all - -int test_mkdir(const char *dir, int perms); -#define mkdir test_mkdir - -int fake_open_eventchn(void); -void fake_block_events(void); -void fake_ack_event(void); - -#define ioctl(a,b,c) 0 - -#endif - -#endif /* _XENSTORED_INTERNAL_H */ diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xenstored_transaction.c --- a/tools/xenstore/xenstored_transaction.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenstore/xenstored_transaction.c Tue Jul 10 08:39:26 2007 -0600 @@ -35,7 +35,6 @@ #include "xenstored_domain.h" #include "xs_lib.h" #include "utils.h" -#include "xenstored_test.h" struct changed_node { diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xenstored_watch.c --- a/tools/xenstore/xenstored_watch.c Mon Jul 09 09:22:58 2007 -0600 +++ b/tools/xenstore/xenstored_watch.c Tue Jul 10 08:39:26 2007 -0600 @@ -29,7 +29,6 @@ #include "xenstored_watch.h" #include "xs_lib.h" #include "utils.h" -#include "xenstored_test.h" #include "xenstored_domain.h" extern int quota_nb_watch_per_domain; @@ -195,17 +194,6 @@ void conn_delete_all_watches(struct conn domain_watch_dec(conn); } } - -#ifdef TESTING -void dump_watches(struct connection *conn) -{ - struct watch *watch; - - list_for_each_entry(watch, &conn->watches, list) - printf(" watch on %s token %s\n", - watch->node, watch->token); -} -#endif /* * Local variables: diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xs_crashme.c --- a/tools/xenstore/xs_crashme.c Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* Code which randomly corrupts bits going to the daemon. - Copyright (C) 2005 Rusty Russell IBM Corporation - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include <stdbool.h> -#include <stdio.h> -#include <sys/types.h> -#include <stdarg.h> -#include <string.h> -#include <sys/time.h> -#include "xs.h" -#include "talloc.h" -#include <errno.h> - -#define XSTEST -#define RAND_FREQ 128 /* One char in 32 is corrupted. */ - -/* jhash.h: Jenkins hash support. - * - * Copyright (C) 1996 Bob Jenkins (bob_jenkins@xxxxxxxxxxxxxxxx) - * - * http://burtleburtle.net/bob/hash/ - * - * These are the credits from Bob's sources: - * - * lookup2.c, by Bob Jenkins, December 1996, Public Domain. - * hash(), hash2(), hash3, and mix() are externally useful functions. - * Routines to test the hash are included if SELF_TEST is defined. - * You can use this free for any purpose. It has no warranty. - * - * Copyright (C) 2003 David S. Miller (davem@xxxxxxxxxx) - * - * I've modified Bob's hash to be useful in the Linux kernel, and - * any bugs present are surely my fault. -DaveM - */ - -/* NOTE: Arguments are modified. */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} - -/* The golden ration: an arbitrary value */ -#define JHASH_GOLDEN_RATIO 0x9e3779b9 - -/* The most generic version, hashes an arbitrary sequence - * of bytes. No alignment or length assumptions are made about - * the input key. - */ -static inline uint32_t jhash(const void *key, uint32_t length, uint32_t initval) -{ - uint32_t a, b, c, len; - const uint8_t *k = key; - - len = length; - a = b = JHASH_GOLDEN_RATIO; - c = initval; - - while (len >= 12) { - a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); - b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); - c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); - - __jhash_mix(a,b,c); - - k += 12; - len -= 12; - } - - c += length; - switch (len) { - case 11: c += ((uint32_t)k[10]<<24); - case 10: c += ((uint32_t)k[9]<<16); - case 9 : c += ((uint32_t)k[8]<<8); - case 8 : b += ((uint32_t)k[7]<<24); - case 7 : b += ((uint32_t)k[6]<<16); - case 6 : b += ((uint32_t)k[5]<<8); - case 5 : b += k[4]; - case 4 : a += ((uint32_t)k[3]<<24); - case 3 : a += ((uint32_t)k[2]<<16); - case 2 : a += ((uint32_t)k[1]<<8); - case 1 : a += k[0]; - }; - - __jhash_mix(a,b,c); - - return c; -} - -/* A special optimized version that handles 1 or more of uint32_ts. - * The length parameter here is the number of uint32_ts in the key. - */ -static inline uint32_t jhash2(uint32_t *k, uint32_t length, uint32_t initval) -{ - uint32_t a, b, c, len; - - a = b = JHASH_GOLDEN_RATIO; - c = initval; - len = length; - - while (len >= 3) { - a += k[0]; - b += k[1]; - c += k[2]; - __jhash_mix(a, b, c); - k += 3; len -= 3; - } - - c += length * 4; - - switch (len) { - case 2 : b += k[1]; - case 1 : a += k[0]; - }; - - __jhash_mix(a,b,c); - - return c; -} - - -/* A special ultra-optimized versions that knows they are hashing exactly - * 3, 2 or 1 word(s). - * - * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally - * done at the end is not done here. - */ -static inline uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval) -{ - a += JHASH_GOLDEN_RATIO; - b += JHASH_GOLDEN_RATIO; - c += initval; - - __jhash_mix(a, b, c); - - return c; -} - -static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval) -{ - return jhash_3words(a, b, 0, initval); -} - -static inline uint32_t jhash_1word(uint32_t a, uint32_t initval) -{ - return jhash_3words(a, 0, 0, initval); -} - -static unsigned int get_randomness(int *state) -{ - return jhash_1word((*state)++, *state * 1103515243); -} - -static int state; - -/* Lengthening headers is pointless: other end will just wait for more - * data and timeout. We merely shorten the length. */ -static void corrupt_header(char *output, const struct xsd_sockmsg *msg, - unsigned int *next_bit) -{ - struct xsd_sockmsg newmsg = *msg; - - while (*next_bit < sizeof(*msg)) { - if (newmsg.len) - newmsg.len = get_randomness(&state) % newmsg.len; - *next_bit += get_randomness(&state) % RAND_FREQ; - } - memcpy(output, &newmsg, sizeof(newmsg)); -} - -#define read_all_choice read_all -static bool write_all_choice(int fd, const void *data, unsigned int len) -{ - char corrupt_data[len]; - bool ret; - static unsigned int next_bit; - - if (len == sizeof(struct xsd_sockmsg) - && ((unsigned long)data % __alignof__(struct xsd_sockmsg)) == 0) - corrupt_header(corrupt_data, data, &next_bit); - else { - memcpy(corrupt_data, data, len); - while (next_bit < len * CHAR_BIT) { - corrupt_data[next_bit/CHAR_BIT] - ^= (1 << (next_bit%CHAR_BIT)); - next_bit += get_randomness(&state) % RAND_FREQ; - } - } - - ret = xs_write_all(fd, corrupt_data, len); - next_bit -= len * CHAR_BIT; - return ret; -} - -#include "xs.c" - -static char *random_path(void) -{ - unsigned int i; - char *ret = NULL; - - if (get_randomness(&state) % 20 == 0) - return talloc_strdup(NULL, "/"); - - for (i = 0; i < 1 || (get_randomness(&state) % 2); i++) { - ret = talloc_asprintf_append(ret, "/%i", - get_randomness(&state) % 15); - } - return ret; -} - -/* Do the next operation, return the results. */ -static void do_next_op(struct xs_handle *h, bool verbose) -{ - char *name; - unsigned int num; - - if (verbose) - printf("State %i: ", state); - - name = random_path(); - switch (get_randomness(&state) % 9) { - case 0: - if (verbose) - printf("DIR %s\n", name); - free(xs_directory(h, name, &num)); - break; - case 1: - if (verbose) - printf("READ %s\n", name); - free(xs_read(h, name, &num)); - break; - case 2: { - char *contents = talloc_asprintf(NULL, "%i", - get_randomness(&state)); - unsigned int len = get_randomness(&state)%(strlen(contents)+1); - if (verbose) - printf("WRITE %s %.*s\n", name, len, contents); - xs_write(h, name, contents, len); - break; - } - case 3: - if (verbose) - printf("MKDIR %s\n", name); - xs_mkdir(h, name); - break; - case 4: - if (verbose) - printf("RM %s\n", name); - xs_rm(h, name); - break; - case 5: - if (verbose) - printf("GETPERMS %s\n", name); - free(xs_get_permissions(h, name, &num)); - break; - case 6: { - unsigned int i, num = get_randomness(&state)%8; - struct xs_permissions perms[num]; - - if (verbose) - printf("SETPERMS %s: ", name); - for (i = 0; i < num; i++) { - perms[i].id = get_randomness(&state)%8; - perms[i].perms = get_randomness(&state)%4; - if (verbose) - printf("%i%c ", perms[i].id, - perms[i].perms == XS_PERM_WRITE ? 'W' - : perms[i].perms == XS_PERM_READ ? 'R' - : perms[i].perms == - (XS_PERM_READ|XS_PERM_WRITE) ? 'B' - : 'N'); - } - if (verbose) - printf("\n"); - xs_set_permissions(h, name, perms, num); - break; - } - case 7: { - if (verbose) - printf("START %s\n", name); - xs_transaction_start(h); - break; - } - case 8: { - bool abort = (get_randomness(&state) % 2); - - if (verbose) - printf("STOP %s\n", abort ? "ABORT" : "COMMIT"); - xs_transaction_end(h, abort); - break; - } - default: - barf("Impossible randomness"); - } -} - -static struct xs_handle *h; -static void alarmed(int sig __attribute__((unused))) -{ - /* We force close on timeout. */ - close(h->fd); -} - -static int start_daemon(void) -{ - int fds[2]; - int daemon_pid; - - /* Start daemon. */ - pipe(fds); - if ((daemon_pid = fork())) { - /* Child writes PID when its ready: we wait for that. */ - char buffer[20]; - close(fds[1]); - if (read(fds[0], buffer, sizeof(buffer)) < 0) - barf("Failed to summon daemon"); - close(fds[0]); - return daemon_pid; - } else { - dup2(fds[1], STDOUT_FILENO); - close(fds[0]); -#if 1 - execlp("valgrind", "valgrind", "--log-file=/tmp/xs_crashme.vglog", "-q", "./xenstored_test", "--output-pid", - "--no-fork", "--trace-file=/tmp/trace", NULL); -#else - execlp("./xenstored_test", "xenstored_test", "--output-pid", - "--no-fork", NULL); -#endif - exit(1); - } -} - - -int main(int argc, char **argv) -{ - unsigned int i; - int pid; - - if (argc != 3 && argc != 4) - barf("Usage: xs_crashme <iterations> <seed> [pid]"); - - if (argc == 3) - pid = start_daemon(); - else - pid = atoi(argv[3]); - - state = atoi(argv[2]); - h = xs_daemon_open(); - if (!h) - barf_perror("Opening connection to daemon"); - signal(SIGALRM, alarmed); - for (i = 0; i < (unsigned)atoi(argv[1]); i++) { - alarm(1); - do_next_op(h, false); - if (i % (atoi(argv[1]) / 72 ?: 1) == 0) { - printf("."); - fflush(stdout); - } - if (kill(pid, 0) != 0) - barf_perror("Pinging daemon on iteration %i", i); - if (h->fd < 0) { - xs_daemon_close(h); - h = xs_daemon_open(); - if (!h) - barf_perror("Connecting on iteration %i", i); - } - } - kill(pid, SIGTERM); - return 0; -} - diff -r 87b0b6a08dbd -r 42586a0f4407 tools/xenstore/xs_random.c --- a/tools/xenstore/xs_random.c Mon Jul 09 09:22:58 2007 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1590 +0,0 @@ -/* Random tests. - - We check that the results from a real filesystem are the same. -*/ -#include <sys/types.h> -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <dirent.h> -#include <errno.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/wait.h> -#include "xs.h" -#include "talloc.h" -#include "utils.h" - -struct ops -{ - char *name; - - char **(*dir)(void *h, const char *path, unsigned int *num); - - void *(*read)(void *h, const char *path, unsigned int *len); - - bool (*write)(void *h, const char *path, const void *data, - unsigned int len); - - bool (*mkdir)(void *h, const char *path); - - bool (*rm)(void *h, const char *path); - - struct xs_permissions *(*get_perms)(void *h, - const char *path, - unsigned int *num); - - bool (*set_perms)(void *h, - const char *path, - struct xs_permissions *perms, - unsigned int num); - - bool (*transaction_start)(void *h); - bool (*transaction_end)(void *h, bool abort); - - /* Create and destroy a new handle. */ - void *(*handle)(const char *path); - void (*close)(void *); -}; - -struct file_ops_info -{ - const char *base; - char *transact_base; -}; - -static void convert_to_dir(const char *dirname) -{ - char *tmpname = talloc_asprintf(dirname, "%s.tmp", dirname); - if (rename(dirname, tmpname) != 0) - barf_perror("Failed to rename %s to %s", dirname, tmpname); - if (mkdir(dirname, 0700) != 0) - barf_perror("Failed to mkdir %s", dirname); - if (rename(tmpname,talloc_asprintf(dirname, "%s/.DATA", dirname)) != 0) - barf_perror("Failed to rename into %s", dirname); - /* If perms exists, move it in. */ - rename(talloc_asprintf(dirname, "%s.perms", dirname), - talloc_asprintf(dirname, "%s/.perms", dirname)); -} - -/* Files can be used as dirs, too. Convert them when they are. */ -static void maybe_convert_to_directory(const char *filename) -{ - struct stat st; - char *dirname = talloc_asprintf( - filename, "%.*s", - (int)(strrchr(filename, '/') - filename), filename); - if (lstat(dirname, &st) == 0 && S_ISREG(st.st_mode)) - convert_to_dir(dirname); -} - -static char *get_name(struct file_ops_info *info, const char *path) -{ - if (info->transact_base) - return talloc_asprintf(path, "%s%s", info->transact_base, - path); - return talloc_asprintf(path, "%s%s", info->base, path); -} - -static char *path_to_name(struct file_ops_info *info, const char *path) -{ - char *filename = get_name(info, path); - maybe_convert_to_directory(filename); - return filename; -} - -static char **file_directory(struct file_ops_info *info, - const char *path, unsigned int *num) -{ - char **ret; - DIR *dir; - struct dirent *dirent; - char *p, *dirname = path_to_name(info, path); - unsigned int i, len = 0; - struct stat st; - - /* If it exists, but isn't a directory, we convert it. */ - if (lstat(dirname, &st) == 0 && !S_ISDIR(st.st_mode)) - convert_to_dir(dirname); - - *num = 0; - dir = opendir(dirname); - if (!dir) - return NULL;; - - /* Once to count them. */ - while ((dirent = readdir(dir)) != NULL) { - if (strchr(dirent->d_name, '.')) - continue; - len += strlen(dirent->d_name) + 1; - (*num)++; - } - rewinddir(dir); - - /* Now allocate and fill in. */ - ret = malloc(sizeof(char *) * *num + len); - p = (char *)&ret[*num]; - i = 0; - while ((dirent = readdir(dir)) != NULL) { - if (strchr(dirent->d_name, '.')) - continue; - ret[i] = p; - strcpy(p, dirent->d_name); - p += strlen(p) + 1; - i++; - } - closedir(dir); - - return ret; -} - -static char *filename_to_data(const char *filename) -{ - struct stat st; - - if (lstat(filename, &st) == 0 && S_ISDIR(st.st_mode)) - return talloc_asprintf(filename, "%s/.DATA", filename); - return (char *)filename; -} - -static void *file_read(struct file_ops_info *info, - const char *path, unsigned int *len) -{ - void *ret; - char *filename = filename_to_data(path_to_name(info, path)); - unsigned long size; - - ret = grab_file(filename, &size); - /* Directory exists, .DATA doesn't. */ - if (!ret && errno == ENOENT && strends(filename, ".DATA")) { - ret = strdup(""); - size = 0; - } - *len = size; - return ret; -} - -static struct xs_permissions *file_get_perms(struct file_ops_info *info, - const char *path, - unsigned int *num) -{ - void *perms; - struct xs_permissions *ret; - char *filename = path_to_name(info, path); - char *permfile; - unsigned long size; - struct stat st; - - if (lstat(filename, &st) != 0) - return NULL; - - if (S_ISDIR(st.st_mode)) - permfile = talloc_asprintf(path, "%s/.perms", filename); - else - permfile = talloc_asprintf(path, "%s.perms", filename); - - perms = grab_file(permfile, &size); - if (!perms) - barf("Grabbing permissions for %s", permfile); - *num = xs_count_strings(perms, size); - - ret = new_array(struct xs_permissions, *num); - if (!xs_strings_to_perms(ret, *num, perms)) - barf("Reading permissions from %s", permfile); - release_file(perms, size); - return ret; -} - -static void do_command(const char *cmd) -{ - int ret; - - ret = system(cmd); - if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) - barf_perror("Failed '%s': %i", cmd, ret); -} - -static void init_perms(const char *filename) -{ - struct stat st; - char *permfile, *command; - - if (lstat(filename, &st) != 0) - barf_perror("Failed to stat %s", filename); - - if (S_ISDIR(st.st_mode)) - permfile = talloc_asprintf(filename, "%s/.perms", filename); - else - permfile = talloc_asprintf(filename, "%s.perms", filename); - - /* Leave permfile if it already exists. */ - if (lstat(permfile, &st) == 0) - return; - - /* Copy permissions from parent */ - command = talloc_asprintf(filename, "cp %.*s/.perms %s", - (int)(strrchr(filename, '/') - filename), - filename, permfile); - do_command(command); -} - -static bool file_set_perms(struct file_ops_info *info, - const char *path, - struct xs_permissions *perms, - unsigned int num) -{ - unsigned int i; - char *filename = path_to_name(info, path); - char *permfile; - int fd; - struct stat st; - - if (num < 1) { - errno = EINVAL; - return false; - } - - /* Check non-perm file exists/ */ - if (lstat(filename, &st) != 0) - return false; - - if (S_ISDIR(st.st_mode)) - permfile = talloc_asprintf(path, "%s/.perms", filename); - else - permfile = talloc_asprintf(path, "%s.perms", filename); - - fd = open(permfile, O_WRONLY|O_CREAT|O_TRUNC, 0600); - if (fd < 0) - return false; - - for (i = 0; i < num; i++) { - char buffer[100]; - - if (!xs_perm_to_string(&perms[i], buffer)) { - int saved_errno = errno; - close(fd); - errno = saved_errno; - return false; - } - if (write(fd, buffer, strlen(buffer) + 1) - != (int)strlen(buffer) + 1) - barf_perror("Failed to write perm"); - } - close(fd); - return true; -} - -static char *parent_filename(const char *name) -{ - char *slash = strrchr(name + 1, '/'); - if (!slash) - return talloc_strdup(name, "/"); - return talloc_asprintf(name, "%.*s", (int)(slash-name), name); -} - -static void make_dirs(const char *filename) -{ - struct stat st; - - if (lstat(filename, &st) == 0 && S_ISREG(st.st_mode)) - convert_to_dir(filename); - - if (mkdir(filename, 0700) == 0) { - init_perms(filename); - return; - } - if (errno == EEXIST) - return; - - make_dirs(parent_filename(filename)); - if (mkdir(filename, 0700) != 0) - barf_perror("Failed to mkdir %s", filename); - init_perms(filename); -} - -static bool file_write(struct file_ops_info *info, - const char *path, const void *data, - unsigned int len) -{ - char *filename = filename_to_data(path_to_name(info, path)); - int fd; - - make_dirs(parent_filename(filename)); - fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0600); - if (fd < 0) - return false; - - if (write(fd, data, len) != (int)len) - barf_perror("Bad write to %s", filename); - - init_perms(filename); - close(fd); - return true; -} - -static bool file_mkdir(struct file_ops_info *info, const char *path) -{ - char *dirname = path_to_name(info, path); - - make_dirs(parent_filename(dirname)); - if (mkdir(dirname, 0700) != 0) - return (errno == EEXIST); - - init_perms(dirname); - return true; -} - -static bool file_rm(struct file_ops_info *info, const char *path) -{ - char *filename = path_to_name(info, path); - struct stat st; - - if (lstat(filename, &st) != 0) { - if (lstat(parent_filename(filename), &st) != 0) - return false; - return true; - } - - if (streq(path, "/")) { - errno = EINVAL; - return false; - } - - do_command(talloc_asprintf(path, "rm -f %s.perms; rm -r %s", - filename, filename)); - return true; -} - -static bool file_transaction_start(struct file_ops_info *info) -{ - char *cmd; - - if (info->transact_base) { - errno = EBUSY; - return false; - } - - info->transact_base = talloc_asprintf(NULL, "%s.transact", info->base); - cmd = talloc_asprintf(NULL, "cp -r %s %s", - info->base, info->transact_base); - do_command(cmd); - talloc_free(cmd); - return true; -} - -static bool file_transaction_end(struct file_ops_info *info, bool abort) -{ - char *old, *cmd; - - if (!info->transact_base) { - errno = ENOENT; - return false; - } - - if (abort) { - cmd = talloc_asprintf(NULL, "rm -rf %s", info->transact_base); - do_command(cmd); - goto success; - } - - old = talloc_asprintf(NULL, "rm -rf %s", info->base); - do_command(old); - talloc_free(old); - - cmd = talloc_asprintf(NULL, "mv %s %s", - info->transact_base, info->base); - do_command(cmd); - -success: - talloc_free(cmd); - talloc_free(info->transact_base); - info->transact_base = NULL; - return true; -} - -static struct file_ops_info *file_handle(const char *dir) -{ - struct file_ops_info *info = talloc(NULL, struct file_ops_info); - - info->base = dir; - info->transact_base = NULL; - return info; -} - -static void file_close(struct file_ops_info *handle) -{ - talloc_free(handle); -} - -static struct xs_handle *xs_handle(const char *dir __attribute__((unused))) -{ - struct xs_handle *h; - - h = xs_daemon_open(); - if (!h) - barf_perror("Connecting to xs daemon"); - return h; -} - -static void xs_close(struct xs_handle *handle) -{ - xs_daemon_close(handle); -} - -struct ops file_ops = { - .name = "FILE", - .dir = (void *)file_directory, - .read = (void *)file_read, - .write = (void *)file_write, - .mkdir = (void *)file_mkdir, - .rm = (void *)file_rm, - .get_perms = (void *)file_get_perms, - .set_perms = (void *)file_set_perms, - .transaction_start = (void *)file_transaction_start, - .transaction_end = (void *)file_transaction_end, - .handle = (void *)file_handle, - .close = (void *)file_close, -}; - -struct ops xs_ops = { - .name = "XS", - .dir = (void *)xs_directory, - .read = (void *)xs_read, - .write = (void *)xs_write, - .mkdir = (void *)xs_mkdir, - .rm = (void *)xs_rm, - .get_perms = (void *)xs_get_permissions, - .set_perms = (void *)xs_set_permissions, - .transaction_start = (void *)xs_transaction_start, - .transaction_end = (void *)xs_transaction_end, - .handle = (void *)xs_handle, - .close = (void *)xs_close, -}; - -static int strptrcmp(const void *a, const void *b) -{ - return strcmp(*(char **)a, *(char **)b); -} - -static void sort_dir(char **dir, unsigned int num) -{ - qsort(dir, num, sizeof(char *), strptrcmp); -} - -static char *dump_dir(struct ops *ops, - void *h, - const char *node, - char **dir, - unsigned int numdirs, - unsigned int depth) -{ - char *ret = talloc_strdup(node, ""); - unsigned int i; - char spacing[depth+1]; - - memset(spacing, ' ', depth); - spacing[depth] = '\0'; - - sort_dir(dir, numdirs); - - for (i = 0; i < numdirs; i++) { - struct xs_permissions *perms; - unsigned int j, numperms; - unsigned int len; - char *contents; - unsigned int subnum; - char **subdirs; - char *subret; - char *subnode = talloc_asprintf(node, "%s/%s", node, dir[i]); - - perms = ops->get_perms(h, subnode, &numperms); - if (!perms) - return NULL; - ret = talloc_asprintf_append(ret, "%s%s: ", spacing, dir[i]); - for (j = 0; j < numperms; j++) { - char buffer[100]; - if (!xs_perm_to_string(&perms[j], buffer)) - barf("perm to string"); - ret = talloc_asprintf_append(ret, "%s ", buffer); - } - free(perms); - ret = talloc_asprintf_append(ret, "\n"); - - /* Even directories can have contents. */ - contents = ops->read(h, subnode, &len); - if (!contents) { - if (errno != EISDIR) - return NULL; - } else { - ret = talloc_asprintf_append(ret, " %s(%.*s)\n", - spacing, len, contents); - free(contents); - } - - /* Every node is a directory. */ - subdirs = ops->dir(h, subnode, &subnum); - if (!subdirs) - return NULL; - subret = dump_dir(ops, h, subnode, subdirs, subnum, depth+1); - if (!subret) - return NULL; - ret = talloc_asprintf_append(ret, "%s", subret); - free(subdirs); - } - return ret; -} - -static char *dump(struct ops *ops, void *h) -{ - char **subdirs; - unsigned int subnum; - char *ret = NULL, *root = talloc_strdup(NULL, "/"); - - subdirs = ops->dir(h, root, &subnum); - if (subdirs) { - ret = dump_dir(ops, h, talloc_strdup(root, ""), subdirs, - subnum, 0); - free(subdirs); - if (ret) - talloc_steal(NULL, ret); - } - talloc_free(root); - return ret; -} - -/* jhash.h: Jenkins hash support. - * - * Copyright (C) 1996 Bob Jenkins (bob_jenkins@xxxxxxxxxxxxxxxx) - * - * http://burtleburtle.net/bob/hash/ - * - * These are the credits from Bob's sources: - * - * lookup2.c, by Bob Jenkins, December 1996, Public Domain. - * hash(), hash2(), hash3, and mix() are externally useful functions. - * Routines to test the hash are included if SELF_TEST is defined. - * You can use this free for any purpose. It has no warranty. - * - * Copyright (C) 2003 David S. Miller (davem@xxxxxxxxxx) - * - * I've modified Bob's hash to be useful in the Linux kernel, and - * any bugs present are surely my fault. -DaveM - */ - -/* NOTE: Arguments are modified. */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} - -/* The golden ration: an arbitrary value */ -#define JHASH_GOLDEN_RATIO 0x9e3779b9 - -/* The most generic version, hashes an arbitrary sequence - * of bytes. No alignment or length assumptions are made about - * the input key. - */ -static inline uint32_t jhash(const void *key, uint32_t length, uint32_t initval) -{ - uint32_t a, b, c, len; - const uint8_t *k = key; - - len = length; - a = b = JHASH_GOLDEN_RATIO; - c = initval; - - while (len >= 12) { - a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); - b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); - c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); - - __jhash_mix(a,b,c); - - k += 12; - len -= 12; - } - - c += length; - switch (len) { - case 11: c += ((uint32_t)k[10]<<24); - case 10: c += ((uint32_t)k[9]<<16); - case 9 : c += ((uint32_t)k[8]<<8); - case 8 : b += ((uint32_t)k[7]<<24); - case 7 : b += ((uint32_t)k[6]<<16); - case 6 : b += ((uint32_t)k[5]<<8); - case 5 : b += k[4]; - case 4 : a += ((uint32_t)k[3]<<24); - case 3 : a += ((uint32_t)k[2]<<16); - case 2 : a += ((uint32_t)k[1]<<8); - case 1 : a += k[0]; - }; - - __jhash_mix(a,b,c); - - return c; -} - -/* A special optimized version that handles 1 or more of uint32_ts. - * The length parameter here is the number of uint32_ts in the key. - */ -static inline uint32_t jhash2(uint32_t *k, uint32_t length, uint32_t initval) -{ - uint32_t a, b, c, len; - - a = b = JHASH_GOLDEN_RATIO; - c = initval; - len = length; - - while (len >= 3) { - a += k[0]; - b += k[1]; - c += k[2]; - __jhash_mix(a, b, c); - k += 3; len -= 3; - } - - c += length * 4; - - switch (len) { - case 2 : b += k[1]; - case 1 : a += k[0]; - }; - - __jhash_mix(a,b,c); - - return c; -} - - -/* A special ultra-optimized versions that knows they are hashing exactly - * 3, 2 or 1 word(s). - * - * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally - * done at the end is not done here. - */ -static inline uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval) -{ - a += JHASH_GOLDEN_RATIO; - b += JHASH_GOLDEN_RATIO; - c += initval; - - __jhash_mix(a, b, c); - - return c; -} - -static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval) -{ - return jhash_3words(a, b, 0, initval); -} - -static inline uint32_t jhash_1word(uint32_t a, uint32_t initval) -{ - return jhash_3words(a, 0, 0, initval); -} - -static unsigned int get_randomness(int *state) -{ - return jhash_1word((*state)++, *state * 1103515243); -} - -static char *random_path(int *state) -{ - unsigned int i; - char *ret = NULL; - - if (get_randomness(state) % 20 == 0) - return talloc_strdup(NULL, "/"); - - for (i = 0; i < 1 || (get_randomness(state) % 2); i++) { - ret = talloc_asprintf_append(ret, "/%i", - get_randomness(state) % 15); - } - return ret; -} - -static char *bool_to_errstring(bool result) -{ - if (result) - return talloc_strdup(NULL, "OK"); - - /* Real daemon can never return this. */ - if (errno == ENOTDIR) - errno = ENOENT; - return talloc_asprintf(NULL, "FAILED:%s", strerror(errno)); -} - -static char *linearize_dir(char **dir, unsigned int *num) -{ - char *result = NULL; - unsigned int i; - - if (!dir) - return bool_to_errstring(false); - - if (!*num) { - free(dir); - return talloc_strdup(NULL, ""); - } - - sort_dir(dir, *num); - for (i = 0; i < *num; i++) - result = talloc_asprintf_append(result, "%s\n", dir[i]); - free(dir); - return result; -} - -static char *linearize_read(char *read, unsigned int *size) -{ - char *ret; - - if (!read) - return bool_to_errstring(false); - - ret = talloc_asprintf(NULL, "%i:%.*s", *size, *size, read); - free(read); - return ret; -} - -static char *linearize_perms(struct xs_permissions *perms, unsigned int *size) -{ - char *ret = NULL; - unsigned int i; - - if (!perms) - return bool_to_errstring(false); - - for (i = 0; i < *size; i++) - ret = talloc_asprintf_append(ret, "(%u %u)", - perms[i].id, perms[i].perms); - - free(perms); - return ret; -} - -/* Do the next operation, return the results. */ -static char *do_next_op(struct ops *ops, void *h, int state, bool verbose) -{ - char *name; - unsigned int num; - char *ret; - - if (verbose) - printf("State %i: ", state); - - name = random_path(&state); - switch (get_randomness(&state) % 9) { - case 0: - if (verbose) - printf("DIR %s\n", name); - ret = linearize_dir(ops->dir(h, name, &num), &num); - break; - case 1: - if (verbose) - printf("READ %s\n", name); - ret = linearize_read(ops->read(h, name, &num), &num); - break; - case 2: { - char *contents = talloc_asprintf(NULL, "%i", - get_randomness(&state)); - unsigned int len = get_randomness(&state)%(strlen(contents)+1); - if (verbose) - printf("WRITE %s %.*s\n", name, len, contents); - ret = bool_to_errstring(ops->write(h, name, contents, len)); - talloc_steal(ret, contents); - break; - } - case 3: - if (verbose) - printf("MKDIR %s\n", name); - ret = bool_to_errstring(ops->mkdir(h, name)); - break; - case 4: - if (verbose) - printf("RM %s\n", name); - ret = bool_to_errstring(ops->rm(h, name)); - break; - case 5: - if (verbose) - printf("GETPERMS %s\n", name); - ret = linearize_perms(ops->get_perms(h, name, &num), - &num); - break; - case 6: { - unsigned int i, num = get_randomness(&state)%8; - struct xs_permissions perms[num]; - - if (verbose) - printf("SETPERMS %s: ", name); - for (i = 0; i < num; i++) { - perms[i].id = get_randomness(&state)%8; - perms[i].perms = get_randomness(&state)%4; - if (verbose) - printf("%i%c ", perms[i].id, - perms[i].perms == XS_PERM_WRITE ? 'W' - : perms[i].perms == XS_PERM_READ ? 'R' - : perms[i].perms == - (XS_PERM_READ|XS_PERM_WRITE) ? 'B' - : 'N'); - } - if (verbose) - printf("\n"); - ret = bool_to_errstring(ops->set_perms(h, name, perms, - num)); - break; - } - case 7: { - if (verbose) - printf("START %s\n", name); - ret = bool_to_errstring(ops->transaction_start(h)); - if (streq(ret, "OK")) { - talloc_free(ret); - ret = talloc_asprintf(NULL, "OK:START-TRANSACT"); - } - - break; - } - case 8: { - bool abort = (get_randomness(&state) % 2); - - if (verbose) - printf("STOP %s\n", abort ? "ABORT" : "COMMIT"); - ret = bool_to_errstring(ops->transaction_end(h, abort)); - if (streq(ret, "OK")) { - talloc_free(ret); - ret = talloc_strdup(NULL, "OK:STOP-TRANSACT"); - } - break; - } - default: - barf("Impossible randomness"); - } - - talloc_steal(ret, name); - return ret; -} - -static int daemon_pid; - -static void cleanup_xs_ops(void) -{ - char *cmd; - - if (daemon_pid) { _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |