aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.rootkeys32
-rw-r--r--BitKeeper/etc/ignore2
-rw-r--r--BitKeeper/etc/logging_ok2
-rw-r--r--Config.mk3
-rw-r--r--buildconfigs/Rules.mk3
-rw-r--r--docs/misc/shype4xen_readme.txt570
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/Makefile8
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig13
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile1
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c7
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c101
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/netfront/netfront.c10
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c30
-rw-r--r--linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/hypercall.h31
-rw-r--r--linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h57
-rw-r--r--linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h2
-rw-r--r--patches/linux-2.6.11/smp-alts.patch554
-rw-r--r--tools/Makefile2
-rw-r--r--tools/firmware/vmxassist/Makefile4
-rw-r--r--tools/firmware/vmxassist/setup.c6
-rw-r--r--tools/firmware/vmxassist/vm86.c11
-rw-r--r--tools/ioemu/hw/i8259.c2
-rw-r--r--tools/ioemu/monitor.c327
-rw-r--r--tools/libxc/Makefile6
-rw-r--r--tools/libxc/xc.h8
-rw-r--r--tools/libxc/xc_domain.c3
-rw-r--r--tools/misc/policyprocessor/SecurityLabel.java34
-rw-r--r--tools/misc/policyprocessor/SecurityPolicySpec.xsd115
-rw-r--r--tools/misc/policyprocessor/SsidsEntry.java29
-rw-r--r--tools/misc/policyprocessor/XmlToBin.java1588
-rw-r--r--tools/misc/policyprocessor/XmlToBinInterface.java135
-rw-r--r--tools/misc/policyprocessor/myHandler.java47
-rw-r--r--tools/misc/policyprocessor/readme.install33
-rw-r--r--tools/misc/policyprocessor/readme.xen65
-rw-r--r--tools/misc/policyprocessor/xen_sample_def.xml46
-rw-r--r--tools/misc/policyprocessor/xen_sample_policy.xml58
-rw-r--r--tools/misc/xend18
-rw-r--r--tools/policy/Makefile36
-rw-r--r--tools/policy/policy_tool.c557
-rw-r--r--tools/python/setup.py2
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c10
-rw-r--r--tools/python/xen/lowlevel/xs/xs.c370
-rw-r--r--tools/python/xen/lowlevel/xu/xu.c16
-rw-r--r--tools/python/xen/xend/XendClient.py6
-rw-r--r--tools/python/xen/xend/XendDomain.py12
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py106
-rw-r--r--tools/python/xen/xend/image.py16
-rw-r--r--tools/python/xen/xend/server/SrvDomain.py8
-rw-r--r--tools/python/xen/xend/server/SrvDomainDir.py1
-rwxr-xr-xtools/python/xen/xend/server/blkif.py11
-rwxr-xr-xtools/python/xen/xend/server/channel.py8
-rwxr-xr-xtools/python/xen/xend/server/console.py3
-rw-r--r--tools/python/xen/xend/server/messages.py18
-rwxr-xr-xtools/python/xen/xend/server/netif.py22
-rw-r--r--tools/python/xen/xend/xenstore/xsnode.py257
-rw-r--r--tools/python/xen/xend/xenstore/xsobj.py96
-rw-r--r--tools/python/xen/xm/create.py7
-rw-r--r--tools/python/xen/xm/main.py45
-rw-r--r--tools/python/xen/xm/opts.py7
-rw-r--r--tools/xenstore/Makefile37
-rw-r--r--tools/xenstore/testsuite/07watch.sh116
-rw-r--r--tools/xenstore/testsuite/10domain-homedir.sh12
-rw-r--r--tools/xenstore/testsuite/11domain-watch.sh51
-rw-r--r--tools/xenstore/testsuite/12readonly.sh40
-rwxr-xr-xtools/xenstore/testsuite/test.sh2
-rw-r--r--tools/xenstore/xenstored_core.c126
-rw-r--r--tools/xenstore/xenstored_core.h19
-rw-r--r--tools/xenstore/xenstored_domain.c28
-rw-r--r--tools/xenstore/xenstored_domain.h4
-rw-r--r--tools/xenstore/xenstored_transaction.c1
-rw-r--r--tools/xenstore/xenstored_watch.c189
-rw-r--r--tools/xenstore/xenstored_watch.h20
-rw-r--r--tools/xenstore/xs.c70
-rw-r--r--tools/xenstore/xs.h45
-rw-r--r--tools/xenstore/xs_dom0_test.c43
-rw-r--r--tools/xenstore/xs_lib.c3
-rw-r--r--tools/xenstore/xs_lib.h8
-rw-r--r--tools/xenstore/xs_stress.c2
-rw-r--r--tools/xenstore/xs_test.c39
-rw-r--r--tools/xenstore/xs_watch_stress.c120
-rw-r--r--xen/Makefile6
-rw-r--r--xen/Rules.mk3
-rw-r--r--xen/acm/Makefile15
-rw-r--r--xen/acm/acm_chinesewall_hooks.c503
-rw-r--r--xen/acm/acm_core.c205
-rw-r--r--xen/acm/acm_null_hooks.c76
-rw-r--r--xen/acm/acm_policy.c197
-rw-r--r--xen/acm/acm_simple_type_enforcement_hooks.c638
-rw-r--r--xen/arch/x86/cpu/amd.c29
-rw-r--r--xen/arch/x86/cpu/common.c49
-rw-r--r--xen/arch/x86/cpu/cpu.h1
-rw-r--r--xen/arch/x86/cpu/intel.c23
-rw-r--r--xen/arch/x86/dom0_ops.c4
-rw-r--r--xen/arch/x86/mm.c22
-rw-r--r--xen/arch/x86/setup.c13
-rw-r--r--xen/arch/x86/smpboot.c32
-rw-r--r--xen/arch/x86/x86_32/entry.S1
-rw-r--r--xen/common/dom0_ops.c37
-rw-r--r--xen/common/event_channel.c4
-rw-r--r--xen/common/grant_table.c6
-rw-r--r--xen/common/kernel.c41
-rw-r--r--xen/common/policy_ops.c137
-rw-r--r--xen/common/schedule.c44
-rw-r--r--xen/include/acm/acm_core.h117
-rw-r--r--xen/include/acm/acm_endian.h88
-rw-r--r--xen/include/acm/acm_hooks.h349
-rw-r--r--xen/include/asm-x86/page.h12
-rw-r--r--xen/include/asm-x86/processor.h1
-rw-r--r--xen/include/asm-x86/smp.h2
-rw-r--r--xen/include/asm-x86/x86_32/page-2level.h2
-rw-r--r--xen/include/asm-x86/x86_32/page-3level.h2
-rw-r--r--xen/include/asm-x86/x86_32/page.h2
-rw-r--r--xen/include/public/acm.h161
-rw-r--r--xen/include/public/dom0_ops.h3
-rw-r--r--xen/include/public/io/domain_controller.h20
-rw-r--r--xen/include/public/policy_ops.h74
-rw-r--r--xen/include/public/version.h30
-rw-r--r--xen/include/public/xen.h4
-rw-r--r--xen/include/xen/sched.h7
-rw-r--r--xen/include/xen/smp.h2
-rw-r--r--xen/include/xen/string.h5
121 files changed, 8904 insertions, 615 deletions
diff --git a/.rootkeys b/.rootkeys
index 390cee03b1..29ea9db08f 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -21,6 +21,7 @@
420b949cy9ZGzED74Fz_DaWlK7tT4g docs/misc/crashdb.txt
4251a1f82AexscYEiF4Iku8Gc_kWfQ docs/misc/grant-tables.txt
424d462b5GuApQ_NyMsRFt9LbrsWow docs/misc/sedf_scheduler_mini-HOWTO.txt
+42b7434c-M2l4Og0klGf6xSAARqa2w docs/misc/shype4xen_readme.txt
40d6ccbfKKBq8jE0ula4eHEzBiQuDA docs/misc/xen_config.html
410a4c2bAO_m_l4RsiiPHnZ4ixHWbQ docs/misc/xend.tex
3f9e7d564bWFB-Czjv1qdmE6o0GqNg docs/src/interface.tex
@@ -470,6 +471,7 @@
428359d4b3fDYtazwXi4UUmSWaOUew patches/linux-2.6.11/linux-2.6.11.12.patch
4296fb998LGSWCcljGKbOCUv3h9uRQ patches/linux-2.6.11/net-csum.patch
429ae875I9ZrqrRDjGD34IC2kzDREw patches/linux-2.6.11/rcu-nohz.patch
+42b165fcilFTNezi9NIsG2ecLZVU0w patches/linux-2.6.11/smp-alts.patch
429ba3007184K-y6WHQ6KgY65-lEIQ patches/linux-2.6.11/udp-frag.patch
424f001e_M1Tnxc52rDrmCLelnDWMQ patches/linux-2.6.11/x86_64-linux.patch
3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
@@ -776,6 +778,16 @@
40c9c469kT0H9COWzA4XzPBjWK0WsA tools/misc/netfix
4022a73cEKvrYe_DVZW2JlAxobg9wg tools/misc/nsplitd/Makefile
4022a73cKms4Oq030x2JBzUB426lAQ tools/misc/nsplitd/nsplitd.c
+42b74436oXEaaUH_dPcGFviMiwNgCQ tools/misc/policyprocessor/SecurityLabel.java
+42b74436fIW8ZI3pUpu13-Ox6G2cOA tools/misc/policyprocessor/SecurityPolicySpec.xsd
+42b74436T4CN4HMWsuaHD2zS8jY1BA tools/misc/policyprocessor/SsidsEntry.java
+42b74436Dk3WKJl6-SyP3LEBo3DXkQ tools/misc/policyprocessor/XmlToBin.java
+42b74436ABj4SOVBWqY_IEIboFUkeA tools/misc/policyprocessor/XmlToBinInterface.java
+42b7443684kBOrEBKFod4fGvnJ-rdA tools/misc/policyprocessor/myHandler.java
+42b74436JjvZmOp2DfMb-TnpGZXQ8w tools/misc/policyprocessor/readme.install
+42b74436-0Ig0yb-w1BYyCAFVTwqUg tools/misc/policyprocessor/readme.xen
+42b74436WAJ6lmTO3foadk2527PFBQ tools/misc/policyprocessor/xen_sample_def.xml
+42b744365VrTALmqRroQOBZ9EopUsw tools/misc/policyprocessor/xen_sample_policy.xml
42308df9dv_ZuP49nNPIROEMQ3F_LA tools/misc/xc_shadow.c
3f5ef5a2ir1kVAthS14Dc5QIRCEFWg tools/misc/xen-clone
3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README
@@ -784,6 +796,8 @@
41adc641dV-0cDLSyzMs5BT8nL7v3Q tools/misc/xenperf.c
4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops
40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
+42b742f6JFcp6LFpYu-B4AEsfQwSFw tools/policy/Makefile
+42b742f66XOdRMrwaHvbCdSSQyCrFw tools/policy/policy_tool.c
4270cc81g3nSNYCZ1ryCMDEbLtMtbQ tools/pygrub/Makefile
4270deeccyRsJn6jLnRh9odRtMW9SA tools/pygrub/README
4270cc81EIl7NyaS3Av6IPRk2c2a6Q tools/pygrub/setup.py
@@ -1065,6 +1079,9 @@
42a57d98fdO519YyATk4_Zwr1STNfQ tools/xenstore/testsuite/07watch.sh
42a57d98zZUtvirUMjmHxFphJjmO7Q tools/xenstore/testsuite/08transaction.sh
42a57d98sn9RbpBgHRv1D99Kt7LwYA tools/xenstore/testsuite/09domain.sh
+42b2a4bfxAwHlRgd31SJBgFnj8g3MA tools/xenstore/testsuite/10domain-homedir.sh
+42b2a4bfHbUp4IB8tfNIa8j37S27fw tools/xenstore/testsuite/11domain-watch.sh
+42b2a4bfhrB5v6uYKPj6jSO_Ng0PAA tools/xenstore/testsuite/12readonly.sh
42a57d98tSuoFCHnnM2GgENXJrRQmw tools/xenstore/testsuite/test.sh
42a57d98zxDP2Ti7dTznGROi66rUGw tools/xenstore/utils.c
42a57d98SDvOYCEjmCjwHSk6390GLA tools/xenstore/utils.h
@@ -1080,11 +1097,13 @@
42a57d99-zLxBjzC7rfj_perV-orUg tools/xenstore/xenstored_watch.h
42a57d99BnkhISKgCCRcUqhteyuxCw tools/xenstore/xs.c
42a57d99FyiYSz9AkKKROrRydnA-gQ tools/xenstore/xs.h
+42b29922EYQ87Y4fwZXSkEHgtQk7CQ tools/xenstore/xs_dom0_test.c
42a57d99SrtsJCDUlKyRPf3EX86A1Q tools/xenstore/xs_lib.c
42a57d99L2pYeMFyjQ_4Rnb17xTSMg tools/xenstore/xs_lib.h
42a57d99Kl6Ba8oCHv2fggl7QN9QZA tools/xenstore/xs_random.c
42a57d99SHYR1lQOD0shuErPDg9NKQ tools/xenstore/xs_stress.c
42a57d996aBawpkQNOWkNWXD6LrhPg tools/xenstore/xs_test.c
+42b2a4bfp-lhxBfenUyHlvw7bPcVgA tools/xenstore/xs_watch_stress.c
403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c
@@ -1095,6 +1114,12 @@
3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
+42b742f6XHTfIEm_hUPtzjKr37LVhw xen/acm/Makefile
+42b742f6tHzn0fZWH3TjPva8gbqpow xen/acm/acm_chinesewall_hooks.c
+42b742f6bM8kZwuIUbepHZ8SQQkjJA xen/acm/acm_core.c
+42b742f6cwfrPubqH47gQpke8xkYSA xen/acm/acm_null_hooks.c
+42b742f69qSxm5MM-wtPaWtCqyI3KA xen/acm/acm_policy.c
+42b742f6VbmdlwekQRMhXugjcu9QXg xen/acm/acm_simple_type_enforcement_hooks.c
421098b25A0RvuYN3rP28ga3_FN3_Q xen/arch/ia64/Makefile
421098b2okIeYXS9w9avmSozls61xA xen/arch/ia64/Rules.mk
421098b21p12UcKjHBrLh_LjlvNEwA xen/arch/ia64/acpi.c
@@ -1321,6 +1346,7 @@
41a61536SZbR6cj1ukWTb0DYU-vz9w xen/common/multicall.c
3ddb79bdD4SLmmdMD7yLW5HcUWucXw xen/common/page_alloc.c
3e54c38dkHAev597bPr71-hGzTdocg xen/common/perfc.c
+42b742f6mgq9puEr7lUrLST0VEpsig xen/common/policy_ops.c
40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c
41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c
3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c
@@ -1336,6 +1362,9 @@
4049e6bfNSIq7s7OV-Bd69QD0RpR2Q xen/drivers/char/console.c
4298e018XQtZkCdufpyFimOGZqqsFA xen/drivers/char/ns16550.c
3e4a8cb7nMChlro4wvOBo76n__iCFA xen/drivers/char/serial.c
+42b742f6OteAMPWnoqxqfRX3yxD0yw xen/include/acm/acm_core.h
+42b742f6XfIijctEwA0YWL2BoWtDNg xen/include/acm/acm_endian.h
+42b742f6jXvp1vdbU2v2WJjTPku65A xen/include/acm/acm_hooks.h
40715b2cFpte_UNWnBZW0Du7z9AhTQ xen/include/acpi/acconfig.h
40715b2ctNvVZ058w8eM8DR9hOat_A xen/include/acpi/acexcep.h
40715b2com8I01qcHcAw47e93XsCqQ xen/include/acpi/acglobal.h
@@ -1488,6 +1517,7 @@
404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
422f27c8RHFkePhD34VIEpMMqofZcA xen/include/asm-x86/x86_emulate.h
400304fcmRQmDdFYEzDh0wcBba9alg xen/include/public/COPYING
+42b742f6duiOTlZvysQkRYZHYBXqvg xen/include/public/acm.h
421098b7OKb9YH_EUA_UpCxBjaqtgA xen/include/public/arch-ia64.h
404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/public/arch-x86_32.h
404f1bc7IwU-qnH8mJeVu0YsNGMrcw xen/include/public/arch-x86_64.h
@@ -1501,8 +1531,10 @@
41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
41ee5e8c6mLxIx82KPsbpt_uts_vSA xen/include/public/io/usbif.h
4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
+42b742f7Lzy8SKKG25L_-fgk5FHA2Q xen/include/public/policy_ops.h
40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
+42b5a5f2QC1IxeuwCwwsOEhvcJ2BJg xen/include/public/version.h
4266bd01Ul-pC01ZVvBkhBnv5eqzvw xen/include/public/vmx_assist.h
3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/public/xen.h
3e397e66m2tO3s-J8Jnr7Ws_tGoPTg xen/include/xen/ac_timer.h
diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore
index 33edc625d6..a6d5a390a0 100644
--- a/BitKeeper/etc/ignore
+++ b/BitKeeper/etc/ignore
@@ -144,9 +144,11 @@ tools/xenstore/testsuite/tmp/*
tools/xenstore/xen
tools/xenstore/xenstored
tools/xenstore/xenstored_test
+tools/xenstore/xs_dom0_test
tools/xenstore/xs_random
tools/xenstore/xs_stress
tools/xenstore/xs_test
+tools/xenstore/xs_watch_stress
tools/xentrace/xentrace
tools/xfrd/xfrd
xen/BLOG
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index afc6cd647f..87c83d88c0 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -28,6 +28,7 @@ djm@djmnc4000.(none)
djm@kirby.fc.hp.com
djm@sportsman.spdomain
doogie@brainfood.com
+dsteklof@us.ibm.com
gm281@boulderdash.cl.cam.ac.uk
gm281@tetrapod.cl.cam.ac.uk
harry@dory.(none)
@@ -38,6 +39,7 @@ iap10@labyrinth.cl.cam.ac.uk
iap10@nidd.cl.cam.ac.uk
iap10@pb001.cl.cam.ac.uk
iap10@pb007.cl.cam.ac.uk
+iap10@spot.cl.cam.ac.uk
iap10@striker.cl.cam.ac.uk
iap10@tetris.cl.cam.ac.uk
jrb44@plym.cl.cam.ac.uk
diff --git a/Config.mk b/Config.mk
index b3320b2711..390a9b3abe 100644
--- a/Config.mk
+++ b/Config.mk
@@ -31,3 +31,6 @@ endif
LDFLAGS += $(foreach i, $(EXTRA_LIB), -L$(i))
CFLAGS += $(foreach i, $(EXTRA_INCLUDES), -I$(i))
+
+# Choose the best mirror to download linux kernel
+KERNEL_REPO = http://www.kernel.org
diff --git a/buildconfigs/Rules.mk b/buildconfigs/Rules.mk
index fe02b1e11b..f2e65f0046 100644
--- a/buildconfigs/Rules.mk
+++ b/buildconfigs/Rules.mk
@@ -27,7 +27,7 @@ vpath linux-%.tar.bz2 $(LINUX_SRC_PATH)
linux-%.tar.bz2: override _LINUX_VDIR = $(word 1,$(subst ., ,$*)).$(word 2,$(subst ., ,$*))
linux-%.tar.bz2:
@echo "Cannot find $@ in path $(LINUX_SRC_PATH)"
- wget http://www.kernel.org/pub/linux/kernel/v$(_LINUX_VDIR)/$@ -O./$@
+ wget $(KERNEL_REPO)/pub/linux/kernel/v$(_LINUX_VDIR)/$@ -O./$@
# Expand NetBSD release to NetBSD version
NETBSD_RELEASE ?= 2.0
@@ -57,6 +57,7 @@ $(patsubst %,pristine-%/.valid-pristine,$(ALLSPARSETREES)) : pristine-%/.valid-p
mkdir -p tmp-pristine-$*
touch tmp-pristine-$*/.bk_skip
tar -C tmp-pristine-$* -jxf $<
+ -@rm tmp-pristine-$*/pax_global_header
mv tmp-pristine-$*/* $(@D)
@rm -rf tmp-pristine-$*
touch $@ # update timestamp to avoid rebuild
diff --git a/docs/misc/shype4xen_readme.txt b/docs/misc/shype4xen_readme.txt
new file mode 100644
index 0000000000..35a2b359f3
--- /dev/null
+++ b/docs/misc/shype4xen_readme.txt
@@ -0,0 +1,570 @@
+Copyright: IBM Corporation (C)
+20 June 2005
+Author: Reiner Sailer
+
+This document is a very short introduction into the sHype access control
+security architecture implementation and how it is perceived by users. It
+is a very preliminary draft for the courageous ones to get "their feet wet"
+and to be able to give feedback (via the xen-devel/xense-devel mailing lists).
+
+Install:
+
+cd into xeno-unstable.bk
+(use --dry-run option if you want to test the patch only)
+patch -p1 -g0 < *tools.diff
+patch -p1 -g0 < *xen.diff
+
+(no rejects, probably some line offsets)
+
+make uninstall; make mrproper; make; ./install.sh should install the default
+sHype into Xen (rebuild your initrd images if necessary). Reboot.
+
+Debug output: there are two triggers for debug output:
+a) General sHype debug:
+ xeno-unstable.bk/xen/include/public/acm.h
+ undefine ACM_DEBUG to switch this debug off
+
+b) sHype enforcement hook trace: This prints a small trace for each enforcement
+hook that is executed. The trigger is in
+ xeno-unstable.bk/xen/include/acm/acm_hooks.h
+ undefine ACM_TRACE_MODE to switch this debug off
+
+1. The default NULL policy
+***************************
+When you apply the patches and startup xen, you should at first not notice any
+difference because the default policy is the "NULL" policy, which as the name
+implies does not enforce anything.
+
+To display the currently enforced policy, use the policy tool under xeno-
+unstable.bk/tools/policy: policy_tool getpolicy. You should see output like the
+one below.
+
+[root@laptop policy]#./policy_tool getpolicy
+
+Policy dump:
+============
+Magic = 1debc.
+PolVer = aaaa0000.
+Len = 14.
+Primary = NULL policy (c=0, off=14).
+Secondary = NULL policy (c=0, off=14).
+No primary policy (NULL).
+No secondary policy (NULL).
+
+Policy dump End.
+
+Since this is a dump of a binary policy, it's not pretty. The important parts
+are the "Primary" and "Secondary" policy fields set to "NULL policy". sHype
+currently allows to set two independent policies; thus the two SSID-REF parts
+shown in 'xm list'. Right here: primary policy only means this policy is
+checked first, the secondary policy is checked if the primary results in
+"permitted access". The result of the combined policy is "permitted" if both
+policies return permitted (NULL policy always returns permitted). The result is
+"denied" if at least one of the policies returns "denied". Look into xeno-
+unstable.bk/xen/include/acm/acm_hooks.h for the general hook structure
+integrating the policy decisions (if you like, you won't need it for the rest
+of the Readme file).
+
+2. Setting Chinese Wall and Simple Type Enforcement policies:
+*************************************************************
+
+We'll get fast to the point. However, in order to understand what we are doing,
+we must at least understand the purpose of the policies that we are going to
+enforce. The two policies presented here are just examples and the
+implementation encourages adding new policies easily.
+
+2.1. Chinese Wall policy: "decides whether a domain can be started based on
+this domain's ssidref and the ssidrefs of the currently running domains".
+Generally, the Chinese wall policy allows specifying certain types (or classes
+or categories, whatever the preferred word) that conflict; we usually assign a
+type to a workload and the set of types of those workloads running in a domain
+make up the type set for this domain. Each domain is assigned a set of types
+through its SSID-REF (we register Chinese Wall as primary policy, so the
+ssidref used for determining the Chinese Wall types is the one annotated with
+"p:" in xm list) since each SSID-REF points at a set of types. We'll see how
+SSIDREFs are represented in Xen later when we will look at the policy. (A good
+read for Chinese Wall is: Brewer/Nash The Chinese Wall Security Policy 1989.)
+
+So let's assume the Chinese Wall policy we are running distinguishes 10 types:
+t0 ... t9. Let us assume further that each SSID-REF points to a set that
+includes exactly one type (attached to domains that run workloads of a single
+type). SSID-REF 0 points to {t0}, ssidref 1 points to {t1} ... 9 points to
+{t9}. [This is actually the example policy we are going to push into xen later]
+
+Now the Chinese Wall policy allows you to define "Conflict type sets" and it
+guarantees that of any conflict set at most one type is "running" at any time.
+As an example, we have defined 2 conflict set: {t2, t3} and {t0, t5, t6}.
+Specifying these conflict sets, sHype ensures that at most one type of each set
+is running (either t2 or t3 but not both; either t0 or t5 or t6 but not
+multiple of them).
+
+The effect is that administrators can define which workload types cannot run
+simultaneously on a single Xen system. This is useful to limit the covert
+timing channels between such payloads or to ensure that payloads don't
+interfere with each other through existing resource dependencies.
+
+2.2. Simple Type Enforcement (ste) policy: "decides whether two domains can
+share data, e.g., setup event channels or grant tables to each other, based on
+the two domains' ssidref. This, as the name says, is a simple policy. Think of
+each type as of a single color. Each domain has one or more colors, i.e., the
+domains ssid for the ste policy points to a set that has set one or multiple
+types. Let us assume in our example policy we differentiate 5 colors (types)
+and define 5 different ssids referenced by ssidref=0..4. Each ssid shall have
+exactly one type set, i.e., describes a uni-color. Only ssid(0) has all types
+set, i.e., has all defined colors.
+
+Sharing is enforced by the ste policy by requiring that two domains that want
+to establish an event channel or grant pages to each other must have a common
+color. Currently all domains communicate through DOM0 by default; i.e., Domain0
+will necessarily have all colors to be able to create domains (thus, we will
+assign ssidref(0) to Domain0 in our example below.
+
+More complex mandatory access control policies governing sharing will follow;
+such policies are more sophisticated than the "color" scheme above by allowing
+more flexible (and complex :_) access control decisions than "share a color" or
+"don't share a color" and will be able to express finer-grained policies.
+
+
+2.3 Binary Policy:
+In the future, we will have a policy tool that takes as input a more humane
+policy description, using types such as development, home-banking, donated-
+Grid, CorpA-Payload ... and translates the respective policy into what we see
+today as the binary policy using 1s and 0s and sets of them. For now, we must
+live with the binary policy when working with sHype.
+
+
+2.4 Exemplary use of a real sHype policy on Xen. To activate a real policy,
+edit the file (yes, this will soon be a compile option):
+ xeno-unstable.bk/xen/include/public/acm.h
+ Change: #define ACM_USE_SECURITY_POLICY ACM_NULL_POLICY
+ To : #define ACM_USE_SECURITY_POLICY ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY
+ cd xeno-unstable.bk
+ make mrproper
+ make uninstall (manually remove /etc/xen.old if necessary)
+ make
+ ./install.sh (recreate your kernel initrd's if necessary)
+ Reboot into new xen.gz
+
+After booting, check out 'xm dmesg'; should show somewhere in the middle:
+
+(XEN) acm_init: Enforcing Primary CHINESE WALL policy, Secondary SIMPLE TYPE
+ENFORCEMENT policy.
+
+Even though you can activate those policies in any combination and also
+independently, the policy tool currently only supports setting the policy for
+the above combination.
+
+Now look at the minimal startup policy with:
+ xeno-unstable.bk/tools/policytool getpolicy
+
+You should see something like:
+
+[root@laptop policy]# ./policy_tool getpolicy
+
+Policy dump:
+============
+Magic = 1debc.
+PolVer = aaaa0000.
+Len = 36.
+Primary = CHINESE WALL policy (c=1, off=14).
+Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=2c).
+
+
+Chinese Wall policy:
+====================
+Max Types = 1.
+Max Ssidrefs = 1.
+Max ConfSets = 1.
+Ssidrefs Off = 10.
+Conflicts Off = 12.
+Runing T. Off = 14.
+C. Agg. Off = 16.
+
+SSID To CHWALL-Type matrix:
+
+ ssidref 0: 00
+
+Confict Sets:
+
+ c-set 0: 00
+
+Running
+Types: 00
+
+Conflict
+Aggregate Set: 00
+
+
+Simple Type Enforcement policy:
+===============================
+Max Types = 1.
+Max Ssidrefs = 1.
+Ssidrefs Off = 8.
+
+SSID To STE-Type matrix:
+
+ ssidref 0: 01
+
+
+Policy dump End.
+
+This is a minimal policy (of little use), except it will disable starting any
+domain that does not have ssidref set to 0x0. The Chinese Wall policy has
+nothing to enforce and the ste policy only knows one type, which is set for the
+only defined ssidref.
+
+The item that defines the ssidref in a domain configuration is:
+
+ssidref = 0x12345678
+
+Where ssidref is interpreted as a 32bit number, where the lower 16bits become
+the ssidref for the primary policy and the higher 16bits become the ssidref for
+the secondary policy. sHype currently supports two policies but this is an
+implementation decision and can be extended if necessary.
+
+This reference defines the security information of a domain. The meaning of the
+SSID-REF depends on the policy, so we explain it when we explain the real
+policies.
+
+
+Setting a new Security Policy:
+******************************
+The policy tool with all its current limitations has one usable example policy
+compiled-in. Please try at this time to use the setpolicy command:
+ xeno-unstable.bk/tools/policy/policy_tool setpolicy
+
+You should see a dump of the policy you are setting. It should say at the very
+end:
+
+Policy successfully set.
+
+Now try to dump the currently enforced policy, which is the policy we have just
+set and the dynamic security state information of this policy
+(<<< ... some additional explanations)
+
+[root@laptop policy]# ./policy_tool getpolicy
+
+Policy dump:
+============
+Magic = 1debc.
+PolVer = aaaa0000.
+Len = 112.
+Primary = CHINESE WALL policy (c=1, off=14).
+Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=d8).
+
+
+Chinese Wall policy:
+====================
+Max Types = a.
+Max Ssidrefs = 5.
+Max ConfSets = 2.
+Ssidrefs Off = 10.
+Conflicts Off = 74.
+Runing T. Off = 9c.
+C. Agg. Off = b0.
+
+SSID To CHWALL-Type matrix:
+
+ ssidref 0: 01 00 00 00 00 00 00 00 00 00 <<< type0 is set for ssidref0
+ ssidref 1: 00 01 00 00 00 00 00 00 00 00
+ ssidref 2: 00 00 01 00 00 00 00 00 00 00
+ ssidref 3: 00 00 00 01 00 00 00 00 00 00
+ ssidref 4: 00 00 00 00 01 00 00 00 00 00 <<< type4 is set for ssidref4
+ <<< types 5-9 are unused
+Confict Sets:
+
+ c-set 0: 00 00 01 01 00 00 00 00 00 00 <<< type2 and type3 never run together
+ c-set 1: 01 00 00 00 00 01 01 00 00 00 <<< only one of types 0, 5 or 6
+ <<< can run simultaneously
+Running
+Types: 01 00 00 00 00 00 00 00 00 00 <<< ref-count for types of running domains
+
+Conflict
+Aggregate Set: 00 00 00 00 00 01 01 00 00 00 <<< aggregated set of types that
+ <<< cannot run because they
+ <<< are in conflict set 1 and
+ <<< (domain 0 is running w t0)
+
+
+Simple Type Enforcement policy:
+===============================
+Max Types = 5.
+Max Ssidrefs = 5.
+Ssidrefs Off = 8.
+
+SSID To STE-Type matrix:
+
+ ssidref 0: 01 01 01 01 01 <<< ssidref0 points to a set that
+ <<< has all types set (colors)
+ ssidref 1: 00 01 00 00 00 <<< ssidref1 has color1 set
+ ssidref 2: 00 00 01 00 00 <<< ...
+ ssidref 3: 00 00 00 01 00
+ ssidref 4: 00 00 00 00 01
+
+
+Policy dump End.
+
+
+This is a small example policy with which we will demonstrate the enforcement.
+
+Starting Domains with policy enforcement
+========================================
+Now let us play with this policy.
+
+Define 3 or 4 domain configurations. I use the following config using a ramdisk
+only and about 8MBytes of memory for each DomU (test purposes):
+
+#-------configuration xmsec1-------------------------
+kernel = "/boot/vmlinuz-2.6.11-xenU"
+ramdisk="/boot/U1_ramdisk.img"
+#security reference identifier
+ssidref= 0x00010001
+memory = 10
+name = "xmsec1"
+cpu = -1 # leave to Xen to pick
+# Number of network interfaces. Default is 1.
+nics=1
+dhcp="dhcp"
+#-----------------------------------------------------
+
+xmsec2 and xmsec3 look the same except for the name and the ssidref line. Use
+your domain config file and add "ssidref = 0x00010001" to the first (xmsec1),
+"ssidref= 0x00020002" to the second (call it xmsec2), and "ssidref=0x00030003"
+to the third (we will call this one xmsec3).
+
+First start xmsec1: xm create -c xmsec1 (succeeds)
+
+Then
+[root@laptop policy]# xm list
+Name Id Mem(MB) CPU State Time(s) Console
+Domain-0 0 620 0 r---- 42.3 s:00/p:00
+xmnosec 1 9 0 -b--- 0.3 9601 s:00/p:05
+xmsec1 2 9 0 -b--- 0.2 9602 s:01/p:01
+
+Shows a new domain xmsec1 running with primary (here: chinese wall) ssidref 1
+and secondary (here: simple type enforcement) ssidref 1. The ssidrefs are
+independent and can differ for a domain.
+
+[root@laptop policy]# ./policy_tool getpolicy
+
+Policy dump:
+============
+Magic = 1debc.
+PolVer = aaaa0000.
+Len = 112.
+Primary = CHINESE WALL policy (c=1, off=14).
+Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=d8).
+
+
+Chinese Wall policy:
+====================
+Max Types = a.
+Max Ssidrefs = 5.
+Max ConfSets = 2.
+Ssidrefs Off = 10.
+Conflicts Off = 74.
+Runing T. Off = 9c.
+C. Agg. Off = b0.
+
+SSID To CHWALL-Type matrix:
+
+ ssidref 0: 01 00 00 00 00 00 00 00 00 00
+ ssidref 1: 00 01 00 00 00 00 00 00 00 00
+ ssidref 2: 00 00 01 00 00 00 00 00 00 00
+ ssidref 3: 00 00 00 01 00 00 00 00 00 00
+ ssidref 4: 00 00 00 00 01 00 00 00 00 00
+
+Confict Sets:
+
+ c-set 0: 00 00 01 01 00 00 00 00 00 00
+ c-set 1: 01 00 00 00 00 01 01 00 00 00 <<< t1 is not part of any c-set
+
+Running
+Types: 01 01 00 00 00 00 00 00 00 00 <<< xmsec1 has ssidref 1->type1
+ ^^ <<< ref-count at position 1 incr
+Conflict
+Aggregate Set: 00 00 00 00 00 01 01 00 00 00 <<< domain 1 was allowed to
+ <<< start since type 1 was not
+ <<< in conflict with running
+ <<< types
+
+Simple Type Enforcement policy:
+===============================
+Max Types = 5.
+Max Ssidrefs = 5.
+Ssidrefs Off = 8.
+
+SSID To STE-Type matrix:
+
+ ssidref 0: 01 01 01 01 01 <<< the ste policy does not maintain; we
+ ssidref 1: 00 01 00 00 00 <-- <<< see that domain xmsec1 has ste
+ ssidref 2: 00 00 01 00 00 <<< ssidref1->type1 and has this type in
+ ssidref 3: 00 00 00 01 00 <<< common with dom0
+ ssidref 4: 00 00 00 00 01
+
+
+Policy dump End.
+
+Look at sHype output in xen dmesg:
+
+[root@laptop xen]# xm dmesg
+.
+.
+[somewhere near the very end]
+(XEN) chwall_init_domain_ssid: determined chwall_ssidref to 1.
+(XEN) ste_init_domain_ssid.
+(XEN) ste_init_domain_ssid: determined ste_ssidref to 1.
+(XEN) acm_init_domain_ssid: Instantiated individual ssid for domain 0x01.
+(XEN) chwall_post_domain_create.
+(XEN) ste_pre_eventchannel_interdomain.
+(XEN) ste_pre_eventchannel_interdomain: (evtchn 0 --> 1) common type #01.
+(XEN) shype_authorize_domops.
+(XEN) ste_pre_eventchannel_interdomain.
+(XEN) ste_pre_eventchannel_interdomain: (evtchn 0 --> 1) common type #01.
+(XEN) ste_pre_eventchannel_interdomain.
+(XEN) ste_pre_eventchannel_interdomain: (evtchn 0 --> 1) common type #01.
+
+
+You can see that the chinese wall policy does not complain and that the ste
+policy makes three access control decisions for three event-channels setup
+between domain 0 and the new domain 1. Each time, the two domains share the
+type1 and setting up the eventchannel is permitted.
+
+
+Starting up a second domain xmsec2:
+
+[root@laptop xen]# xm create -c xmsec2
+Using config file "xmsec2".
+Started domain xmsec2, console on port 9602
+************ REMOTE CONSOLE: CTRL-] TO QUIT ********
+Linux version 2.6.11-xenU (root@laptop.home.org) (gcc version 3.4.2 20041017
+(Red Hat 3.4.2-6.fc3)) #1 Wed Mar 30 13:14:31 EST 2005
+.
+.
+.
+[root@laptop policy]# xm list
+Name Id Mem(MB) CPU State Time(s) Console
+Domain-0 0 620 0 r---- 71.7 s:00/p:00
+xmsec1 1 9 0 -b--- 0.3 9601 s:01/p:01
+xmsec2 2 7 0 -b--- 0.3 9602 s:02/p:02 << our domain runs both policies with ssidref 2
+
+
+[root@laptop policy]# ./policy_tool getpolicy
+
+Policy dump:
+============
+Magic = 1debc.
+PolVer = aaaa0000.
+Len = 112.
+Primary = CHINESE WALL policy (c=1, off=14).
+Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=d8).
+
+
+Chinese Wall policy:
+====================
+Max Types = a.
+Max Ssidrefs = 5.
+Max ConfSets = 2.
+Ssidrefs Off = 10.
+Conflicts Off = 74.
+Runing T. Off = 9c.
+C. Agg. Off = b0.
+
+SSID To CHWALL-Type matrix:
+
+ ssidref 0: 01 00 00 00 00 00 00 00 00 00
+ ssidref 1: 00 01 00 00 00 00 00 00 00 00
+ ssidref 2: 00 00 01 00 00 00 00 00 00 00 <<< our domain has type 2 set
+ ssidref 3: 00 00 00 01 00 00 00 00 00 00
+ ssidref 4: 00 00 00 00 01 00 00 00 00 00
+
+Confict Sets:
+
+ c-set 0: 00 00 01 01 00 00 00 00 00 00 <<< t2 is in c-set0 with type 3
+ c-set 1: 01 00 00 00 00 01 01 00 00 00
+
+Running
+Types: 01 01 01 00 00 00 00 00 00 00 <<< t2 is running since the
+ ^^ <<< current aggregate conflict
+ <<< set (see above) does not
+ <<< include type 2
+Conflict
+Aggregate Set: 00 00 00 01 00 01 01 00 00 00 <<< type 3 is added to the
+ <<< conflict aggregate
+
+
+Simple Type Enforcement policy:
+===============================
+Max Types = 5.
+Max Ssidrefs = 5.
+Ssidrefs Off = 8.
+
+SSID To STE-Type matrix:
+
+ ssidref 0: 01 01 01 01 01
+ ssidref 1: 00 01 00 00 00
+ ssidref 2: 00 00 01 00 00
+ ssidref 3: 00 00 00 01 00
+ ssidref 4: 00 00 00 00 01
+
+
+Policy dump End.
+
+
+The sHype xen dmesg output looks similar to the one above when starting the
+first domain.
+
+Now we start xmsec3 and it has ssidref3. Thus, it tries to run as type3 which
+conflicts with running type2 (from xmsec2). As expected, creating this domain
+fails for security policy enforcement reasons.
+
+[root@laptop xen]# xm create -c xmsec3
+Using config file "xmsec3".
+Error: Error creating domain: (22, 'Invalid argument')
+[root@laptop xen]#
+
+[root@laptop xen]# xm dmesg
+.
+.
+[somewhere near the very end]
+(XEN) chwall_pre_domain_create.
+(XEN) chwall_pre_domain_create: CHINESE WALL CONFLICT in type 03.
+
+xmsec3 ssidref3 points to type3, which is in the current conflict aggregate
+set. This domain cannot start until domain xmsec2 is destroyed, at which time
+the aggregate conflict set is reduced and type3 is excluded from it. Then,
+xmsec3 can start. Of course, afterwards, xmsec2 cannot be restarted. Try it.
+
+3. Policy tool
+**************
+toos/policy/policy_tool.c
+
+a) ./policy_tool getpolicy
+ prints the currently enforced policy
+ (see for example section 1.)
+
+b) ./policy_tool setpolicy
+ sets a predefined and hardcoded security
+ policy (the one described in section 2.)
+
+c) ./policy_tool dumpstats
+ prints some status information about the caching
+ of access control decisions (number of cache hits
+ and number of policy evaluations for grant_table
+ and event channels).
+
+d) ./policy_tool loadpolicy <binary_policy_file>
+ sets the policy defined in the <binary_policy_file>
+ please use the policy_processor that is posted to this
+ mailing list to create such a binary policy from an XML
+ policy description
+
+4. Policy interface:
+********************
+The Policy interface is working in "network-byte-order" (big endian). The reason for this
+is that policy files/management should be portable and independent of the platforms.
+
+Our policy interface enables managers to create a single binary policy file in a trusted
+environment and distributed it to multiple systems for enforcement.
+
+====================end-of file=======================================
diff --git a/linux-2.6.11-xen-sparse/arch/xen/Makefile b/linux-2.6.11-xen-sparse/arch/xen/Makefile
index 378dba9615..159006083d 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/Makefile
+++ b/linux-2.6.11-xen-sparse/arch/xen/Makefile
@@ -27,15 +27,17 @@ include/.asm-ignore: include/asm
@mv include/asm include/.asm-ignore
@echo ' SYMLINK include/asm -> include/asm-$(XENARCH)'
$(Q)if [ ! -d include ]; then mkdir -p include; fi;
- @ln -fsn asm-$(XENARCH) include/asm
+ @ln -fsn $(srctree)/include/asm-$(XENARCH) include/asm
include/asm-xen/asm:
@echo ' SYMLINK $@ -> include/asm-xen/asm-$(XENARCH)'
- @ln -fsn asm-$(XENARCH) $@
+ @mkdir -p include/asm-xen
+ @ln -fsn $(srctree)/include/asm-xen/asm-$(XENARCH) $@
arch/xen/arch:
@rm -f $@
- @ln -fsn $(XENARCH) $@
+ @mkdir -p arch/xen
+ @ln -fsn $(srctree)/arch/xen/$(XENARCH) $@
arch/$(XENARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
include/config/MARKER
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig
index d1ffcb05d1..dec06cdfd1 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig
@@ -372,6 +372,19 @@ config SMP
If you don't know what to do here, say N.
+config SMP_ALTERNATIVES
+ bool "SMP alternatives support (EXPERIMENTAL)"
+ depends on SMP && EXPERIMENTAL
+ help
+ Try to reduce the overhead of running an SMP kernel on a uniprocessor
+ host slightly by replacing certain key instruction sequences
+ according to whether we currently have more than one CPU available.
+ This should provide a noticeable boost to performance when
+ running SMP kernels on UP machines, and have negligible impact
+ when running on an true SMP host.
+
+ If unsure, say N.
+
config NR_CPUS
int "Maximum number of CPUs (2-255)"
range 2 255
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile
index 3f2fef4a94..6973df049f 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile
@@ -42,6 +42,7 @@ c-obj-$(CONFIG_ACPI_SRAT) += srat.o
c-obj-$(CONFIG_HPET_TIMER) += time_hpet.o
c-obj-$(CONFIG_EFI) += efi.o efi_stub.o
c-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+c-obj-$(CONFIG_SMP_ALTERNATIVES)+= smpalts.o
EXTRA_AFLAGS := -traditional
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c
index d428b2305f..eba38c6579 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c
@@ -154,8 +154,13 @@ void cpu_idle (void)
cpu_clear(cpu, cpu_idle_map);
rmb();
- if (cpu_is_offline(cpu))
+ if (cpu_is_offline(cpu)) {
+#if defined(CONFIG_XEN) && defined(CONFIG_HOTPLUG_CPU)
+ /* Tell hypervisor to take vcpu down. */
+ HYPERVISOR_vcpu_down(cpu);
+#endif
play_dead();
+ }
irq_stat[cpu].idle_timestamp = jiffies;
xen_idle();
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
index a716095376..14342b66de 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
@@ -54,6 +54,8 @@
#include <asm/desc.h>
#include <asm/arch_hooks.h>
+#include <asm/smp_alt.h>
+
#ifndef CONFIG_X86_IO_APIC
#define Dprintk(args...)
#endif
@@ -1186,6 +1188,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
if (max_cpus <= cpucount+1)
continue;
+#ifdef CONFIG_SMP_ALTERNATIVES
+ if (kicked == 1)
+ prepare_for_smp();
+#endif
if (do_boot_cpu(cpu))
printk("CPU #%d not responding - cannot use it.\n",
cpu);
@@ -1297,10 +1303,23 @@ void __devinit smp_prepare_boot_cpu(void)
}
#ifdef CONFIG_HOTPLUG_CPU
+#include <asm-xen/ctrl_if.h>
+
+/* hotplug down/up funtion pointer and target vcpu */
+struct vcpu_hotplug_handler_t {
+ void (*fn)();
+ u32 vcpu;
+};
+static struct vcpu_hotplug_handler_t vcpu_hotplug_handler;
/* must be called with the cpucontrol mutex held */
static int __devinit cpu_enable(unsigned int cpu)
{
+#ifdef CONFIG_SMP_ALTERNATIVES
+ if (num_online_cpus() == 1)
+ prepare_for_smp();
+#endif
+
/* get the target out of its holding state */
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
wmb();
@@ -1340,6 +1359,12 @@ int __cpu_disable(void)
fixup_irqs(map);
/* It's now safe to remove this processor from the online map */
cpu_clear(cpu, cpu_online_map);
+
+#ifdef CONFIG_SMP_ALTERNATIVES
+ if (num_online_cpus() == 1)
+ unprepare_for_smp();
+#endif
+
return 0;
}
@@ -1357,6 +1382,78 @@ void __cpu_die(unsigned int cpu)
}
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
}
+
+static int vcpu_hotplug_cpu_process(void *unused)
+{
+ struct vcpu_hotplug_handler_t *handler = &vcpu_hotplug_handler;
+
+ if (handler->fn) {
+ (*(handler->fn))(handler->vcpu);
+ handler->fn = NULL;
+ }
+ return 0;
+}
+
+static void __vcpu_hotplug_handler(void *unused)
+{
+ int err;
+
+ err = kernel_thread(vcpu_hotplug_cpu_process,
+ NULL, CLONE_FS | CLONE_FILES);
+ if (err < 0)
+ printk(KERN_ALERT "Error creating hotplug_cpu process!\n");
+
+}
+
+static void vcpu_hotplug_event_handler(ctrl_msg_t *msg, unsigned long id)
+{
+ static DECLARE_WORK(vcpu_hotplug_work, __vcpu_hotplug_handler, NULL);
+ vcpu_hotplug_t *req = (vcpu_hotplug_t *)&msg->msg[0];
+ struct vcpu_hotplug_handler_t *handler = &vcpu_hotplug_handler;
+ ssize_t ret;
+
+ if (msg->length != sizeof(vcpu_hotplug_t))
+ goto parse_error;
+
+ /* grab target vcpu from msg */
+ handler->vcpu = req->vcpu;
+
+ /* determine which function to call based on msg subtype */
+ switch (msg->subtype) {
+ case CMSG_VCPU_HOTPLUG_OFF:
+ handler->fn = (void *)&cpu_down;
+ ret = schedule_work(&vcpu_hotplug_work);
+ req->status = (u32) ret;
+ break;
+ case CMSG_VCPU_HOTPLUG_ON:
+ handler->fn = (void *)&cpu_up;
+ ret = schedule_work(&vcpu_hotplug_work);
+ req->status = (u32) ret;
+ break;
+ default:
+ goto parse_error;
+ }
+
+ ctrl_if_send_response(msg);
+ return;
+ parse_error:
+ msg->length = 0;
+ ctrl_if_send_response(msg);
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+ struct vcpu_hotplug_handler_t *handler = &vcpu_hotplug_handler;
+
+ handler->fn = NULL;
+ ctrl_if_register_receiver(CMSG_VCPU_HOTPLUG,
+ vcpu_hotplug_event_handler, 0);
+
+ return 0;
+}
+
+__initcall(setup_vcpu_hotplug_event);
+
#else /* ... !CONFIG_HOTPLUG_CPU */
int __cpu_disable(void)
{
@@ -1380,6 +1477,10 @@ int __devinit __cpu_up(unsigned int cpu)
}
#ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_XEN
+ /* Tell hypervisor to bring vcpu up. */
+ HYPERVISOR_vcpu_up(cpu);
+#endif
/* Already up, and in cpu_quiescent now? */
if (cpu_isset(cpu, smp_commenced_mask)) {
cpu_enable(cpu);
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6.11-xen-sparse/drivers/xen/netfront/netfront.c
index c1cf253510..208b00353f 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/netfront/netfront.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/netfront/netfront.c
@@ -623,7 +623,7 @@ static int netif_poll(struct net_device *dev, int *pbudget)
/* Only copy the packet if it fits in the current MTU. */
if (skb->len <= (dev->mtu + ETH_HLEN)) {
if ((skb->tail > skb->end) && net_ratelimit())
- printk(KERN_INFO "Received packet needs %d bytes more "
+ printk(KERN_INFO "Received packet needs %zd bytes more "
"headroom.\n", skb->tail - skb->end);
if ((nskb = alloc_xen_skb(skb->len + 2)) != NULL) {
@@ -967,9 +967,9 @@ static int create_netdev(int handle, struct net_device **val)
/* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
for (i = 0; i <= NETIF_TX_RING_SIZE; i++)
- np->tx_skbs[i] = (void *)(i+1);
+ np->tx_skbs[i] = (void *)((unsigned long) i+1);
for (i = 0; i <= NETIF_RX_RING_SIZE; i++)
- np->rx_skbs[i] = (void *)(i+1);
+ np->rx_skbs[i] = (void *)((unsigned long) i+1);
dev->open = network_open;
dev->hard_start_xmit = network_start_xmit;
@@ -1343,7 +1343,7 @@ static int xennet_proc_read(
{
struct net_device *dev = (struct net_device *)((unsigned long)data & ~3UL);
struct net_private *np = netdev_priv(dev);
- int len = 0, which_target = (int)data & 3;
+ int len = 0, which_target = (unsigned long) data & 3;
switch (which_target)
{
@@ -1368,7 +1368,7 @@ static int xennet_proc_write(
{
struct net_device *dev = (struct net_device *)((unsigned long)data & ~3UL);
struct net_private *np = netdev_priv(dev);
- int which_target = (int)data & 3;
+ int which_target = (unsigned long) data & 3;
char string[64];
long target;
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c
index 2f9d5fde38..9eea1835b5 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c
@@ -196,6 +196,36 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
}
break;
+ case IOCTL_PRIVCMD_INITDOMAIN_STORE:
+ {
+ extern int do_xenbus_probe(void*);
+
+ if (xen_start_info.store_evtchn != 0) {
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Allocate page. */
+ xen_start_info.store_page = get_zeroed_page(GFP_KERNEL);
+ if (!xen_start_info.store_page) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ /* We don't refcnt properly, so set reserved on page.
+ * (this allocation is permanent) */
+ SetPageReserved(virt_to_page(xen_start_info.store_page));
+
+ /* Initial connect. Setup channel and page. */
+ xen_start_info.store_evtchn = data;
+ ret = pfn_to_mfn(virt_to_phys((void *)xen_start_info.store_page) >>
+ PAGE_SHIFT);
+
+ /* We'll return then this will wait for daemon to answer */
+ // kthread_run(do_xenbus_probe, NULL, "xenbus_probe");
+ }
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/hypercall.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/hypercall.h
index 13ab9c3fde..98b2b999fd 100644
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/hypercall.h
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/hypercall.h
@@ -517,4 +517,35 @@ HYPERVISOR_boot_vcpu(
return ret;
}
+static inline int
+HYPERVISOR_vcpu_down(
+ int vcpu)
+{
+ int ret;
+ unsigned long ign1;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret), "=b" (ign1)
+ : "0" (__HYPERVISOR_sched_op),
+ "1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift))
+ : "memory" );
+
+ return ret;
+}
+
+static inline int
+HYPERVISOR_vcpu_up(
+ int vcpu)
+{
+ int ret;
+ unsigned long ign1;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret), "=b" (ign1)
+ : "0" (__HYPERVISOR_sched_op),
+ "1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift))
+ : "memory" );
+
+ return ret;
+}
#endif /* __HYPERCALL_H__ */
diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
index 021acbd159..fcf9959526 100644
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
@@ -8,6 +8,7 @@
#include <asm/segment.h>
#include <asm/cpufeature.h>
#include <asm-xen/hypervisor.h>
+#include <asm/smp_alt.h>
#ifdef __KERNEL__
@@ -251,19 +252,19 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long prev;
switch (size) {
case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+ __asm__ __volatile__(LOCK "cmpxchgb %b1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+ __asm__ __volatile__(LOCK "cmpxchgw %w1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+ __asm__ __volatile__(LOCK "cmpxchgl %1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
@@ -427,11 +428,55 @@ struct alt_instr {
#endif
#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
#define smp_wmb() wmb()
-#define smp_read_barrier_depends() read_barrier_depends()
+#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE)
+#define smp_alt_mb(instr) \
+__asm__ __volatile__("6667:\nnop\nnop\nnop\nnop\nnop\nnop\n6668:\n" \
+ ".section __smp_alternatives,\"a\"\n" \
+ ".long 6667b\n" \
+ ".long 6673f\n" \
+ ".previous\n" \
+ ".section __smp_replacements,\"a\"\n" \
+ "6673:.byte 6668b-6667b\n" \
+ ".byte 6670f-6669f\n" \
+ ".byte 6671f-6670f\n" \
+ ".byte 0\n" \
+ ".byte %c0\n" \
+ "6669:lock;addl $0,0(%%esp)\n" \
+ "6670:" instr "\n" \
+ "6671:\n" \
+ ".previous\n" \
+ : \
+ : "i" (X86_FEATURE_XMM2) \
+ : "memory")
+#define smp_rmb() smp_alt_mb("lfence")
+#define smp_mb() smp_alt_mb("mfence")
+#define set_mb(var, value) do { \
+unsigned long __set_mb_temp; \
+__asm__ __volatile__("6667:movl %1, %0\n6668:\n" \
+ ".section __smp_alternatives,\"a\"\n" \
+ ".long 6667b\n" \
+ ".long 6673f\n" \
+ ".previous\n" \
+ ".section __smp_replacements,\"a\"\n" \
+ "6673: .byte 6668b-6667b\n" \
+ ".byte 6670f-6669f\n" \
+ ".byte 0\n" \
+ ".byte 6671f-6670f\n" \
+ ".byte -1\n" \
+ "6669: xchg %1, %0\n" \
+ "6670:movl %1, %0\n" \
+ "6671:\n" \
+ ".previous\n" \
+ : "=m" (var), "=r" (__set_mb_temp) \
+ : "1" (value) \
+ : "memory"); } while (0)
+#else
+#define smp_rmb() rmb()
+#define smp_mb() mb()
#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#endif
+#define smp_read_barrier_depends() read_barrier_depends()
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h b/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h
index 9142c6b35d..51d1ce5acf 100644
--- a/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h
@@ -84,5 +84,7 @@ typedef struct privcmd_blkmsg
_IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t))
#define IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN \
_IOC(_IOC_READ, 'P', 4, sizeof(unsigned long))
+#define IOCTL_PRIVCMD_INITDOMAIN_STORE \
+ _IOC(_IOC_READ, 'P', 5, 0)
#endif /* __PRIVCMD_H__ */
diff --git a/patches/linux-2.6.11/smp-alts.patch b/patches/linux-2.6.11/smp-alts.patch
new file mode 100644
index 0000000000..db71ab1e56
--- /dev/null
+++ b/patches/linux-2.6.11/smp-alts.patch
@@ -0,0 +1,554 @@
+diff -Naur linux-2.6.11/arch/i386/Kconfig linux-2.6.11.post/arch/i386/Kconfig
+--- linux-2.6.11/arch/i386/Kconfig 2005-03-02 07:37:49.000000000 +0000
++++ linux-2.6.11.post/arch/i386/Kconfig 2005-06-10 13:42:35.000000000 +0100
+@@ -481,6 +481,19 @@
+
+ If you don't know what to do here, say N.
+
++config SMP_ALTERNATIVES
++ bool "SMP alternatives support (EXPERIMENTAL)"
++ depends on SMP && EXPERIMENTAL
++ help
++ Try to reduce the overhead of running an SMP kernel on a uniprocessor
++ host slightly by replacing certain key instruction sequences
++ according to whether we currently have more than one CPU available.
++ This should provide a noticeable boost to performance when
++ running SMP kernels on UP machines, and have negligible impact
++ when running on an true SMP host.
++
++ If unsure, say N.
++
+ config NR_CPUS
+ int "Maximum number of CPUs (2-255)"
+ range 2 255
+diff -Naur linux-2.6.11/arch/i386/kernel/Makefile linux-2.6.11.post/arch/i386/kernel/Makefile
+--- linux-2.6.11/arch/i386/kernel/Makefile 2005-03-02 07:37:49.000000000 +0000
++++ linux-2.6.11.post/arch/i386/kernel/Makefile 2005-06-16 11:16:18.555332435 +0100
+@@ -32,6 +32,7 @@
+ obj-$(CONFIG_HPET_TIMER) += time_hpet.o
+ obj-$(CONFIG_EFI) += efi.o efi_stub.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
++obj-$(CONFIG_SMP_ALTERNATIVES) += smpalts.o
+
+ EXTRA_AFLAGS := -traditional
+
+diff -Naur linux-2.6.11/arch/i386/kernel/smpalts.c linux-2.6.11.post/arch/i386/kernel/smpalts.c
+--- linux-2.6.11/arch/i386/kernel/smpalts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.11.post/arch/i386/kernel/smpalts.c 2005-06-16 11:23:39.300902424 +0100
+@@ -0,0 +1,76 @@
++#include <linux/kernel.h>
++#include <asm/system.h>
++#include <asm/smp_alt.h>
++#include <asm/processor.h>
++#include <asm/string.h>
++
++struct smp_replacement_record {
++ unsigned char targ_size;
++ unsigned char smp1_size;
++ unsigned char smp2_size;
++ unsigned char up_size;
++ unsigned char feature;
++ unsigned char data[0];
++};
++
++struct smp_alternative_record {
++ void *targ_start;
++ struct smp_replacement_record *repl;
++};
++
++extern struct smp_alternative_record __start_smp_alternatives_table,
++ __stop_smp_alternatives_table;
++
++void prepare_for_smp(void)
++{
++ struct smp_alternative_record *r;
++ printk(KERN_INFO "Enabling SMP...\n");
++ for (r = &__start_smp_alternatives_table;
++ r != &__stop_smp_alternatives_table;
++ r++) {
++ BUG_ON(r->repl->targ_size < r->repl->smp1_size);
++ BUG_ON(r->repl->targ_size < r->repl->smp2_size);
++ BUG_ON(r->repl->targ_size < r->repl->up_size);
++ if (r->repl->feature != (unsigned char)-1 &&
++ boot_cpu_has(r->repl->feature)) {
++ memcpy(r->targ_start,
++ r->repl->data + r->repl->smp1_size,
++ r->repl->smp2_size);
++ memset(r->targ_start + r->repl->smp2_size,
++ 0x90,
++ r->repl->targ_size - r->repl->smp2_size);
++ } else {
++ memcpy(r->targ_start,
++ r->repl->data,
++ r->repl->smp1_size);
++ memset(r->targ_start + r->repl->smp1_size,
++ 0x90,
++ r->repl->targ_size - r->repl->smp1_size);
++ }
++ }
++ /* Paranoia */
++ asm volatile ("jmp 1f\n1:");
++ mb();
++}
++
++void unprepare_for_smp(void)
++{
++ struct smp_alternative_record *r;
++ printk(KERN_INFO "Disabling SMP...\n");
++ for (r = &__start_smp_alternatives_table;
++ r != &__stop_smp_alternatives_table;
++ r++) {
++ BUG_ON(r->repl->targ_size < r->repl->smp1_size);
++ BUG_ON(r->repl->targ_size < r->repl->smp2_size);
++ BUG_ON(r->repl->targ_size < r->repl->up_size);
++ memcpy(r->targ_start,
++ r->repl->data + r->repl->smp1_size + r->repl->smp2_size,
++ r->repl->up_size);
++ memset(r->targ_start + r->repl->up_size,
++ 0x90,
++ r->repl->targ_size - r->repl->up_size);
++ }
++ /* Paranoia */
++ asm volatile ("jmp 1f\n1:");
++ mb();
++}
+diff -Naur linux-2.6.11/arch/i386/kernel/smpboot.c linux-2.6.11.post/arch/i386/kernel/smpboot.c
+--- linux-2.6.11/arch/i386/kernel/smpboot.c 2005-03-02 07:38:09.000000000 +0000
++++ linux-2.6.11.post/arch/i386/kernel/smpboot.c 2005-06-16 11:17:09.287064617 +0100
+@@ -1003,6 +1003,11 @@
+ if (max_cpus <= cpucount+1)
+ continue;
+
++#ifdef CONFIG_SMP_ALTERNATIVES
++ if (kicked == 1)
++ prepare_for_smp();
++#endif
++
+ if (do_boot_cpu(apicid))
+ printk("CPU #%d not responding - cannot use it.\n",
+ apicid);
+@@ -1118,6 +1123,11 @@
+ return -EIO;
+ }
+
++#ifdef CONFIG_SMP_ALTERNATIVES
++ if (num_online_cpus() == 1)
++ prepare_for_smp();
++#endif
++
+ local_irq_enable();
+ /* Unleash the CPU! */
+ cpu_set(cpu, smp_commenced_mask);
+diff -Naur linux-2.6.11/arch/i386/kernel/vmlinux.lds.S linux-2.6.11.post/arch/i386/kernel/vmlinux.lds.S
+--- linux-2.6.11/arch/i386/kernel/vmlinux.lds.S 2005-03-02 07:38:37.000000000 +0000
++++ linux-2.6.11.post/arch/i386/kernel/vmlinux.lds.S 2005-06-10 11:14:14.000000000 +0100
+@@ -30,6 +30,13 @@
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
++ . = ALIGN(16);
++ __start_smp_alternatives_table = .;
++ __smp_alternatives : { *(__smp_alternatives) }
++ __stop_smp_alternatives_table = .;
++
++ __smp_replacements : { *(__smp_replacements) }
++
+ RODATA
+
+ /* writeable */
+diff -Naur linux-2.6.11/include/asm-i386/atomic.h linux-2.6.11.post/include/asm-i386/atomic.h
+--- linux-2.6.11/include/asm-i386/atomic.h 2005-03-02 07:37:51.000000000 +0000
++++ linux-2.6.11.post/include/asm-i386/atomic.h 2005-06-13 10:10:39.000000000 +0100
+@@ -4,18 +4,13 @@
+ #include <linux/config.h>
+ #include <linux/compiler.h>
+ #include <asm/processor.h>
++#include <asm/smp_alt.h>
+
+ /*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+-#ifdef CONFIG_SMP
+-#define LOCK "lock ; "
+-#else
+-#define LOCK ""
+-#endif
+-
+ /*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+diff -Naur linux-2.6.11/include/asm-i386/bitops.h linux-2.6.11.post/include/asm-i386/bitops.h
+--- linux-2.6.11/include/asm-i386/bitops.h 2005-03-02 07:38:12.000000000 +0000
++++ linux-2.6.11.post/include/asm-i386/bitops.h 2005-06-13 10:11:54.000000000 +0100
+@@ -7,6 +7,7 @@
+
+ #include <linux/config.h>
+ #include <linux/compiler.h>
++#include <asm/smp_alt.h>
+
+ /*
+ * These have to be done with inline assembly: that way the bit-setting
+@@ -16,12 +17,6 @@
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+-#ifdef CONFIG_SMP
+-#define LOCK_PREFIX "lock ; "
+-#else
+-#define LOCK_PREFIX ""
+-#endif
+-
+ #define ADDR (*(volatile long *) addr)
+
+ /**
+@@ -41,7 +36,7 @@
+ */
+ static inline void set_bit(int nr, volatile unsigned long * addr)
+ {
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btsl %1,%0"
+ :"=m" (ADDR)
+ :"Ir" (nr));
+@@ -76,7 +71,7 @@
+ */
+ static inline void clear_bit(int nr, volatile unsigned long * addr)
+ {
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btrl %1,%0"
+ :"=m" (ADDR)
+ :"Ir" (nr));
+@@ -121,7 +116,7 @@
+ */
+ static inline void change_bit(int nr, volatile unsigned long * addr)
+ {
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btcl %1,%0"
+ :"=m" (ADDR)
+ :"Ir" (nr));
+@@ -140,7 +135,7 @@
+ {
+ int oldbit;
+
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btsl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"=m" (ADDR)
+ :"Ir" (nr) : "memory");
+@@ -180,7 +175,7 @@
+ {
+ int oldbit;
+
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btrl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"=m" (ADDR)
+ :"Ir" (nr) : "memory");
+@@ -231,7 +226,7 @@
+ {
+ int oldbit;
+
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btcl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"=m" (ADDR)
+ :"Ir" (nr) : "memory");
+diff -Naur linux-2.6.11/include/asm-i386/rwsem.h linux-2.6.11.post/include/asm-i386/rwsem.h
+--- linux-2.6.11/include/asm-i386/rwsem.h 2005-03-02 07:38:08.000000000 +0000
++++ linux-2.6.11.post/include/asm-i386/rwsem.h 2005-06-13 10:13:06.000000000 +0100
+@@ -40,6 +40,7 @@
+
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
++#include <asm/smp_alt.h>
+
+ struct rwsem_waiter;
+
+@@ -99,7 +100,7 @@
+ {
+ __asm__ __volatile__(
+ "# beginning down_read\n\t"
+-LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */
++LOCK " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */
+ " js 2f\n\t" /* jump if we weren't granted the lock */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -130,7 +131,7 @@
+ " movl %1,%2\n\t"
+ " addl %3,%2\n\t"
+ " jle 2f\n\t"
+-LOCK_PREFIX " cmpxchgl %2,%0\n\t"
++LOCK " cmpxchgl %2,%0\n\t"
+ " jnz 1b\n\t"
+ "2:\n\t"
+ "# ending __down_read_trylock\n\t"
+@@ -150,7 +151,7 @@
+ tmp = RWSEM_ACTIVE_WRITE_BIAS;
+ __asm__ __volatile__(
+ "# beginning down_write\n\t"
+-LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */
++LOCK " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */
+ " testl %%edx,%%edx\n\t" /* was the count 0 before? */
+ " jnz 2f\n\t" /* jump if we weren't granted the lock */
+ "1:\n\t"
+@@ -188,7 +189,7 @@
+ __s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
+ __asm__ __volatile__(
+ "# beginning __up_read\n\t"
+-LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old value */
++LOCK " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old value */
+ " js 2f\n\t" /* jump if the lock is being waited upon */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -214,7 +215,7 @@
+ __asm__ __volatile__(
+ "# beginning __up_write\n\t"
+ " movl %2,%%edx\n\t"
+-LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
++LOCK " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
+ " jnz 2f\n\t" /* jump if the lock is being waited upon */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -239,7 +240,7 @@
+ {
+ __asm__ __volatile__(
+ "# beginning __downgrade_write\n\t"
+-LOCK_PREFIX " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
++LOCK " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
+ " js 2f\n\t" /* jump if the lock is being waited upon */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -263,7 +264,7 @@
+ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+ {
+ __asm__ __volatile__(
+-LOCK_PREFIX "addl %1,%0"
++LOCK "addl %1,%0"
+ : "=m"(sem->count)
+ : "ir"(delta), "m"(sem->count));
+ }
+@@ -276,7 +277,7 @@
+ int tmp = delta;
+
+ __asm__ __volatile__(
+-LOCK_PREFIX "xadd %0,(%2)"
++LOCK "xadd %0,(%2)"
+ : "+r"(tmp), "=m"(sem->count)
+ : "r"(sem), "m"(sem->count)
+ : "memory");
+diff -Naur linux-2.6.11/include/asm-i386/smp_alt.h linux-2.6.11.post/include/asm-i386/smp_alt.h
+--- linux-2.6.11/include/asm-i386/smp_alt.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.11.post/include/asm-i386/smp_alt.h 2005-06-16 11:16:50.109433206 +0100
+@@ -0,0 +1,32 @@
++#ifndef __ASM_SMP_ALT_H__
++#define __ASM_SMP_ALT_H__
++
++#include <linux/config.h>
++
++#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE)
++#define LOCK \
++ "6677: nop\n" \
++ ".section __smp_alternatives,\"a\"\n" \
++ ".long 6677b\n" \
++ ".long 6678f\n" \
++ ".previous\n" \
++ ".section __smp_replacements,\"a\"\n" \
++ "6678: .byte 1\n" \
++ ".byte 1\n" \
++ ".byte 0\n" \
++ ".byte 1\n" \
++ ".byte -1\n" \
++ "lock\n" \
++ "nop\n" \
++ ".previous\n"
++void prepare_for_smp(void);
++void unprepare_for_smp(void);
++#else
++#define LOCK "lock ; "
++#endif
++#else
++#define LOCK ""
++#endif
++
++#endif /* __ASM_SMP_ALT_H__ */
+diff -Naur linux-2.6.11/include/asm-i386/spinlock.h linux-2.6.11.post/include/asm-i386/spinlock.h
+--- linux-2.6.11/include/asm-i386/spinlock.h 2005-03-02 07:37:50.000000000 +0000
++++ linux-2.6.11.post/include/asm-i386/spinlock.h 2005-06-13 14:13:52.000000000 +0100
+@@ -6,6 +6,7 @@
+ #include <asm/page.h>
+ #include <linux/config.h>
+ #include <linux/compiler.h>
++#include <asm/smp_alt.h>
+
+ asmlinkage int printk(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+@@ -47,8 +48,9 @@
+ #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+ #define spin_lock_string \
+- "\n1:\t" \
+- "lock ; decb %0\n\t" \
++ "1:\n" \
++ LOCK \
++ "decb %0\n\t" \
+ "jns 3f\n" \
+ "2:\t" \
+ "rep;nop\n\t" \
+@@ -58,8 +60,9 @@
+ "3:\n\t"
+
+ #define spin_lock_string_flags \
+- "\n1:\t" \
+- "lock ; decb %0\n\t" \
++ "1:\n" \
++ LOCK \
++ "decb %0\n\t" \
+ "jns 4f\n\t" \
+ "2:\t" \
+ "testl $0x200, %1\n\t" \
+@@ -121,10 +124,34 @@
+ static inline int _raw_spin_trylock(spinlock_t *lock)
+ {
+ char oldval;
++#ifdef CONFIG_SMP_ALTERNATIVES
+ __asm__ __volatile__(
+- "xchgb %b0,%1"
++ "1:movb %1,%b0\n"
++ "movb $0,%1\n"
++ "2:"
++ ".section __smp_alternatives,\"a\"\n"
++ ".long 1b\n"
++ ".long 3f\n"
++ ".previous\n"
++ ".section __smp_replacements,\"a\"\n"
++ "3: .byte 2b - 1b\n"
++ ".byte 5f-4f\n"
++ ".byte 0\n"
++ ".byte 6f-5f\n"
++ ".byte -1\n"
++ "4: xchgb %b0,%1\n"
++ "5: movb %1,%b0\n"
++ "movb $0,%1\n"
++ "6:\n"
++ ".previous\n"
+ :"=q" (oldval), "=m" (lock->slock)
+ :"0" (0) : "memory");
++#else
++ __asm__ __volatile__(
++ "xchgb %b0,%1\n"
++ :"=q" (oldval), "=m" (lock->slock)
++ :"0" (0) : "memory");
++#endif
+ return oldval > 0;
+ }
+
+@@ -225,8 +252,8 @@
+ __build_write_lock(rw, "__write_lock_failed");
+ }
+
+-#define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory")
+-#define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")
++#define _raw_read_unlock(rw) asm volatile(LOCK "incl %0" :"=m" ((rw)->lock) : : "memory")
++#define _raw_write_unlock(rw) asm volatile(LOCK "addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")
+
+ static inline int _raw_read_trylock(rwlock_t *lock)
+ {
+diff -Naur linux-2.6.11/include/asm-i386/system.h linux-2.6.11.post/include/asm-i386/system.h
+--- linux-2.6.11/include/asm-i386/system.h 2005-03-02 07:37:30.000000000 +0000
++++ linux-2.6.11.post/include/asm-i386/system.h 2005-06-15 13:21:40.000000000 +0100
+@@ -5,7 +5,7 @@
+ #include <linux/kernel.h>
+ #include <asm/segment.h>
+ #include <asm/cpufeature.h>
+-#include <linux/bitops.h> /* for LOCK_PREFIX */
++#include <asm/smp_alt.h>
+
+ #ifdef __KERNEL__
+
+@@ -249,19 +249,19 @@
+ unsigned long prev;
+ switch (size) {
+ case 1:
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
++ __asm__ __volatile__(LOCK "cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
++ __asm__ __volatile__(LOCK "cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
++ __asm__ __volatile__(LOCK "cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+@@ -425,11 +425,55 @@
+ #endif
+
+ #ifdef CONFIG_SMP
+-#define smp_mb() mb()
+-#define smp_rmb() rmb()
+ #define smp_wmb() wmb()
+-#define smp_read_barrier_depends() read_barrier_depends()
++#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE)
++#define smp_alt_mb(instr) \
++__asm__ __volatile__("6667:\nnop\nnop\nnop\nnop\nnop\nnop\n6668:\n" \
++ ".section __smp_alternatives,\"a\"\n" \
++ ".long 6667b\n" \
++ ".long 6673f\n" \
++ ".previous\n" \
++ ".section __smp_replacements,\"a\"\n" \
++ "6673:.byte 6668b-6667b\n" \
++ ".byte 6670f-6669f\n" \
++ ".byte 6671f-6670f\n" \
++ ".byte 0\n" \
++ ".byte %c0\n" \
++ "6669:lock;addl $0,0(%%esp)\n" \
++ "6670:" instr "\n" \
++ "6671:\n" \
++ ".previous\n" \
++ : \
++ : "i" (X86_FEATURE_XMM2) \
++ : "memory")
++#define smp_rmb() smp_alt_mb("lfence")
++#define smp_mb() smp_alt_mb("mfence")
++#define set_mb(var, value) do { \
++unsigned long __set_mb_temp; \
++__asm__ __volatile__("6667:movl %1, %0\n6668:\n" \
++ ".section __smp_alternatives,\"a\"\n" \
++ ".long 6667b\n" \
++ ".long 6673f\n" \
++ ".previous\n" \
++ ".section __smp_replacements,\"a\"\n" \
++ "6673: .byte 6668b-6667b\n" \
++ ".byte 6670f-6669f\n" \
++ ".byte 0\n" \
++ ".byte 6671f-6670f\n" \
++ ".byte -1\n" \
++ "6669: xchg %1, %0\n" \
++ "6670:movl %1, %0\n" \
++ "6671:\n" \
++ ".previous\n" \
++ : "=m" (var), "=r" (__set_mb_temp) \
++ : "1" (value) \
++ : "memory"); } while (0)
++#else
++#define smp_rmb() rmb()
++#define smp_mb() mb()
+ #define set_mb(var, value) do { xchg(&var, value); } while (0)
++#endif
++#define smp_read_barrier_depends() read_barrier_depends()
+ #else
+ #define smp_mb() barrier()
+ #define smp_rmb() barrier()
diff --git a/tools/Makefile b/tools/Makefile
index b122ba465a..00eb4991cc 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -10,9 +10,9 @@ SUBDIRS += xentrace
SUBDIRS += python
SUBDIRS += xcs
SUBDIRS += xcutils
-SUBDIRS += xenstore
SUBDIRS += pygrub
SUBDIRS += firmware
+SUBDIRS += policy
.PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
diff --git a/tools/firmware/vmxassist/Makefile b/tools/firmware/vmxassist/Makefile
index a9b142363c..97d6cc4c6e 100644
--- a/tools/firmware/vmxassist/Makefile
+++ b/tools/firmware/vmxassist/Makefile
@@ -23,9 +23,9 @@ include $(XEN_ROOT)/tools/Rules.mk
# The emulator code lives in ROM space
TEXTADDR=0x000D0000
+
DEFINES=-DDEBUG -DTEXTADDR=${TEXTADDR}
-XENINC=-I../../../xen/include
-#TEXTADDR=0x000E0000
+XENINC=-I$(XEN_ROOT)/xen/include
#DEFINES=-DDEBUG -DTEST -DTEXTADDR=${TEXTADDR}
#XENINC=-I/home/leendert/xen/xeno-unstable.bk/xen/include
diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c
index 64b9a6e06d..dceac64099 100644
--- a/tools/firmware/vmxassist/setup.c
+++ b/tools/firmware/vmxassist/setup.c
@@ -21,11 +21,9 @@
#include "util.h"
#include "machine.h"
-#ifndef TEST
#if (VMXASSIST_BASE != TEXTADDR)
#error VMXAssist base mismatch
#endif
-#endif
#define NR_PGD (PGSIZE / sizeof(unsigned))
@@ -118,8 +116,8 @@ setup_gdt(void)
"movl %%eax,%%fs;"
"movl %%eax,%%gs;"
"movl %%eax,%%ss" : : "a" (DATA_SELECTOR));
-/* XXX 0x10 == CODE_SELECTOR (figure out gnuas) */
- __asm__ __volatile__ ("ljmp $0x10,$1f; 1:");
+
+ __asm__ __volatile__ ("ljmp %0,$1f; 1:" : : "i" (CODE_SELECTOR));
__asm__ __volatile__ ("ltr %%ax" : : "a" (TSS_SELECTOR));
}
diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c
index d63843660e..d6ac150683 100644
--- a/tools/firmware/vmxassist/vm86.c
+++ b/tools/firmware/vmxassist/vm86.c
@@ -39,6 +39,13 @@ enum vm86_mode mode;
#ifdef DEBUG
int traceset = 0;
+
+char *states[] = {
+ "<VM86_REAL>",
+ "<VM86_REAL_TO_PROTECTED>",
+ "<VM86_PROTECTED_TO_REAL>",
+ "<VM86_PROTECTED>"
+};
#endif /* DEBUG */
@@ -596,7 +603,6 @@ set_mode(struct regs *regs, enum vm86_mode newmode)
{
switch (newmode) {
case VM86_REAL:
- TRACE((regs, 0, "<VM86_REAL>"));
if (mode == VM86_PROTECTED_TO_REAL) {
real_mode(regs);
break;
@@ -607,7 +613,6 @@ set_mode(struct regs *regs, enum vm86_mode newmode)
break;
case VM86_REAL_TO_PROTECTED:
- TRACE((regs, 0, "<VM86_REAL_TO_PROTECTED>"));
if (mode == VM86_REAL) {
regs->eflags |= EFLAGS_TF;
break;
@@ -624,7 +629,6 @@ set_mode(struct regs *regs, enum vm86_mode newmode)
panic("unexpected protected-to-real mode transition");
case VM86_PROTECTED:
- TRACE((regs, 0, "<VM86_PROTECTED>"));
if (mode == VM86_REAL_TO_PROTECTED) {
protected_mode(regs);
break;
@@ -634,6 +638,7 @@ set_mode(struct regs *regs, enum vm86_mode newmode)
}
mode = newmode;
+ TRACE((regs, 0, states[mode]));
}
void
diff --git a/tools/ioemu/hw/i8259.c b/tools/ioemu/hw/i8259.c
index 5bdc65d700..75f0391097 100644
--- a/tools/ioemu/hw/i8259.c
+++ b/tools/ioemu/hw/i8259.c
@@ -27,7 +27,7 @@
//#define DEBUG_PIC
//#define DEBUG_IRQ_LATENCY
-//#define DEBUG_IRQ_COUNT
+#define DEBUG_IRQ_COUNT
typedef struct PicState {
uint8_t last_irr; /* edge detection */
diff --git a/tools/ioemu/monitor.c b/tools/ioemu/monitor.c
index dec25febaa..2234d775ba 100644
--- a/tools/ioemu/monitor.c
+++ b/tools/ioemu/monitor.c
@@ -123,6 +123,108 @@ static int compare_cmd(const char *name, const char *list)
return 0;
}
+static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
+{
+ term_cmd_t *cmd;
+
+ for(cmd = cmds; cmd->name != NULL; cmd++) {
+ if (!name || !strcmp(name, cmd->name))
+ term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
+ }
+}
+
+static void help_cmd(const char *name)
+{
+ if (name && !strcmp(name, "info")) {
+ help_cmd1(info_cmds, "info ", NULL);
+ } else {
+ help_cmd1(term_cmds, "", name);
+ if (name && !strcmp(name, "log")) {
+ CPULogItem *item;
+ term_printf("Log items (comma separated):\n");
+ term_printf("%-10s %s\n", "none", "remove all logs");
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ term_printf("%-10s %s\n", item->name, item->help);
+ }
+ }
+ }
+}
+
+static void do_help(const char *name)
+{
+ help_cmd(name);
+}
+
+static void do_commit(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_DISKS; i++) {
+ if (bs_table[i]) {
+ bdrv_commit(bs_table[i]);
+ }
+ }
+}
+
+static void do_info(const char *item)
+{
+ term_cmd_t *cmd;
+
+ if (!item)
+ goto help;
+ for(cmd = info_cmds; cmd->name != NULL; cmd++) {
+ if (compare_cmd(item, cmd->name))
+ goto found;
+ }
+ help:
+ help_cmd("info");
+ return;
+ found:
+ cmd->handler();
+}
+
+static void do_info_version(void)
+{
+ term_printf("%s\n", QEMU_VERSION);
+}
+
+static void do_info_network(void)
+{
+ int i, j;
+ NetDriverState *nd;
+
+ for(i = 0; i < nb_nics; i++) {
+ nd = &nd_table[i];
+ term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
+ for(j = 0; j < 6; j++) {
+ if (j > 0)
+ term_printf(":");
+ term_printf("%02x", nd->macaddr[j]);
+ }
+ term_printf("\n");
+ }
+}
+
+static void do_info_block(void)
+{
+ bdrv_info();
+}
+
+static void do_info_history (void)
+{
+ int i;
+ const char *str;
+
+ i = 0;
+ for(;;) {
+ str = readline_get_history(i);
+ if (!str)
+ break;
+ term_printf("%d: '%s'\n", i, str);
+ i++;
+ }
+}
+
static void do_quit(void)
{
extern int domid;
@@ -134,12 +236,191 @@ static void do_quit(void)
exit(0);
}
+static int eject_device(BlockDriverState *bs, int force)
+{
+ if (bdrv_is_inserted(bs)) {
+ if (!force) {
+ if (!bdrv_is_removable(bs)) {
+ term_printf("device is not removable\n");
+ return -1;
+ }
+ if (bdrv_is_locked(bs)) {
+ term_printf("device is locked\n");
+ return -1;
+ }
+ }
+ bdrv_close(bs);
+ }
+ return 0;
+}
+
+static void do_eject(int force, const char *filename)
+{
+ BlockDriverState *bs;
+
+ bs = bdrv_find(filename);
+ if (!bs) {
+ term_printf("device not found\n");
+ return;
+ }
+ eject_device(bs, force);
+}
+
+static void do_change(const char *device, const char *filename)
+{
+ BlockDriverState *bs;
+#if 0
+ int i;
+ char password[256];
+#endif
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ term_printf("device not found\n");
+ return;
+ }
+ if (eject_device(bs, 0) < 0)
+ return;
+ bdrv_open(bs, filename, 0);
+#if 0
+ if (bdrv_is_encrypted(bs)) {
+ term_printf("%s is encrypted.\n", device);
+ for(i = 0; i < 3; i++) {
+ monitor_readline("Password: ", 1, password, sizeof(password));
+ if (bdrv_set_key(bs, password) == 0)
+ break;
+ term_printf("invalid password\n");
+ }
+ }
+#endif
+}
+
+static void do_screen_dump(const char *filename)
+{
+ vga_screen_dump(filename);
+}
+
+static void do_log(const char *items)
+{
+ int mask;
+
+ if (!strcmp(items, "none")) {
+ mask = 0;
+ } else {
+ mask = cpu_str_to_log_mask(items);
+ if (!mask) {
+ help_cmd("log");
+ return;
+ }
+ }
+ cpu_set_log(mask);
+}
+
static term_cmd_t term_cmds[] = {
+ { "help|?", "s?", do_help,
+ "[cmd]", "show the help" },
+ { "commit", "", do_commit,
+ "", "commit changes to the disk images (if -snapshot is used)" },
+ { "info", "s?", do_info,
+ "subcommand", "show various information about the system state" },
+ { "q|quit", "", do_quit,
+ "", "quit the emulator" },
+ { "eject", "-fB", do_eject,
+ "[-f] device", "eject a removable media (use -f to force it)" },
+ { "change", "BF", do_change,
+ "device filename", "change a removable media" },
+ { "screendump", "F", do_screen_dump,
+ "filename", "save screen into PPM image 'filename'" },
+ { "log", "s", do_log,
+ "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
{ "q|quit", "", do_quit,
"", "quit the emulator" },
{ NULL, NULL, },
};
+static term_cmd_t info_cmds[] = {
+ { "version", "", do_info_version,
+ "", "show the version of qemu" },
+ { "network", "", do_info_network,
+ "", "show the network state" },
+ { "block", "", do_info_block,
+ "", "show the block devices" },
+ { "history", "", do_info_history,
+ "", "show the command line history", },
+ { "irq", "", irq_info,
+ "", "show the interrupts statistics (if available)", },
+ { "pic", "", pic_info,
+ "", "show i8259 (PIC) state", },
+ { "pci", "", pci_info,
+ "", "show PCI info", },
+ { NULL, NULL, },
+};
+
+static int get_str(char *buf, int buf_size, const char **pp)
+{
+ const char *p;
+ char *q;
+ int c;
+
+ q = buf;
+ p = *pp;
+ while (isspace(*p))
+ p++;
+ if (*p == '\0') {
+ fail:
+ *q = '\0';
+ *pp = p;
+ return -1;
+ }
+ if (*p == '\"') {
+ p++;
+ while (*p != '\0' && *p != '\"') {
+ if (*p == '\\') {
+ p++;
+ c = *p++;
+ switch(c) {
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case '\\':
+ case '\'':
+ case '\"':
+ break;
+ default:
+ qemu_printf("unsupported escape code: '\\%c'\n", c);
+ goto fail;
+ }
+ if ((q - buf) < buf_size - 1) {
+ *q++ = c;
+ }
+ } else {
+ if ((q - buf) < buf_size - 1) {
+ *q++ = *p;
+ }
+ p++;
+ }
+ }
+ if (*p != '\"') {
+ qemu_printf("unterminated string\n");
+ goto fail;
+ }
+ p++;
+ } else {
+ while (*p != '\0' && !isspace(*p)) {
+ if ((q - buf) < buf_size - 1) {
+ *q++ = *p;
+ }
+ p++;
+ }
+ }
+ *q = '\0';
+ *pp = p;
+ return 0;
+}
+
#define MAX_ARGS 16
static void monitor_handle_command(const char *cmdline)
@@ -149,6 +430,7 @@ static void monitor_handle_command(const char *cmdline)
int c, nb_args, len, i;
term_cmd_t *cmd;
char cmdname[256];
+ char buf[1024];
void *str_allocated[MAX_ARGS];
void *args[MAX_ARGS];
@@ -193,10 +475,53 @@ static void monitor_handle_command(const char *cmdline)
break;
typestr++;
switch(c) {
- /* TODO: add more commands we need here to support vmx device model */
case 'F':
case 'B':
case 's':
+ {
+ int ret;
+ char *str;
+
+ while (isspace(*p))
+ p++;
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ /* no optional string: NULL argument */
+ str = NULL;
+ goto add_str;
+ }
+ }
+ ret = get_str(buf, sizeof(buf), &p);
+ if (ret < 0) {
+ switch(c) {
+ case 'F':
+ term_printf("%s: filename expected\n", cmdname);
+ break;
+ case 'B':
+ term_printf("%s: block device name expected\n", cmdname);
+ break;
+ default:
+ term_printf("%s: string expected\n", cmdname);
+ break;
+ }
+ goto fail;
+ }
+ str = qemu_malloc(strlen(buf) + 1);
+ strcpy(str, buf);
+ str_allocated[nb_args] = str;
+ add_str:
+ if (nb_args >= MAX_ARGS) {
+#if 0
+ error_args:
+#endif
+ term_printf("%s: too many arguments\n", cmdname);
+ goto fail;
+ }
+ args[nb_args++] = str;
+ }
+ break;
+ /* TODO: add more commands we need here to support vmx device model */
case '/':
case 'i':
case '-':
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index cbe7983a44..e8c6058b7d 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -44,7 +44,8 @@ DEPS = .*.d
LIB_OBJS := $(patsubst %.c,%.o,$(SRCS))
PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS))
-LIB := libxc.a libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR)
+LIB := libxc.a libxc-pic.a
+LIB += libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR)
all: build
build: check-for-zlib mk-symlinks
@@ -98,6 +99,9 @@ rpm: build
libxc.a: $(LIB_OBJS)
$(AR) rc $@ $^
+libxc-pic.a: $(PIC_OBJS)
+ $(AR) rc $@ $^
+
libxc.so: libxc.so.$(MAJOR)
ln -sf $< $@
libxc.so.$(MAJOR): libxc.so.$(MAJOR).$(MINOR)
diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h
index 27e7845798..09eff6675f 100644
--- a/tools/libxc/xc.h
+++ b/tools/libxc/xc.h
@@ -110,6 +110,7 @@ int xc_waitdomain_core(int domain,
typedef struct {
u32 domid;
+ u32 ssidref;
unsigned int dying:1, crashed:1, shutdown:1,
paused:1, blocked:1, running:1;
unsigned int shutdown_reason; /* only meaningful if shutdown==1 */
@@ -124,6 +125,7 @@ typedef struct {
typedef dom0_getdomaininfo_t xc_domaininfo_t;
int xc_domain_create(int xc_handle,
+ u32 ssidref,
u32 *pdomid);
@@ -169,7 +171,11 @@ int xc_domain_pincpu(int xc_handle,
int vcpu,
cpumap_t *cpumap);
/**
- * This function will return information about one or more domains.
+ * This function will return information about one or more domains. It is
+ * designed to iterate over the list of domains. If a single domain is
+ * requested, this function will return the next domain in the list - if
+ * one exists. It is, therefore, important in this case to make sure the
+ * domain requested was the one returned.
*
* @parm xc_handle a handle to an open hypervisor interface
* @parm first_domid the first domain to enumerate information from. Domains
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 8f0bba3216..2edf11c39d 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -9,6 +9,7 @@
#include "xc_private.h"
int xc_domain_create(int xc_handle,
+ u32 ssidref,
u32 *pdomid)
{
int err;
@@ -16,6 +17,7 @@ int xc_domain_create(int xc_handle,
op.cmd = DOM0_CREATEDOMAIN;
op.u.createdomain.domain = (domid_t)*pdomid;
+ op.u.createdomain.ssidref = ssidref;
if ( (err = do_dom0_op(xc_handle, &op)) != 0 )
return err;
@@ -101,6 +103,7 @@ int xc_domain_getinfo(int xc_handle,
info->crashed = 1;
}
+ info->ssidref = op.u.getdomaininfo.ssidref;
info->nr_pages = op.u.getdomaininfo.tot_pages;
info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT);
info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
diff --git a/tools/misc/policyprocessor/SecurityLabel.java b/tools/misc/policyprocessor/SecurityLabel.java
new file mode 100644
index 0000000000..c7ffbcaaeb
--- /dev/null
+++ b/tools/misc/policyprocessor/SecurityLabel.java
@@ -0,0 +1,34 @@
+/**
+ * (C) Copyright IBM Corp. 2005
+ *
+ * $Id: SecurityLabel.java,v 1.2 2005/06/17 20:00:04 rvaldez Exp $
+ *
+ * Author: Ray Valdez
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * SecurityLabel Class.
+ *
+ * <p>
+ *
+ * Keeps track of types.
+ *
+ * <p>
+ *
+ *
+ */
+import java.util.*;
+public class SecurityLabel
+{
+ Vector ids;
+ Vector vlans;
+ Vector slots;
+ Vector steTypes;
+ int steSsidPosition;
+ Vector chwIDs;
+ Vector chwTypes;
+ int chwSsidPosition;
+}
diff --git a/tools/misc/policyprocessor/SecurityPolicySpec.xsd b/tools/misc/policyprocessor/SecurityPolicySpec.xsd
new file mode 100644
index 0000000000..bb7265e6b0
--- /dev/null
+++ b/tools/misc/policyprocessor/SecurityPolicySpec.xsd
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Author: Ray Valdez, rvaldez@us.ibm.com -->
+<!-- xml schema definition for xen xml policies -->
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+targetNamespace="http://www.ibm.com"
+xmlns="http://www.ibm.com"
+elementFormDefault="qualified">
+
+<xsd:element name="TE" type="xsd:string" />
+<xsd:element name="ChWall" type="xsd:string" />
+
+<xsd:element name="Definition">
+ <xsd:complexType>
+ <xsd:sequence>
+
+ <!-- simple type enforcement -->
+ <xsd:element name="Types" minOccurs ="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="TE" minOccurs ="1" maxOccurs ="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- chinese wall -->
+ <!-- type definition -->
+ <xsd:element name="ChWallTypes" minOccurs ="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="ChWall" minOccurs ="1" maxOccurs ="unbounded"/>
+
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- conflict set -->
+ <xsd:element name="ConflictSet" minOccurs ="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="ChWall" minOccurs ="2" maxOccurs ="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ </xsd:sequence>
+ </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="Policy">
+ <xsd:complexType>
+ <xsd:sequence>
+
+ <xsd:element name="PolicyHeader">
+ <xsd:complexType>
+ <xsd:all>
+ <xsd:element name = "Name" type="xsd:string"/>
+ <xsd:element name = "DateTime" type="xsd:dateTime"/>
+ <xsd:element name = "Tag" minOccurs ="1" maxOccurs ="1" type="xsd:string"/>
+ <xsd:element name = "TypeDefinition">
+ <xsd:complexType>
+ <xsd:all>
+ <xsd:element name = "url" type="xsd:string"/>
+ <xsd:element name = "hash" minOccurs ="0" maxOccurs ="1" type="xsd:string"/>
+ </xsd:all>
+ </xsd:complexType>
+ </xsd:element>
+
+ </xsd:all>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="VM" minOccurs ="1" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="id" type="xsd:integer"/>
+ <xsd:element ref="TE" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element ref="ChWall" minOccurs ="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="Vlan" minOccurs ="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="vid" type="xsd:integer"/>
+ <xsd:element ref="TE" minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="Slot" minOccurs ="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="bus" type="xsd:integer"/>
+ <xsd:element name="slot" type="xsd:integer"/>
+ <xsd:element ref="TE" minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+
+ </xsd:sequence>
+ </xsd:complexType>
+</xsd:element>
+
+<!-- root element -->
+<xsd:element name="SecurityPolicySpec">
+ <xsd:complexType>
+ <xsd:choice>
+ <xsd:element ref="Definition" minOccurs ="1" maxOccurs="unbounded"/>
+ <xsd:element ref="Policy" minOccurs ="1" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:complexType>
+</xsd:element>
+</xsd:schema>
diff --git a/tools/misc/policyprocessor/SsidsEntry.java b/tools/misc/policyprocessor/SsidsEntry.java
new file mode 100644
index 0000000000..e178d9e6a3
--- /dev/null
+++ b/tools/misc/policyprocessor/SsidsEntry.java
@@ -0,0 +1,29 @@
+/**
+ * (C) Copyright IBM Corp. 2005
+ *
+ * $Id: SsidsEntry.java,v 1.2 2005/06/17 20:02:40 rvaldez Exp $
+ *
+ * Author: Ray Valdez
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * SsidsEntry Class.
+ * <p>
+ *
+ * Holds ssid information.
+ *
+ * <p>
+ *
+ *
+ */
+public class SsidsEntry
+ {
+ int id; /* used for partition and vlan */
+ int bus; /* used for slots */
+ int slot;
+ int ste = 0xffffffff;
+ int chw = 0xffffffff;
+ }
diff --git a/tools/misc/policyprocessor/XmlToBin.java b/tools/misc/policyprocessor/XmlToBin.java
new file mode 100644
index 0000000000..1b21b41535
--- /dev/null
+++ b/tools/misc/policyprocessor/XmlToBin.java
@@ -0,0 +1,1588 @@
+/**
+ * (C) Copyright IBM Corp. 2005
+ *
+ * $Id: XmlToBin.java,v 1.2 2005/06/17 20:00:04 rvaldez Exp $
+ *
+ * Author: Ray Valdez
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * XmlToBin Class.
+ * <p>
+ *
+ * Translates a xml representation of a SHYPE policy into a binary
+ * format. The class processes an xml policy file based on elment tags
+ * defined in a schema definition files: SecurityPolicySpec.xsd.
+ *
+ * XmlToBin Command line Options:
+ *
+ * -i inputFile: name of policyfile (.xml)
+ * -o outputFile: name of binary policy file (Big Endian)
+ * -xssid SsidFile: xen ssids to types text file
+ * -xssidconf SsidConf: xen conflict ssids to types text file
+ * -debug turn on debug messages
+ * -help help. This printout
+ *
+ * <p>
+ *
+ *
+ */
+import java.util.*;
+import java.io.*;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Attr;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+import org.xml.sax.*;
+import javax.xml.parsers.*;
+import org.xml.sax.helpers.*;
+
+public class XmlToBin
+ implements XmlToBinInterface
+{
+ class SlotInfo {
+ String bus;
+ String slot;
+ }
+
+ boolean LittleEndian = false;
+ boolean debug = false;
+
+ static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+
+ static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
+
+ public static void printUsage()
+ {
+ System.out.println("XmlToBin Command line Options: ");
+ System.out.println("\t-i\t\tinputFile:\tname of policyfile (.xml)");
+ System.out.println("\t-o\t\toutputFile:\tname of binary policy file (Big Endian)");
+ System.out.println("\t-xssid\t\tSsidFile:\tXen ssids to named types text file");
+ System.out.println("\t-xssidconf\tSsidConfFile:\tXen conflict ssids to named types text file");
+ System.out.println("\t-debug\t\t\t\tturn on debug messages");
+ System.out.println("\t-help\t\t\t\thelp. This printout");
+ return;
+ }
+
+ public void printDebug(String message)
+ {
+ if (debug)
+ System.out.println(message);
+ }
+
+ public void writeBinPolicy(byte[] binPolicy, String outputFileName)
+ throws Exception
+ {
+ if (debug)
+ printHex(binPolicy,binPolicy.length);
+
+ DataOutputStream writeObj = new DataOutputStream(
+ new FileOutputStream(outputFileName));
+
+ writeObj.write(binPolicy);
+ writeObj.flush();
+ writeObj.close();
+ System.out.println(" wBP:: wrote outputfile: " + outputFileName);
+
+ return;
+ }
+
+ public void writeXenTypeVectorFile(Vector list, String outputFileName)
+ throws Exception
+ {
+ PrintWriter out;
+
+ if (0 == list.size())
+ {
+ printDebug(" wSTF : size of input is zero when writing :" + outputFileName);
+ return;
+ }
+ out = new PrintWriter(
+ new BufferedWriter(
+ new FileWriter(outputFileName)));
+
+
+ for (int i = 0; i < list.size(); i++)
+ {
+ Vector ee = (Vector) list.elementAt(i);
+ out.println(i + " " +ee.toString());
+ }
+ out.close();
+
+ return;
+ }
+
+ public void writeXenTypeFile(Vector list, String outputFileName, boolean slabel)
+ throws Exception
+ {
+ Vector entry;
+ String strTypes = "";
+ SecurityLabel ee;
+ PrintWriter out;
+
+ if (0 == list.size())
+ {
+ printDebug(" wSTF : size of input is zero when writing :" + outputFileName);
+ return;
+ }
+ out = new PrintWriter(
+ new BufferedWriter(
+ new FileWriter(outputFileName)));
+
+ for (int i = 0; i < list.size(); i++)
+ {
+ ee = (SecurityLabel) list.elementAt(i);
+
+ if (slabel)
+ {
+ entry = ee.steTypes;
+ } else {
+
+ entry = ee.chwTypes;
+ }
+ if (null == entry) continue;
+
+ Enumeration e = entry.elements();
+ while (e.hasMoreElements())
+ {
+ String typeName = (String) e.nextElement();
+ strTypes = strTypes + " " + typeName;
+ }
+ printDebug(" WXTF:: ssid : "+i +" :"+strTypes);
+ out.println(i +" "+strTypes);
+ strTypes = "";
+ }
+ out.close();
+
+ return;
+ }
+
+ public void setDebug(boolean value)
+ {
+ debug=value;
+ }
+
+ public void setEndian(boolean value)
+ {
+ LittleEndian = value;
+ }
+
+ public byte[] generateVlanSsids(Vector bagOfSsids)
+ throws Exception
+ {
+ /**
+ typedef struct {
+ u16 vlan;
+ u16 ssid_ste;
+ } acm_vlan_entry_t;
+ **/
+
+ Hashtable vlanSsid = new Hashtable();
+ printDebug(" gVS::Size of bagOfSsids: "+ bagOfSsids.size());
+
+ /* Get the number of partitions */
+ for (int i = 0; i < bagOfSsids.size(); i++)
+ {
+ SecurityLabel entry = (SecurityLabel) bagOfSsids.elementAt(i);
+
+ if (null == entry.vlans)
+ continue;
+
+ Enumeration e = entry.vlans.elements();
+ while (e.hasMoreElements())
+ {
+ String id = (String) e.nextElement();
+ printDebug(" gVS:: vlan: " + id + "has ste ssid: " + entry.steSsidPosition);
+ if (-1 == entry.steSsidPosition)
+ continue;
+
+ /* Only use ste for vlan */
+ SsidsEntry ssidsObj = new SsidsEntry();
+
+ ssidsObj.id = Integer.parseInt(id);
+ ssidsObj.ste = entry.steSsidPosition;
+
+ if (vlanSsid.contains(id))
+ printDebug(" gVS:: Error already in the Hash part:" + ssidsObj.id);
+ else
+ vlanSsid.put(id, ssidsObj);
+ printDebug(" gVS:: added part: " + id + "has ste ssid: " + entry.steSsidPosition);
+ }
+ }
+
+ /* allocate array */
+ int numOfVlan = vlanSsid.size();
+ int totalSize = (numOfVlan * vlanEntrySz);
+
+ if (0 == numOfVlan)
+ {
+ printDebug(" gVS:: vlan: binary ==> zero");
+ return new byte[0];
+ }
+
+ byte[] vlanArray = new byte[totalSize];
+
+ int index = 0;
+
+ Enumeration e = vlanSsid.elements();
+ while (e.hasMoreElements())
+ {
+ SsidsEntry entry = (SsidsEntry) e.nextElement();
+ printDebug(" gVS:: part: " + entry.id + " ste ssid: " + entry.ste);
+
+ /* Write id */
+ writeShortToStream(vlanArray,(short)entry.id,index);
+ index = index + u16Size;
+
+ /* write ste ssid */
+ writeShortToStream(vlanArray,(short) entry.ste,index);
+ index = index + u16Size;
+ }
+
+ printDebug(" gVS:: vlan: num of vlans " + numOfVlan);
+ printDebug(" gVS:: vlan: binary ==> Length "+ vlanArray.length);
+
+ if (debug)
+ printHex(vlanArray,vlanArray.length);
+ printDebug("\n");
+
+ return vlanArray;
+ }
+
+ public byte[] generateSlotSsids(Vector bagOfSsids)
+ throws Exception
+ {
+ /**
+ typedef struct {
+ u16 slot_max;
+ u16 slot_offset;
+ } acm_slot_buffer_t;
+
+ typedef struct {
+ u16 bus;
+ u16 slot;
+ u16 ssid_ste;
+ } acm_slot_entry_t;
+ **/
+ Hashtable slotSsid = new Hashtable();
+ printDebug(" gSS::Size of bagOfSsids: "+ bagOfSsids.size());
+
+ /* Find the number of VMs */
+ for (int i = 0; i < bagOfSsids.size(); i++)
+ {
+ SecurityLabel entry = (SecurityLabel) bagOfSsids.elementAt(i);
+
+ if (null == entry.slots)
+ continue;
+
+ Enumeration e = entry.slots.elements();
+ while (e.hasMoreElements())
+ {
+ SlotInfo item = (SlotInfo) e.nextElement();
+ printDebug(" gSS:: bus slot: " + item.bus + " "+ item.slot + " " + entry.steSsidPosition);
+ if (-1 == entry.steSsidPosition)
+ continue;
+
+ SsidsEntry ssidsObj = new SsidsEntry();
+
+ String id = item.bus +" "+item.slot;
+ ssidsObj.bus = Integer.parseInt(item.bus);
+ ssidsObj.slot = Integer.parseInt(item.slot);
+ /* set ste ssid */
+ ssidsObj.ste = entry.steSsidPosition;
+
+ if (slotSsid.contains(id))
+ printDebug(" gSS:: Error already in the Hash part:" + id);
+ else
+ slotSsid.put(id, ssidsObj);
+
+ printDebug(" gSS:: added slot: " + id + "has ste ssid: " + entry.steSsidPosition);
+ }
+ }
+
+ /* allocate array */
+ int numOfSlot = slotSsid.size();
+
+ if (0 == numOfSlot)
+ {
+ printDebug(" gVS:: slot: binary ==> zero");
+ return new byte[0];
+ }
+
+ int totalSize = (numOfSlot * slotEntrySz);
+
+ byte[] slotArray = new byte[totalSize];
+
+ int index = 0;
+
+ Enumeration e = slotSsid.elements();
+ while (e.hasMoreElements())
+ {
+ SsidsEntry entry = (SsidsEntry) e.nextElement();
+ System.out.println(" gSS:: bus slot: " + entry.bus + " " + entry.slot + " ste ssid: " + entry.ste);
+
+ /* Write bus */
+ writeShortToStream(slotArray,(short)entry.bus,index);
+ index = index + u16Size;
+
+ /* Write slot */
+ writeShortToStream(slotArray,(short)entry.slot,index);
+ index = index + u16Size;
+
+ /* Write ste ssid */
+ writeShortToStream(slotArray,(short) entry.ste,index);
+ index = index + u16Size;
+
+ }
+
+ printDebug(" gSS:: slot: num of vlans " + numOfSlot);
+ printDebug(" gSS:: slot: binary ==> Length "+ slotArray.length);
+
+ if (debug)
+ printHex(slotArray,slotArray.length);
+ printDebug("\n");
+
+ return slotArray;
+
+ }
+
+ public byte[] generatePartSsids(Vector bagOfSsids, Vector bagOfChwSsids)
+ throws Exception
+ {
+ /**
+ typedef struct {
+ u16 id;
+ u16 ssid_ste;
+ u16 ssid_chwall;
+ } acm_partition_entry_t;
+
+ **/
+ Hashtable partSsid = new Hashtable();
+ printDebug(" gPS::Size of bagOfSsids: "+ bagOfSsids.size());
+
+ /* Find the number of VMs */
+ for (int i = 0; i < bagOfSsids.size(); i++)
+ {
+ SecurityLabel entry = (SecurityLabel) bagOfSsids.elementAt(i);
+
+ if (null == entry.ids)
+ continue;
+
+ Enumeration e = entry.ids.elements();
+ while (e.hasMoreElements())
+ {
+ String id = (String) e.nextElement();
+ printDebug(" gPS:: part: " + id + "has ste ssid: " + entry.steSsidPosition);
+ if (-1 == entry.steSsidPosition)
+ continue;
+
+ SsidsEntry ssidsObj = new SsidsEntry();
+
+ ssidsObj.id = Integer.parseInt(id);
+ ssidsObj.ste = entry.steSsidPosition;
+
+ if (partSsid.contains(id))
+ printDebug(" gPS:: Error already in the Hash part:" + ssidsObj.id);
+ else
+ partSsid.put(id, ssidsObj);
+ printDebug(" gPS:: added part: " + id + "has ste ssid: " + entry.steSsidPosition);
+ }
+
+ }
+
+ for (int i = 0; i < bagOfChwSsids.size(); i++)
+ {
+ SecurityLabel entry = (SecurityLabel) bagOfChwSsids.elementAt(i);
+
+ Enumeration e = entry.chwIDs.elements();
+ while (e.hasMoreElements())
+ {
+ String id = (String) e.nextElement();
+ printDebug(" gPS:: part: " + id + "has chw ssid: " + entry.chwSsidPosition);
+ if (partSsid.containsKey(id))
+ {
+ SsidsEntry item = (SsidsEntry) partSsid.get(id);
+ item.chw = entry.chwSsidPosition;
+ printDebug(" gPS:: added :" + item.id +" chw: " + item.chw);
+ }
+ else
+ {
+ printDebug(" gPS:: creating :" + id +" chw: " + entry.chwSsidPosition);
+ SsidsEntry ssidsObj = new SsidsEntry();
+ ssidsObj.id = Integer.parseInt(id);
+ ssidsObj.chw = entry.chwSsidPosition;
+ partSsid.put(id, ssidsObj);
+
+ }
+ }
+ }
+
+ /* Allocate array */
+ int numOfPar = partSsid.size();
+ int totalSize = (numOfPar * partitionEntrySz);
+
+ if (0 == numOfPar)
+ {
+ printDebug(" gPS:: part: binary ==> zero");
+ return new byte[0];
+ }
+
+ byte[] partArray = new byte[totalSize];
+
+ int index = 0;
+
+ Enumeration e = partSsid.elements();
+ while (e.hasMoreElements())
+ {
+ SsidsEntry entry = (SsidsEntry) e.nextElement();
+ printDebug(" gPS:: part: " + entry.id + " ste ssid: " + entry.ste + " chw ssid: "+ entry.chw);
+
+ /* Write id */
+ writeShortToStream(partArray,(short)entry.id,index);
+ index = index + u16Size;
+
+ /* Write ste ssid */
+ writeShortToStream(partArray,(short) entry.ste,index);
+ index = index + u16Size;
+
+ /* Write chw ssid */
+ writeShortToStream(partArray,(short) entry.chw,index);
+ index = index + u16Size;
+ }
+
+ printDebug(" gPS:: part: num of partitions " + numOfPar);
+ printDebug(" gPS:: part: binary ==> Length " + partArray.length);
+
+ if (debug)
+ printHex(partArray,partArray.length);
+ printDebug("\n");
+
+ return partArray;
+ }
+
+ public byte[] GenBinaryPolicyBuffer(byte[] chwPolicy, byte[] stePolicy, byte [] partMap, byte[] vlanMap, byte[] slotMap)
+ {
+ byte[] binBuffer;
+ short chwSize =0;
+ short steSize =0;
+ int index = 0;
+
+ /* Builds data structure acm_policy_buffer_t */
+ /* Get number of colorTypes */
+ if (null != chwPolicy)
+ chwSize = (short) chwPolicy.length;
+
+ if (null != stePolicy)
+ steSize = (short) stePolicy.length;
+
+ int totalDataSize = chwSize + steSize + resourceOffsetSz + 3 *(2 * u16Size);
+
+ /* Add vlan and slot */
+ totalDataSize = totalDataSize +partMap.length + vlanMap.length + slotMap.length;
+ binBuffer = new byte[binaryBufferHeaderSz +totalDataSize];
+
+
+ try {
+ /* Write magic */
+ writeIntToStream(binBuffer,ACM_MAGIC,index);
+ index = u32Size;
+
+ /* Write policy version */
+ writeIntToStream(binBuffer,POLICY_INTERFACE_VERSION,index);
+ index = index + u32Size;
+
+ /* write len */
+ writeIntToStream(binBuffer,binBuffer.length,index);
+ index = index + u32Size;
+
+ } catch (IOException ee) {
+ System.out.println(" GBPB:: got exception : " + ee);
+ return null;
+ }
+
+ int offset, address;
+ address = index;
+
+ if (null != partMap)
+ offset = binaryBufferHeaderSz + resourceOffsetSz;
+ else
+ offset = binaryBufferHeaderSz;
+
+ try {
+
+ if (null == chwPolicy || null == stePolicy)
+ {
+ writeShortToStream(binBuffer,ACM_NULL_POLICY,index);
+ index = index + u16Size;
+
+ writeShortToStream(binBuffer,(short) 0,index);
+ index = index + u16Size;
+
+ writeShortToStream(binBuffer,ACM_NULL_POLICY,index);
+ index = index + u16Size;
+
+ writeShortToStream(binBuffer,(short) 0,index);
+ index = index + u16Size;
+
+ }
+ index = address;
+ if (null != chwPolicy)
+ {
+
+ /* Write policy name */
+ writeShortToStream(binBuffer,ACM_CHINESE_WALL_POLICY,index);
+ index = index + u16Size;
+
+ /* Write offset */
+ writeShortToStream(binBuffer,(short) offset,index);
+ index = index + u16Size;
+
+ /* Write payload. No need increment index */
+ address = offset;
+ System.arraycopy(chwPolicy, 0, binBuffer,address, chwPolicy.length);
+ address = address + chwPolicy.length;
+
+ if (null != stePolicy)
+ {
+ /* Write policy name */
+ writeShortToStream(binBuffer,ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,index);
+ index = index + u16Size;
+
+ /* Write offset */
+ writeShortToStream(binBuffer,(short) address,index);
+ index = index + u16Size;
+
+ /* Copy array */
+ System.arraycopy(stePolicy, 0, binBuffer,address, stePolicy.length);
+ /* Update address */
+ address = address + stePolicy.length;
+ } else {
+ /* Skip writing policy name and offset */
+ index = index + 2 * u16Size;
+
+ }
+
+ } else {
+
+ if (null != stePolicy)
+ {
+ /* Write policy name */
+ writeShortToStream(binBuffer,ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,index);
+ index = index + u16Size;
+
+ /* Write offset */
+ address = offset;
+ writeShortToStream(binBuffer, (short) offset,index);
+ index = index + u16Size;
+
+ /* Copy array */
+ System.arraycopy(stePolicy, 0, binBuffer,address, stePolicy.length);
+ /* Update address */
+ address = address + stePolicy.length;
+
+ /* Increment index, since there is no secondary */
+ index = index + secondaryPolicyCodeSz + secondaryBufferOffsetSz;
+
+ }
+
+ }
+ int size;
+ /* Assumes that you will always have a partition defined in policy */
+ if ( 0 < partMap.length)
+ {
+ writeShortToStream(binBuffer, (short) address,index);
+ index = address;
+
+ /* Compute num of VMs */
+ size = partMap.length / (3 * u16Size);
+
+ writeShortToStream(binBuffer, (short)size,index);
+ index = index + u16Size;
+
+ /* part, vlan and slot: each one consists of two entries */
+ offset = 3 * (2 * u16Size);
+ writeShortToStream(binBuffer, (short) offset,index);
+
+ /* Write partition array at offset */
+ System.arraycopy(partMap, 0, binBuffer,(offset + address), partMap.length);
+ index = index + u16Size;
+ offset = offset + partMap.length;
+ }
+
+ if ( 0 < vlanMap.length)
+ {
+ size = vlanMap.length / (2 * u16Size);
+ writeShortToStream(binBuffer, (short) size,index);
+ index = index + u16Size;
+
+ writeShortToStream(binBuffer, (short) offset,index);
+ index = index + u16Size;
+ System.arraycopy(vlanMap, 0, binBuffer,(offset + address), vlanMap.length);
+ } else {
+ /* Write vlan max */
+ writeShortToStream(binBuffer, (short) 0,index);
+ index = index + u16Size;
+
+ /* Write vlan offset */
+ writeShortToStream(binBuffer, (short) 0,index);
+ index = index + u16Size;
+
+ }
+
+ offset = offset + vlanMap.length;
+ if ( 0 < slotMap.length)
+ {
+ size = slotMap.length / (3 * u16Size);
+ writeShortToStream(binBuffer, (short) size,index);
+ index = index + u16Size;
+
+ writeShortToStream(binBuffer, (short) offset,index);
+ index = index + u16Size;
+ System.arraycopy(slotMap, 0, binBuffer,(offset + address), slotMap.length);
+ }
+
+ } catch (IOException ee)
+ {
+ System.out.println(" GBPB:: got exception : " + ee);
+ return null;
+ }
+
+ printDebug(" GBP:: Binary Policy ==> length " + binBuffer.length);
+ if (debug)
+ printHex(binBuffer,binBuffer.length);
+
+ return binBuffer;
+ }
+
+ public byte[] generateChwBuffer(Vector Ssids, Vector ConflictSsids, Vector ColorTypes)
+ {
+ byte[] chwBuffer;
+ int index = 0;
+ int position = 0;
+
+ /* Get number of rTypes */
+ short maxTypes = (short) ColorTypes.size();
+
+ /* Get number of SSids entry */
+ short maxSsids = (short) Ssids.size();
+
+ /* Get number of conflict sets */
+ short maxConflict = (short) ConflictSsids.size();
+
+
+ if (maxTypes * maxSsids == 0)
+ return null;
+ /*
+ data structure acm_chwall_policy_buffer_t;
+
+ uint16 policy_code;
+ uint16 chwall_max_types;
+ uint16 chwall_max_ssidrefs;
+ uint16 chwall_max_conflictsets;
+ uint16 chwall_ssid_offset;
+ uint16 chwall_conflict_sets_offset;
+ uint16 chwall_running_types_offset;
+ uint16 chwall_conflict_aggregate_offset;
+ */
+ int totalBytes = chwHeaderSize + u16Size *(maxTypes * (maxSsids + maxConflict));
+
+ chwBuffer = new byte[ totalBytes ];
+ int address = chwHeaderSize + (u16Size * maxTypes * maxSsids );
+
+ printDebug(" gCB:: chwall totalbytes : "+totalBytes);
+
+ try {
+ index = 0;
+ writeShortToStream(chwBuffer,ACM_CHINESE_WALL_POLICY,index);
+ index = u16Size;
+
+ writeShortToStream(chwBuffer,maxTypes,index);
+ index = index + u16Size;
+
+ writeShortToStream(chwBuffer,maxSsids,index);
+ index = index + u16Size;
+
+ writeShortToStream(chwBuffer,maxConflict,index);
+ index = index + u16Size;
+
+ /* Write chwall_ssid_offset */
+ writeShortToStream(chwBuffer,chwHeaderSize,index);
+ index = index + u16Size;
+
+ /* Write chwall_conflict_sets_offset */
+ writeShortToStream(chwBuffer,(short) address,index);
+ index = index + u16Size;
+
+ /* Write chwall_running_types_offset */
+ writeShortToStream(chwBuffer,(short) 0,index);
+ index = index + u16Size;
+
+ /* Write chwall_conflict_aggregate_offset */
+ writeShortToStream(chwBuffer,(short) 0,index);
+ index = index + u16Size;
+
+ } catch (IOException ee) {
+ System.out.println(" gCB:: got exception : " + ee);
+ return null;
+ }
+ int markPos = 0;
+
+ /* Create the SSids entry */
+ for (int i = 0; i < maxSsids; i++)
+ {
+
+ SecurityLabel ssidEntry = (SecurityLabel) Ssids.elementAt(i);
+ /* Get chwall types */
+ ssidEntry.chwSsidPosition = i;
+ Enumeration e = ssidEntry.chwTypes.elements();
+ while (e.hasMoreElements())
+ {
+ String typeName = (String) e.nextElement();
+ printDebug(" gCB:: Ssid "+ i+ ": has type : " + typeName);
+ position = ColorTypes.indexOf(typeName);
+
+ if (position < 0)
+ {
+ System.out.println (" gCB:: Error type : " + typeName + " not found in ColorTypes");
+ return null;
+ }
+ printDebug(" GCB:: type : " + typeName + " found in ColorTypes at position: " + position);
+ markPos = ((i * maxTypes + position) * u16Size) + index;
+
+ try {
+ writeShortToStream(chwBuffer,markSymbol,markPos);
+ } catch (IOException ee) {
+ System.out.println(" gCB:: got exception : ");
+ return null;
+ }
+ }
+ }
+
+ if (debug)
+ printHex(chwBuffer,chwBuffer.length);
+
+ /* Add conflict set */
+ index = address;
+ for (int i = 0; i < maxConflict; i++)
+ {
+ /* Get ste types */
+ Vector entry = (Vector) ConflictSsids.elementAt(i);
+ Enumeration e = entry.elements();
+ while (e.hasMoreElements())
+ {
+ String typeName = (String) e.nextElement();
+ printDebug (" GCB:: conflict Ssid "+ i+ ": has type : " + typeName);
+ position = ColorTypes.indexOf(typeName);
+
+ if (position < 0)
+ {
+ System.out.println (" GCB:: Error type : " + typeName + " not found in ColorTypes");
+ return null;
+ }
+ printDebug(" GCB:: type : " + typeName + " found in ColorTypes at position: " + position);
+ markPos = ((i * maxTypes + position) * u16Size) + index;
+
+ try {
+ writeShortToStream(chwBuffer,markSymbol,markPos);
+ } catch (IOException ee) {
+ System.out.println(" GCB:: got exception : ");
+ return null;
+ }
+ }
+
+ }
+ printDebug(" gSB:: chw binary ==> Length " + chwBuffer.length);
+ if (debug)
+ printHex(chwBuffer,chwBuffer.length);
+ printDebug("\n");
+
+ return chwBuffer;
+ }
+
+/**********************************************************************
+ Generate byte representation of policy using type information
+ <p>
+ @param Ssids Vector
+ @param ColorTypes Vector
+ <p>
+ @return bytes represenation of simple type enforcement policy
+**********************************************************************/
+ public byte[] generateSteBuffer(Vector Ssids, Vector ColorTypes)
+ {
+ byte[] steBuffer;
+ int index = 0;
+ int position = 0;
+
+ /* Get number of colorTypes */
+ short numColorTypes = (short) ColorTypes.size();
+
+ /* Get number of SSids entry */
+ short numSsids = (short) Ssids.size();
+
+ if (numColorTypes * numSsids == 0)
+ return null;
+
+ /* data structure: acm_ste_policy_buffer_t
+ *
+ * policy code (uint16) >
+ * max_types (uint16) >
+ * max_ssidrefs (uint16) > steHeaderSize
+ * ssid_offset (uint16) >
+ * DATA (colorTypes(size) * Ssids(size) *unit16)
+ *
+ * total bytes: steHeaderSize * 2B + colorTypes(size) * Ssids(size)
+ *
+ */
+ steBuffer = new byte[ steHeaderSize + (numColorTypes * numSsids) * 2];
+
+ try {
+
+ index = 0;
+ writeShortToStream(steBuffer,ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,index);
+ index = u16Size;
+
+ writeShortToStream(steBuffer,numColorTypes,index);
+ index = index + u16Size;
+
+ writeShortToStream(steBuffer,numSsids,index);
+ index = index + u16Size;
+
+ writeShortToStream(steBuffer,(short)steHeaderSize,index);
+ index = index + u16Size;
+
+ } catch (IOException ee) {
+ System.out.println(" gSB:: got exception : " + ee);
+ return null;
+ }
+ int markPos = 0;
+ for (int i = 0; i < numSsids; i++)
+ {
+
+ SecurityLabel ssidEntry = (SecurityLabel) Ssids.elementAt(i);
+ ssidEntry.steSsidPosition = i;
+ /* Get ste types */
+ Enumeration e = ssidEntry.steTypes.elements();
+ while (e.hasMoreElements())
+ {
+ String typeName = (String) e.nextElement();
+ printDebug (" gSB:: Ssid "+ i+ ": has type : " + typeName);
+ position = ColorTypes.indexOf(typeName);
+
+ if (position < 0)
+ {
+ printDebug(" gSB:: Error type : " + typeName + " not found in ColorTypes");
+ return null;
+ }
+ printDebug(" gSB:: type : " + typeName + " found in ColorTypes at position: " + position);
+ markPos = ((i * numColorTypes + position) * u16Size) + index;
+
+ try {
+ writeShortToStream(steBuffer,markSymbol,markPos);
+ } catch (IOException ee)
+ {
+ System.out.println(" gSB:: got exception : ");
+ return null;
+ }
+ }
+
+ }
+
+ printDebug(" gSB:: ste binary ==> Length " + steBuffer.length);
+ if (debug)
+ printHex(steBuffer,steBuffer.length);
+ printDebug("\n");
+
+ return steBuffer;
+ }
+
+ public static void printHex(byte [] dataArray, int length)
+ {
+ char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ int hexIndex;
+ int value;
+ int arraylength;
+
+ arraylength = length;
+
+ if (dataArray == null)
+ {
+ System.err.print("printHex: input byte array is null");
+ }
+
+ if (length > dataArray.length || length < 0)
+ arraylength = dataArray.length;
+
+ System.out.print("\n\t");
+
+ int i;
+ for(i = 0; i < arraylength; )
+ {
+ value = dataArray[i] & 0xFF;
+ hexIndex = (value >>> 4);
+ System.out.print(hexChars[hexIndex]);
+ hexIndex = (value & 0x0F);
+ System.out.print(hexChars[hexIndex]);
+
+ i++;
+ /* if done, print a final newline */
+ if (i == arraylength) {
+ if (arraylength < dataArray.length) {
+ System.out.print("...");
+ }
+ System.out.println();
+ }
+ else if ((i % 24) == 0) {
+ System.out.print("\n\t");
+ }
+ else if ((i % 4) == 0) {
+ System.out.print(" ");
+ }
+ }
+
+ return;
+ }
+
+
+ private void writeShortToStream(byte[] stream, short value, int index)
+ throws IOException
+ {
+ int littleEndian = 0;
+ int byteVal;
+
+ if (index + 2 > stream.length)
+ {
+ throw new IOException("Writing beyond stream length: " +
+ stream.length + " writing at locations from: " + index + " to " + (index + 4));
+ }
+
+ if (!LittleEndian)
+ {
+
+ byteVal = value >> 8;
+ stream[index ] = (byte) byteVal;
+
+ byteVal = value;
+ stream[index + 1] = (byte) byteVal;
+ } else {
+ stream[index] = (byte) ((value & 0x00ff) );
+ stream[index + 1] = (byte) ((value & 0xff00) >> 8);
+ }
+ return;
+ }
+
+ private void writeIntToStream(byte[] stream, int value, int index)
+ throws IOException
+ {
+ int littleEndian = 0;
+ int byteVal;
+
+ if (4 > stream.length)
+ {
+ throw new IOException("writeIntToStream: stream length less than 4 bytes " +
+ stream.length);
+ }
+
+ /* Do not Write beyond range */
+ if (index + 4 > stream.length)
+ {
+ throw new IOException("writeIntToStream: writing beyond stream length: " +
+ stream.length + " writing at locations from: " + index + " to " + (index + 4));
+ }
+ if (!LittleEndian)
+ {
+ byteVal = value >>> 24;
+ stream[index] = (byte) byteVal;
+
+ byteVal = value >> 16;
+ stream[index + 1] = (byte) byteVal;
+
+ byteVal = value >> 8;
+ stream[index + 2] = (byte) byteVal;
+
+ byteVal = value;
+ stream[index + 3] = (byte) byteVal;
+ } else {
+ stream[index] = (byte) value;
+ stream[index + 1] = (byte) ((value & 0x0000ff00) >> 8);
+ stream[index + 2] = (byte) ((value & 0x00ff0000) >> 16);
+ stream[index + 3] = (byte) ( value >>> 24);
+ }
+ return;
+ }
+
+ public Document getDomTree(String xmlFileName)
+ throws Exception, SAXException, ParserConfigurationException
+ {
+ javax.xml.parsers.DocumentBuilderFactory dbf =
+ javax.xml.parsers.DocumentBuilderFactory.newInstance();
+
+ /* Turn on namespace aware and validation */
+ dbf.setNamespaceAware(true);
+ dbf.setValidating(true);
+ dbf.setAttribute(JAXP_SCHEMA_LANGUAGE,W3C_XML_SCHEMA);
+
+ /* Checks that the document is well-formed */
+ javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
+
+ myHandler errHandler= new myHandler();
+ db.setErrorHandler(errHandler);
+ Document doc = db.parse(xmlFileName);
+
+ /* Checks for validation errors */
+ if (errHandler.isValid)
+ printDebug(" gDT:: Xml file: " + xmlFileName + " is valid");
+ else
+ throw new Exception("Xml file: " + xmlFileName + " is NOT valid");
+
+ return doc;
+ }
+
+ public void processDomTree(
+ Document doc,
+ Vector bagOfSsids,
+ Vector bagOfTypes,
+ Vector bagOfChwSsids,
+ Vector bagOfChwTypes,
+ Vector bagOfConflictSsids)
+ throws Exception, SAXException, ParserConfigurationException
+ {
+ boolean found;
+
+ /* print the root Element */
+ Element root = doc.getDocumentElement();
+ printDebug ("\n pDT:: Document Element: Name = " + root.getNodeName() + ",Value = " + root.getNodeValue());
+
+ /* Go through the list of the root Element's Attributes */
+ NamedNodeMap nnm = root.getAttributes();
+ printDebug (" pDT:: # of Attributes: " + nnm.getLength());
+ for (int i = 0; i < nnm.getLength(); i++)
+ {
+ Node n = nnm.item (i);
+ printDebug (" pDT:: Attribute: Name = " + n.getNodeName() + ", Value = "
+ + n.getNodeValue());
+ }
+
+ /* Retrieve the policy definition */
+ NodeList elementList = root.getElementsByTagName ("url");
+ String definitionFileName = elementList.item(0).getFirstChild().getNodeValue();
+
+ String definitionHash = null;
+
+ /* Note that SecurityPolicySpec.xsd allows for 0 hash value! */
+ elementList = root.getElementsByTagName ("hash");
+ if (0 != elementList.getLength())
+ definitionHash = elementList.item(0).getFirstChild().getNodeValue();
+
+ Document definitionDoc = pGetDomDefinition(definitionFileName,definitionHash);
+ pGetTypes(definitionDoc,bagOfTypes, bagOfChwTypes, bagOfConflictSsids);
+
+
+ /* Get VM security information */
+ elementList = root.getElementsByTagName ("VM");
+ printDebug ("\n pDT:: partition length of NodeList:" + elementList.getLength());
+
+
+ for (int x = 0; x < elementList.getLength(); x++)
+ {
+ found = false;
+
+ Node node = elementList.item (x);
+
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ printDebug (" pDT:: child: " + x + " is an element node" );
+ Element e1 = (Element) node;
+
+ /* Get id */
+ NodeList elist = e1.getElementsByTagName ("id");
+ String idStr = elist.item(0).getFirstChild().getNodeValue();
+ printDebug (" pDT:: id:" + idStr);
+
+ /* Get TE */
+ Vector colorTypes = new Vector();
+ pConflictEntries(e1, "TE", bagOfTypes, colorTypes);
+
+ Enumeration e = bagOfSsids.elements();
+ while (e.hasMoreElements())
+ {
+ SecurityLabel elem = (SecurityLabel) e.nextElement();
+ if ( elem.steTypes.size() == colorTypes.size() && elem.steTypes.containsAll(colorTypes))
+ {
+ found = true;
+ elem.ids.add(idStr);
+ }
+
+ }
+ if (!found && (0 < colorTypes.size()))
+ {
+ SecurityLabel entry = new SecurityLabel();
+ entry.steTypes = colorTypes;
+ entry.ids = new Vector();
+ entry.ids.add(idStr);
+ bagOfSsids.add(entry);
+ }
+
+ /* Get Chinese wall type */
+ Vector chwTypes = new Vector();
+ pConflictEntries(e1, "ChWall", bagOfChwTypes, chwTypes);
+
+ found = false;
+ e = bagOfChwSsids.elements();
+
+ while (e.hasMoreElements())
+ {
+ SecurityLabel elem = (SecurityLabel) e.nextElement();
+ if ( elem.chwTypes.size() == chwTypes.size() && elem.chwTypes.containsAll(chwTypes))
+ {
+ found = true;
+ elem.chwIDs.add(idStr);
+ }
+
+ }
+
+ if (!found && (0 < chwTypes.size()))
+ {
+ SecurityLabel entry = new SecurityLabel();
+ entry.chwTypes = chwTypes;
+ entry.chwIDs = new Vector();
+ entry.chwIDs.add(idStr);
+ bagOfChwSsids.add(entry);
+ }
+ }
+ }
+ return;
+ }
+
+ public Document pGetDomDefinition(
+ String definitionFileName,
+ String definitionHash)
+ throws Exception, SAXException, ParserConfigurationException
+ {
+ printDebug("\n pGDD:: definition file name: " + definitionFileName);
+ printDebug("\n pGDD:: definition file hash: " + definitionHash);
+
+ Document doc = getDomTree(definitionFileName);
+ return doc;
+ }
+
+ public void pGetTypes(
+ Document defDoc,
+ Vector bagOfTypes,
+ Vector bagOfChwTypes,
+ Vector bagOfConflictSsids)
+ throws Exception
+ {
+
+
+ if (null == defDoc)
+ throw new Exception(" pGT:: definition file DOM is null ");
+
+ Element root = defDoc.getDocumentElement();
+
+ /* Get list of TE types */
+ NodeList elementList = root.getElementsByTagName ("Types");
+ printDebug ("\n pGT:: Types length of NodeList:" + elementList.getLength());
+ Element e1 = (Element) elementList.item (0);
+ pGetEntries(e1,"TE",bagOfTypes);
+
+ /* Get list of Chinese types */
+ elementList = root.getElementsByTagName ("ChWallTypes");
+ printDebug ("\n pGT:: ChwTypes length of NodeList:" + elementList.getLength());
+ if (0 == elementList.getLength())
+ {
+ printDebug ("\n pGT:: ChWallTypes has zero length: :" + elementList.getLength());
+ } else {
+ e1 = (Element) elementList.item (0);
+ pGetEntries(e1,"ChWall",bagOfChwTypes);
+ }
+ printDebug (" pGT:: Total number of unique chw types: " + bagOfChwTypes.size());
+
+ /* Get Chinese type conflict sets */
+ elementList = root.getElementsByTagName ("ConflictSet");
+ printDebug ("\n pGT:: Conflict sets length of NodeList:" + elementList.getLength());
+ for (int x = 0; x < elementList.getLength(); x++)
+ {
+ Vector conflictEntry = new Vector();
+ e1 = (Element) elementList.item (x);
+ printDebug ("\n pGT:: Conflict sets : " + x);
+
+ pConflictEntries(e1, "ChWall", bagOfChwTypes, conflictEntry);
+
+ if (conflictEntry.size() > 0)
+ {
+ boolean found = false;
+ Enumeration e = bagOfConflictSsids.elements();
+
+ while (e.hasMoreElements())
+ {
+ Vector elem = (Vector) e.nextElement();
+ if (elem.size() == conflictEntry.size() && elem.containsAll(conflictEntry))
+ {
+ found = true;
+ }
+
+ }
+ if (!found)
+ {
+ bagOfConflictSsids.add(conflictEntry);
+ }
+ }
+ }
+
+ }
+
+ public void pGetEntries(Element doc, String tag, Vector typeBag)
+ throws Exception
+ {
+
+ if (null == doc)
+ throw new Exception(" pGE:: Element doc is null");
+
+ if (null == typeBag)
+ throw new Exception(" pGE:: typeBag is null");
+
+ NodeList elist = doc.getElementsByTagName (tag);
+ for (int j = 0; j < elist.getLength(); j++)
+ {
+ Node knode = elist.item (j);
+ Node childNode = knode.getFirstChild();
+ String value = childNode.getNodeValue();
+
+ printDebug (" pGT:: "+ tag +" type: " + value);
+
+ /* Check if value is known */
+ if (!typeBag.contains(value))
+ typeBag.addElement(value);
+ }
+ }
+
+ public void pConflictEntries(Element doc, String tag, Vector typeBag, Vector conflictEntry)
+ throws Exception
+ {
+
+ if (null == doc)
+ throw new Exception(" pGE:: Element doc is null");
+
+ if (null == typeBag)
+ throw new Exception(" pGE:: typeBag is null");
+
+ if (null == conflictEntry)
+ throw new Exception(" pGE:: typeBag is null");
+
+
+ NodeList elist = doc.getElementsByTagName (tag);
+
+ for (int j = 0; j < elist.getLength(); j++)
+ {
+ Node knode = elist.item (j);
+ Node childNode = knode.getFirstChild();
+ String value = childNode.getNodeValue();
+
+ printDebug (" pGE:: "+ tag +" type: " + value);
+
+ /* Check if value is known */
+ if (!typeBag.contains(value))
+ throw new Exception(" pCE:: found undefined type set " + value);
+
+ if (!conflictEntry.contains(value))
+ conflictEntry.addElement(value);
+
+ }
+ }
+
+ public void processDomTreeVlanSlot(
+ Document doc,
+ Vector bagOfSsids,
+ Vector bagOfTypes)
+ throws Exception
+ {
+ boolean found;
+
+ printDebug(" pDTVS::Size of bagOfSsids: "+ bagOfSsids.size());
+ Element root = doc.getDocumentElement();
+
+ NodeList elementList = root.getElementsByTagName ("Vlan");
+ printDebug("\n pDTVS:: Vlan length of NodeList:" + elementList.getLength());
+
+ for (int x = 0; x < elementList.getLength(); x++)
+ {
+ found = false;
+
+ Node node = elementList.item (x);
+
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ printDebug(" pDTVS:: child: " + x + " is an element node" );
+ Element e1 = (Element) node;
+
+ /* Get vid */
+ NodeList elist = e1.getElementsByTagName ("vid");
+ String idStr = elist.item(0).getFirstChild().getNodeValue();
+ printDebug ("pDTVS:: vid:" + idStr);
+
+ /* Get TE */
+ elist = e1.getElementsByTagName ("TE");
+ printDebug ("pDTVS:: Total ste types: " + elist.getLength());
+
+ Vector colorTypes = new Vector();
+ for (int j = 0; j < elist.getLength(); j++)
+ {
+ Node knode = elist.item (j);
+ Node childNode = knode.getFirstChild();
+ String value = childNode.getNodeValue();
+
+ printDebug (" pDT:: My color is: " + value);
+ if (!bagOfTypes.contains(value))
+ {
+ throw new IOException("pDT:: Vlan: " + idStr+ " has unknown type : "+ value);
+ }
+
+ if (!colorTypes.contains(value))
+ colorTypes.addElement(value);
+ }
+ Enumeration e = bagOfSsids.elements();
+ while (e.hasMoreElements())
+ {
+ SecurityLabel elem = (SecurityLabel) e.nextElement();
+ if ( elem.steTypes.size() == colorTypes.size() && elem.steTypes.containsAll(colorTypes))
+ {
+ found = true;
+ if (null == elem.vlans)
+ elem.vlans = new Vector();
+ elem.vlans.add(idStr);
+ }
+
+ }
+ if (!found && (0 < colorTypes.size()))
+ {
+ SecurityLabel entry = new SecurityLabel();
+ entry.steTypes = colorTypes;
+ entry.vlans = new Vector();
+ entry.vlans.add(idStr);
+ bagOfSsids.add(entry);
+ }
+
+ }
+ }
+ printDebug(" pDTVS::After slot Size of bagOfSsids: "+ bagOfSsids.size());
+
+ elementList = root.getElementsByTagName ("Slot");
+ printDebug ("\n pDTVS:: Slot length of NodeList:" + elementList.getLength());
+
+ for (int x = 0; x < elementList.getLength(); x++)
+ {
+ found = false;
+
+ Node node = elementList.item (x);
+
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ printDebug(" pDT:: child: " + x + " is an element node" );
+ Element e1 = (Element) node;
+
+
+ /* Get slot and bus */
+ SlotInfo item = new SlotInfo();
+
+ NodeList elist = e1.getElementsByTagName ("bus");
+ item.bus = elist.item(0).getFirstChild().getNodeValue();
+ elist = e1.getElementsByTagName ("slot");
+ item.slot = elist.item(0).getFirstChild().getNodeValue();
+ printDebug ("pDT:: bus and slot:" + item.bus + " "+ item.slot);
+
+ /* Get TE */
+ elist = e1.getElementsByTagName ("TE");
+ printDebug ("pDT:: Total ste types: " + elist.getLength());
+
+ Vector colorTypes = new Vector();
+ for (int j = 0; j < elist.getLength(); j++)
+ {
+ Node knode = elist.item (j);
+ Node childNode = knode.getFirstChild();
+ String value = childNode.getNodeValue();
+
+ printDebug ("pDT:: My color is: " + value);
+ if (!bagOfTypes.contains(value))
+ {
+ throw new IOException("pDT:: bus: " + item.bus + " slot: "+ item.slot + " has unknown type : "+ value);
+ }
+
+ if (!colorTypes.contains(value))
+ colorTypes.addElement(value);
+ }
+
+ Enumeration e = bagOfSsids.elements();
+ while (e.hasMoreElements())
+ {
+ SecurityLabel elem = (SecurityLabel) e.nextElement();
+ if ( elem.steTypes.size() == colorTypes.size() && elem.steTypes.containsAll(colorTypes))
+ {
+ found = true;
+ if (null == elem.slots)
+ elem.slots = new Vector();
+ elem.slots.add(item);
+
+ }
+
+ }
+
+ if (!found && (0 < colorTypes.size()))
+ {
+ SecurityLabel entry = new SecurityLabel();
+ entry.steTypes = colorTypes;
+ entry.slots = new Vector();
+ entry.slots.add(item);
+ bagOfSsids.add(entry);
+ }
+
+ }
+ }
+ return;
+ }
+
+ public static void main (String[] args)
+ {
+ String xmlFileName = null; /* policy file */
+ String outputFileName = null; /* binary policy file */
+ String xenSsidOutputFileName = null; /* outputfile ssid to named types */
+ /* outputfile conflicts ssid to named types */
+ String xenSsidConfOutputFileName = null;
+
+ XmlToBin genObj = new XmlToBin();
+
+
+ for (int i = 0 ; i < args.length ; i++) {
+
+ if ( args[i].equals("-help")) {
+ printUsage();
+ System.exit(1);
+
+ } else if ( args[i].equals("-i")) {
+ i++;
+ if (i < args.length) {
+ xmlFileName = args[i];
+ } else {
+ System.out.println("-i argument needs parameter");
+ System.exit(1);
+ }
+
+ } else if ( args[i].equals("-o")) {
+ i++;
+ if (i < args.length) {
+ outputFileName = args[i];
+ } else {
+ System.out.println("-o argument needs parameter");
+ System.exit(1);
+ }
+
+ } else if ( args[i].equals("-xssid")) {
+ i++;
+ if (i < args.length) {
+ xenSsidOutputFileName = args[i];
+ } else {
+ System.out.println("-xssid argument needs parameter");
+ System.exit(1);
+ }
+
+ } else if ( args[i].equals("-xssidconf")) {
+ i++;
+ if (i < args.length) {
+ xenSsidConfOutputFileName = args[i];
+ } else {
+ System.out.println("-xssidconf argument needs parameter");
+ System.exit(1);
+ }
+ } else if ( args[i].equals("-debug")) { /* turn on debug msg */
+ genObj.setDebug(true);
+ } else {
+ System.out.println("bad command line argument: " + args[i]);
+ printUsage();
+ System.exit(1);
+ }
+
+ }
+
+ if (xmlFileName == null)
+ {
+ System.out.println("Need to specify input file -i option");
+ printUsage();
+ System.exit(1);
+ }
+
+
+ try
+ {
+ /* Parse and validate */
+ Document doc = genObj.getDomTree(xmlFileName);
+
+ /* Vectors to hold sets of types */
+ Vector bagOfSsids = new Vector();
+ Vector bagOfTypes = new Vector();
+ Vector bagOfChwSsids = new Vector();
+ Vector bagOfChwTypes = new Vector();
+ Vector bagOfConflictSsids = new Vector();
+
+ Vector vlanMapSsids = new Vector();
+ Vector slotMapSsids = new Vector();
+
+ genObj.processDomTree(doc, bagOfSsids, bagOfTypes, bagOfChwSsids, bagOfChwTypes, bagOfConflictSsids);
+
+ genObj.processDomTreeVlanSlot(doc, bagOfSsids, bagOfTypes);
+
+ /* Get binary representation of policies */
+ byte[] stePolicy = genObj.generateSteBuffer(bagOfSsids, bagOfTypes);
+ byte[] chwPolicy = genObj.generateChwBuffer(bagOfChwSsids, bagOfConflictSsids,bagOfChwTypes);
+
+ byte[] binPolicy = null;
+ byte[] binaryPartionSsid = null;
+ byte[] binaryVlanSsid = null;
+ byte[] binarySlotSsid = null;
+
+ /* Get binary representation of partition to ssid mapping */
+ binaryPartionSsid = genObj.generatePartSsids(bagOfSsids,bagOfChwSsids);
+
+ /* Get binary representation of vlan to ssid mapping */
+ binaryVlanSsid = genObj.generateVlanSsids(bagOfSsids);
+
+ /* Get binary representation of slot to ssid mapping */
+ binarySlotSsid = genObj.generateSlotSsids(bagOfSsids);
+
+ /* Generate binary representation: policy, partition, slot and vlan */
+ binPolicy = genObj.GenBinaryPolicyBuffer(chwPolicy,stePolicy, binaryPartionSsid, binaryVlanSsid, binarySlotSsid);
+
+
+ /* Write binary policy into file */
+ if (null != outputFileName)
+ {
+ genObj.writeBinPolicy(binPolicy, outputFileName);
+ } else {
+ System.out.println (" No binary policy generated, outputFileName: " + outputFileName);
+ }
+
+ /* Print total number of types */
+ System.out.println (" Total number of unique ste types: " + bagOfTypes.size());
+ System.out.println (" Total number of Ssids : " + bagOfSsids.size());
+ System.out.println (" Total number of unique chw types: " + bagOfChwTypes.size());
+ System.out.println (" Total number of conflict ssids : " + bagOfConflictSsids.size());
+ System.out.println (" Total number of chw Ssids : " + bagOfChwSsids.size());
+
+ if (null != xenSsidOutputFileName)
+ genObj.writeXenTypeFile(bagOfSsids, xenSsidOutputFileName, true);
+
+ if (null != xenSsidConfOutputFileName)
+ genObj.writeXenTypeFile(bagOfChwSsids, xenSsidConfOutputFileName, false);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/tools/misc/policyprocessor/XmlToBinInterface.java b/tools/misc/policyprocessor/XmlToBinInterface.java
new file mode 100644
index 0000000000..ec63416519
--- /dev/null
+++ b/tools/misc/policyprocessor/XmlToBinInterface.java
@@ -0,0 +1,135 @@
+/**
+ * (C) Copyright IBM Corp. 2005
+ *
+ * $Id: XmlToBinInterface.java,v 1.2 2005/06/17 20:00:04 rvaldez Exp $
+ *
+ * Author: Ray Valdez
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * XmlToBinInterface Class.
+ * <p>
+ *
+ * Defines constants used by XmToBin.
+ *
+ * <p>
+ *
+ * policy binary structures
+ *
+ * typedef struct {
+ * u32 magic;
+ *
+ * u32 policyversion;
+ * u32 len;
+ *
+ * u16 primary_policy_code;
+ * u16 primary_buffer_offset;
+ * u16 secondary_policy_code;
+ * u16 secondary_buffer_offset;
+ * u16 resource_offset;
+ *
+ * } acm_policy_buffer_t;
+ *
+ * typedef struct {
+ * u16 policy_code;
+ * u16 ste_max_types;
+ * u16 ste_max_ssidrefs;
+ * u16 ste_ssid_offset;
+ * } acm_ste_policy_buffer_t;
+ *
+ * typedef struct {
+ * uint16 policy_code;
+ * uint16 chwall_max_types;
+ * uint16 chwall_max_ssidrefs;
+ * uint16 chwall_max_conflictsets;
+ * uint16 chwall_ssid_offset;
+ * uint16 chwall_conflict_sets_offset;
+ * uint16 chwall_running_types_offset;
+ * uint16 chwall_conflict_aggregate_offset;
+ * } acm_chwall_policy_buffer_t;
+ *
+ * typedef struct {
+ * u16 partition_max;
+ * u16 partition_offset;
+ * u16 vlan_max;
+ * u16 vlan_offset;
+ * u16 slot_max;
+ * u16 slot_offset;
+ * } acm_resource_buffer_t;
+ *
+ * typedef struct {
+ * u16 id;
+ * u16 ssid_ste;
+ * u16 ssid_chwall;
+ * } acm_partition_entry_t;
+ *
+ * typedef struct {
+ * u16 vlan;
+ * u16 ssid_ste;
+ * } acm_vlan_entry_t;
+ *
+ * typedef struct {
+ * u16 bus;
+ * u16 slot;
+ * u16 ssid_ste;
+ * } acm_slot_entry_t;
+ *
+ *
+ *
+ */
+public interface XmlToBinInterface
+{
+ /* policy code (uint16) */
+ final int policyCodeSize = 2;
+
+ /* max_types (uint16) */
+ final int maxTypesSize = 2;
+
+ /* max_ssidrefs (uint16) */
+ final int maxSsidrefSize = 2;
+
+ /* ssid_offset (uint32) */
+ final int ssidOffsetSize = 2;
+
+ final short markSymbol = 0x0001;
+
+ final int u32Size = 4;
+ final int u16Size = 2;
+
+ /* num of bytes for acm_ste_policy_buffer_t */
+ final short steHeaderSize = (4 * u16Size);
+ /* byte for acm_chinese_wall_policy_buffer_t */
+ final short chwHeaderSize = (8 * u16Size);
+
+ final short primaryPolicyCodeSize = u16Size;
+ final short primaryBufferOffsetSize = u16Size ;
+
+ final int secondaryPolicyCodeSz = u16Size;
+ final int secondaryBufferOffsetSz = u16Size;
+ final short resourceOffsetSz = u16Size;
+
+ final short partitionBufferSz = (2 * u16Size);
+ final short partitionEntrySz = (3 * u16Size);
+
+ final short slotBufferSz = (2 * u16Size);
+ final short slotEntrySz = (3 * u16Size);
+
+ final short vlanBufferSz = (2 * u16Size);
+ final short vlanEntrySz = (2 * u16Size);
+
+ final short binaryBufferHeaderSz = (3 * u32Size + 4* u16Size);
+
+ /* copied directlty from policy_ops.h */
+ final int POLICY_INTERFACE_VERSION = 0xAAAA0000;
+
+ /* copied directly from acm.h */
+ final int ACM_MAGIC = 0x0001debc;
+ final short ACM_NULL_POLICY = 0;
+ final short ACM_CHINESE_WALL_POLICY = 1;
+ final short ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY = 2;
+ final short ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY = 3;
+ final short ACM_EMPTY_POLICY = 4;
+}
diff --git a/tools/misc/policyprocessor/myHandler.java b/tools/misc/policyprocessor/myHandler.java
new file mode 100644
index 0000000000..b972c20605
--- /dev/null
+++ b/tools/misc/policyprocessor/myHandler.java
@@ -0,0 +1,47 @@
+/**
+ * (C) Copyright IBM Corp. 2005
+ *
+ * $Id: myHandler.java,v 1.2 2005/06/17 20:00:04 rvaldez Exp $
+ *
+ * Author: Ray Valdez
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * myHandler Class.
+ *
+ * <p>
+ *
+ * A dummy class used for detecting XML validating/parsing errors.
+ *
+ * <p>
+ *
+ *
+ */
+import org.xml.sax.helpers.*;
+import org.xml.sax.SAXParseException;
+
+class myHandler extends DefaultHandler
+{
+ public boolean isValid = true;
+
+ /* Notification of a recoverable error. */
+ public void error(SAXParseException se)
+ {
+ isValid = false;
+ }
+
+ /* Notification of a non-recoverable error. */
+ public void fatalError(SAXParseException se)
+ {
+ isValid = false;
+ }
+
+ /* Notification of a warning. */
+ public void warning(SAXParseException se)
+ {
+ isValid = false;
+ }
+}
diff --git a/tools/misc/policyprocessor/readme.install b/tools/misc/policyprocessor/readme.install
new file mode 100644
index 0000000000..058ab8212a
--- /dev/null
+++ b/tools/misc/policyprocessor/readme.install
@@ -0,0 +1,33 @@
+# Author: Ray Valdez, rvaldez@us.ibm.com
+# Version: 1.0
+#
+# install readme
+#
+PREREQUISITES:
+
+Prior to installation of the policy processor tool (XmlToBin) you must have...
+
+ 1. Java version 1.4.2
+ 2. xmlParserAPIs.jar and xercesImpl.jar
+
+The above can be obtained from the Sun Developer Network web site at
+http://java.sun.com/j2se/1.4.2/download.html.
+
+XmlParserAPIs and xercesImpl jars can be obtained from
+http://www.apache.org/dist/xml/xerces-j (Xerces-J-bin.2.6.2.tar.gz,
+for example).
+
+The tool has been tested with J2SE v1.4.2_08 JRE on Linux (32-bit
+INTEL).
+
+INSTALLATION
+
+1. Set PATH to include $HOME_JAVA/bin and $HOME_JAVA/jre/bin
+ where $HOME_JAVA is your java installation directory
+
+2. Compile XmlToBin:
+ javac XmlToBin.java
+
+USAGE
+
+ See readme.xen
diff --git a/tools/misc/policyprocessor/readme.xen b/tools/misc/policyprocessor/readme.xen
new file mode 100644
index 0000000000..e7f9fa4c9a
--- /dev/null
+++ b/tools/misc/policyprocessor/readme.xen
@@ -0,0 +1,65 @@
+# Author: Ray Valdez, rvaldez@us.ibm.com
+# Version: 1.0
+#
+# This readme describes the policy processor tool for sHype.
+#
+
+Java program:
+
+ java XmlToBin -i [file.xml] -o <file.bin> -xssid <SsidFile> -xssidconf <SsidConf>
+
+ Command line options:
+
+ -i inputFile: name of policyfile (.xml)
+ -o outputFile: name of binary policy file (Big Endian)
+ -xssid SsidFile: xen ssids to named types text file
+ -xssidconf SsidConf: xen conflict ssids to types text file
+ -debug turn on debug messages
+ -help help. This printout
+
+Where:
+
+file.xml is the (input) xml policy file to be parsed and validated.
+The syntax for file.xml is defined in the SecurityPolicySpec.xsd file.
+file.bin is the (output) binary policy file generated by XmlToBin.
+This binary policy can be activated in sHype. The binary policy file
+is laid out in network byte order (i.e., big endian). The SsidFile
+file contains the mapping of type enforcement (TE) ssids to the "named
+types". Similarly, the SsidConf file contains the mapping of Chinese
+Wall (ChWall) ssids to conflict named types. The ssidFile and SsidConf
+files are used by Xen.
+
+Xml Schema and policy:
+
+The SecurityPolicySpec.xsd defines the syntax of a policy file. It
+declares the tags that are used by XmlToBin to generate the binary
+policy file. The tags that XmlToBin keys on are TE, ChWall, id, vid,
+etc. The xml files that describe a policy are simple. Semantic
+checking of a policy is performed mostly by XmlToBin. A type, for
+example, is a string. No fixed values are defined for types in Xml.
+
+A policy consists of two Xml files: definition and policy. The
+definition Xml declares the types that are permitted in the policy
+Xml. The policy Xml contains the assignment of labels to
+subject/object (e.g., vm). This Xml file contains an explicit
+reference to the definition Xml (e.g., <url>xen_sample_def.xml</url>).
+The policy Xml is the one provided as a command line argument.
+
+
+Files:
+
+*.java - policy processor source
+xen_sample_policy.xml - sample xml policy file
+xen_sample_def.xml - sample user defined types
+SecurityPolicySpec.xsd - schema definition file
+
+
+To generate the sample binary policy:
+
+export CLASSPATH=$XERCES_HOME/xercesImpl.jar:$XERCES_HOME/xmlParserAPIs.jar:.
+
+java XmlToBin -i xen_sample_policy.xml -o xen_sample_policy.bin
+
+where $XERCES_HOME is the installation directory of the Apache Xerces-J
+
+
diff --git a/tools/misc/policyprocessor/xen_sample_def.xml b/tools/misc/policyprocessor/xen_sample_def.xml
new file mode 100644
index 0000000000..e64fbd068f
--- /dev/null
+++ b/tools/misc/policyprocessor/xen_sample_def.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!-- Author: Ray Valdez, rvaldez@us.ibm.com -->
+<!-- example policy type definition -->
+<SecurityPolicySpec
+xmlns="http://www.ibm.com"
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="http://www.ibm.com SecurityPolicySpec.xsd">
+
+<Definition>
+<!-- an example of a simple type enforcement type definition -->
+ <Types>
+ <TE>LOCAL-management</TE>
+ <TE>R-Company-development</TE>
+ <TE>S-Company-order</TE>
+ <TE>T-Company-advertising</TE>
+ <TE>U-Company-computing</TE>
+ <!-- TE nondevelopment -->
+ </Types>
+
+<!-- an example of a chinese wall type definition along with conflict sets-->
+ <ChWallTypes>
+ <ChWall>Q-Company</ChWall>
+ <ChWall>R-Company</ChWall>
+ <ChWall>S-Company</ChWall>
+ <ChWall>T-Company</ChWall>
+ <ChWall>U-Company</ChWall>
+ <ChWall>V-Company</ChWall>
+ <ChWall>W-Company</ChWall>
+ <ChWall>X-Company</ChWall>
+ <ChWall>Y-Company</ChWall>
+ <ChWall>Z-Company</ChWall>
+ </ChWallTypes>
+
+ <ConflictSet>
+ <ChWall>T-Company</ChWall>
+ <ChWall>S-Company</ChWall>
+ </ConflictSet>
+
+ <ConflictSet>
+ <ChWall>Q-Company</ChWall>
+ <ChWall>V-Company</ChWall>
+ <ChWall>W-Company</ChWall>
+ </ConflictSet>
+
+</Definition>
+</SecurityPolicySpec>
diff --git a/tools/misc/policyprocessor/xen_sample_policy.xml b/tools/misc/policyprocessor/xen_sample_policy.xml
new file mode 100644
index 0000000000..cebb303c4f
--- /dev/null
+++ b/tools/misc/policyprocessor/xen_sample_policy.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!-- Author: Ray Valdez, rvaldez@us.ibm.com -->
+<!-- example xen policy file -->
+
+<SecurityPolicySpec
+xmlns="http://www.ibm.com"
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="http://www.ibm.com SecurityPolicySpec.xsd">
+<Policy>
+ <PolicyHeader>
+ <Name>xen sample policy</Name>
+ <DateTime>2005-05-20T16:56:00</DateTime>
+ <Tag>foobar</Tag>
+ <TypeDefinition>
+ <url>xen_sample_def.xml</url>
+ <hash>abcdef123456abcdef</hash>
+ </TypeDefinition>
+ </PolicyHeader>
+
+ <VM>
+ <id> 0 </id>
+ <TE>LOCAL-management</TE>
+ <TE>R-Company-development</TE>
+ <TE>S-Company-order</TE>
+ <TE>T-Company-advertising</TE>
+ <TE>U-Company-computing</TE>
+ <ChWall>Q-Company</ChWall>
+ </VM>
+
+ <VM>
+ <id> 1 </id>
+ <TE>R-Company-development</TE>
+ <ChWall>R-Company</ChWall>
+ </VM>
+
+ <VM>
+ <id> 2 </id>
+ <TE>S-Company-order</TE>
+ <ChWall>S-Company</ChWall>
+
+ </VM>
+
+ <VM>
+ <id> 3 </id>
+ <TE>T-Company-advertising</TE>
+ <ChWall>T-Company</ChWall>
+ </VM>
+
+
+ <VM>
+ <id> 4 </id>
+ <TE>U-Company-computing</TE>
+ <ChWall>U-Company</ChWall>
+ </VM>
+
+
+</Policy>
+</SecurityPolicySpec>
diff --git a/tools/misc/xend b/tools/misc/xend
index 768cd20f94..06f5e660ec 100644
--- a/tools/misc/xend
+++ b/tools/misc/xend
@@ -86,9 +86,7 @@ def xcs_running():
def start_xcs():
if (not xcs_running()):
- if os.fork():
- time.sleep(0.1) # let xcs start
- else:
+ if os.fork() == 0 :
if not os.path.isdir(os.path.dirname(XCS_PATH)):
os.makedirs(os.path.dirname(XCS_PATH))
try:
@@ -98,11 +96,15 @@ def start_xcs():
msg("Tried to start xcs, but failed. Is it installed?")
hline()
raise CheckError("couldn't start xcs")
- if (not xcs_running()):
- hline()
- msg("Failed to start the control interface switch.")
- hline()
- raise CheckError("xcs not running")
+ for n in range(10) :
+ if (xcs_running()):
+ break
+ time.sleep(0.1)
+ else :
+ hline()
+ msg("Failed to start the control interface switch.")
+ hline()
+ raise CheckError("xcs not running")
def stop_xcs():
try:
diff --git a/tools/policy/Makefile b/tools/policy/Makefile
new file mode 100644
index 0000000000..b8d67471ae
--- /dev/null
+++ b/tools/policy/Makefile
@@ -0,0 +1,36 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SRCS = policy_tool.c
+CFLAGS += -static
+CFLAGS += -Wall
+CFLAGS += -Werror
+CFLAGS += -O3
+CFLAGS += -fno-strict-aliasing
+CFLAGS += -I.
+
+all: build
+build: mk-symlinks
+ $(MAKE) policy_tool
+
+default: all
+
+install: all
+
+policy_tool : policy_tool.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+clean:
+ rm -rf policy_tool xen
+
+
+LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse)
+mk-symlinks:
+ [ -e xen/linux ] || mkdir -p xen/linux
+ [ -e xen/io ] || mkdir -p xen/io
+ ( cd xen >/dev/null ; \
+ ln -sf ../$(XEN_ROOT)/xen/include/public/*.h . )
+ ( cd xen/io >/dev/null ; \
+ ln -sf ../../$(XEN_ROOT)/xen/include/public/io/*.h . )
+ ( cd xen/linux >/dev/null ; \
+ ln -sf ../../$(LINUX_ROOT)/include/asm-xen/linux-public/*.h . )
diff --git a/tools/policy/policy_tool.c b/tools/policy/policy_tool.c
new file mode 100644
index 0000000000..696a70c282
--- /dev/null
+++ b/tools/policy/policy_tool.c
@@ -0,0 +1,557 @@
+/****************************************************************
+ * policy_tool.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype policy management tool. This code runs in a domain and
+ * manages the Xen security policy by interacting with the
+ * Xen access control module via a /proc/xen/policycmd proc-ioctl,
+ * which is translated into a policy_op hypercall into Xen.
+ *
+ * todo: implement setpolicy to dynamically set a policy cache.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+
+#include <xen/acm.h>
+
+#include <xen/policy_ops.h>
+
+#include <xen/linux/privcmd.h>
+
+#define ERROR(_m, _a...) \
+ fprintf(stderr, "ERROR: " _m "\n" , ## _a )
+
+#define PERROR(_m, _a...) \
+ fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
+ errno, strerror(errno))
+
+static inline int do_policycmd(int xc_handle,
+ unsigned int cmd,
+ unsigned long data)
+{
+ return ioctl(xc_handle, cmd, data);
+}
+
+static inline int do_xen_hypercall(int xc_handle,
+ privcmd_hypercall_t *hypercall)
+{
+ return do_policycmd(xc_handle,
+ IOCTL_PRIVCMD_HYPERCALL,
+ (unsigned long)hypercall);
+}
+
+static inline int do_policy_op(int xc_handle, policy_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ op->interface_version = POLICY_INTERFACE_VERSION;
+
+ hypercall.op = __HYPERVISOR_policy_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen policy hypercall");
+ goto out1;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "POLICY operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ goto out2;
+ }
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+/*************************** DUMPS *******************************/
+
+void acm_dump_chinesewall_buffer(void *buf, int buflen) {
+
+ struct acm_chwall_policy_buffer *cwbuf = (struct acm_chwall_policy_buffer *)buf;
+ domaintype_t *ssids, *conflicts, *running_types, *conflict_aggregate;
+ int i,j;
+
+
+ if (htons(cwbuf->policy_code) != ACM_CHINESE_WALL_POLICY) {
+ printf("CHINESE WALL POLICY CODE not found ERROR!!\n");
+ return;
+ }
+ printf("\n\nChinese Wall policy:\n");
+ printf("====================\n");
+ printf("Max Types = %x.\n", ntohs(cwbuf->chwall_max_types));
+ printf("Max Ssidrefs = %x.\n", ntohs(cwbuf->chwall_max_ssidrefs));
+ printf("Max ConfSets = %x.\n", ntohs(cwbuf->chwall_max_conflictsets));
+ printf("Ssidrefs Off = %x.\n", ntohs(cwbuf->chwall_ssid_offset));
+ printf("Conflicts Off = %x.\n", ntohs(cwbuf->chwall_conflict_sets_offset));
+ printf("Runing T. Off = %x.\n", ntohs(cwbuf->chwall_running_types_offset));
+ printf("C. Agg. Off = %x.\n", ntohs(cwbuf->chwall_conflict_aggregate_offset));
+ printf("\nSSID To CHWALL-Type matrix:\n");
+
+ ssids = (domaintype_t *)(buf + ntohs(cwbuf->chwall_ssid_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_ssidrefs); i++) {
+ printf("\n ssidref%2x: ", i);
+ for(j=0; j< ntohs(cwbuf->chwall_max_types); j++)
+ printf("%02x ", ntohs(ssids[i*ntohs(cwbuf->chwall_max_types) + j]));
+ }
+ printf("\n\nConfict Sets:\n");
+ conflicts = (domaintype_t *)(buf + ntohs(cwbuf->chwall_conflict_sets_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_conflictsets); i++) {
+ printf("\n c-set%2x: ", i);
+ for(j=0; j< ntohs(cwbuf->chwall_max_types); j++)
+ printf("%02x ", ntohs(conflicts[i*ntohs(cwbuf->chwall_max_types) +j]));
+ }
+ printf("\n");
+
+ printf("\nRunning\nTypes: ");
+ if (ntohs(cwbuf->chwall_running_types_offset)) {
+ running_types = (domaintype_t *)(buf + ntohs(cwbuf->chwall_running_types_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_types); i++) {
+ printf("%02x ", ntohs(running_types[i]));
+ }
+ printf("\n");
+ } else {
+ printf("Not Reported!\n");
+ }
+ printf("\nConflict\nAggregate Set: ");
+ if (ntohs(cwbuf->chwall_conflict_aggregate_offset)) {
+ conflict_aggregate = (domaintype_t *)(buf + ntohs(cwbuf->chwall_conflict_aggregate_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_types); i++) {
+ printf("%02x ", ntohs(conflict_aggregate[i]));
+ }
+ printf("\n\n");
+ } else {
+ printf("Not Reported!\n");
+ }
+}
+
+void acm_dump_ste_buffer(void *buf, int buflen) {
+
+ struct acm_ste_policy_buffer *stebuf = (struct acm_ste_policy_buffer *)buf;
+ domaintype_t *ssids;
+ int i,j;
+
+
+ if (ntohs(stebuf->policy_code) != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+ printf("SIMPLE TYPE ENFORCEMENT POLICY CODE not found ERROR!!\n");
+ return;
+ }
+ printf("\nSimple Type Enforcement policy:\n");
+ printf("===============================\n");
+ printf("Max Types = %x.\n", ntohs(stebuf->ste_max_types));
+ printf("Max Ssidrefs = %x.\n", ntohs(stebuf->ste_max_ssidrefs));
+ printf("Ssidrefs Off = %x.\n", ntohs(stebuf->ste_ssid_offset));
+ printf("\nSSID To STE-Type matrix:\n");
+
+ ssids = (domaintype_t *)(buf + ntohs(stebuf->ste_ssid_offset));
+ for(i=0; i< ntohs(stebuf->ste_max_ssidrefs); i++) {
+ printf("\n ssidref%2x: ", i);
+ for(j=0; j< ntohs(stebuf->ste_max_types); j++)
+ printf("%02x ", ntohs(ssids[i*ntohs(stebuf->ste_max_types) +j]));
+ }
+ printf("\n\n");
+}
+
+void acm_dump_policy_buffer(void *buf, int buflen) {
+ struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
+
+ printf("\nPolicy dump:\n");
+ printf("============\n");
+ printf("Magic = %x.\n", ntohl(pol->magic));
+ printf("PolVer = %x.\n", ntohl(pol->policyversion));
+ printf("Len = %x.\n", ntohl(pol->len));
+ printf("Primary = %s (c=%x, off=%x).\n",
+ ACM_POLICY_NAME(ntohs(pol->primary_policy_code)),
+ ntohs(pol->primary_policy_code), ntohs(pol->primary_buffer_offset));
+ printf("Secondary = %s (c=%x, off=%x).\n",
+ ACM_POLICY_NAME(ntohs(pol->secondary_policy_code)),
+ ntohs(pol->secondary_policy_code), ntohs(pol->secondary_buffer_offset));
+ switch (ntohs(pol->primary_policy_code)) {
+ case ACM_CHINESE_WALL_POLICY:
+ acm_dump_chinesewall_buffer(buf+ntohs(pol->primary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->primary_buffer_offset));
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ acm_dump_ste_buffer(buf+ntohs(pol->primary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->primary_buffer_offset));
+ break;
+ case ACM_NULL_POLICY:
+ printf("Primary policy is NULL Policy (n/a).\n");
+ break;
+ default:
+ printf("UNKNOWN POLICY!\n");
+ }
+ switch (ntohs(pol->secondary_policy_code)) {
+ case ACM_CHINESE_WALL_POLICY:
+ acm_dump_chinesewall_buffer(buf+ntohs(pol->secondary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->secondary_buffer_offset));
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ acm_dump_ste_buffer(buf+ntohs(pol->secondary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->secondary_buffer_offset));
+ break;
+ case ACM_NULL_POLICY:
+ printf("Secondary policy is NULL Policy (n/a).\n");
+ break;
+ default:
+ printf("UNKNOWN POLICY!\n");
+ }
+ printf("\nPolicy dump End.\n\n");
+}
+
+/*************************** set policy ****************************/
+
+int acm_domain_set_chwallpolicy(void *bufstart, int buflen) {
+#define CWALL_MAX_SSIDREFS 5
+#define CWALL_MAX_TYPES 10
+#define CWALL_MAX_CONFLICTSETS 2
+
+ struct acm_chwall_policy_buffer *chwall_bin_pol = (struct acm_chwall_policy_buffer *)bufstart;
+ domaintype_t *ssidrefs, *conflicts;
+ int ret = 0;
+ int i,j;
+
+ chwall_bin_pol->chwall_max_types = htons(CWALL_MAX_TYPES);
+ chwall_bin_pol->chwall_max_ssidrefs = htons(CWALL_MAX_SSIDREFS);
+ chwall_bin_pol->policy_code = htons(ACM_CHINESE_WALL_POLICY);
+ chwall_bin_pol->chwall_ssid_offset = htons(sizeof(struct acm_chwall_policy_buffer));
+ chwall_bin_pol->chwall_max_conflictsets = htons(CWALL_MAX_CONFLICTSETS);
+ chwall_bin_pol->chwall_conflict_sets_offset =
+ htons(
+ ntohs(chwall_bin_pol->chwall_ssid_offset) +
+ sizeof(domaintype_t)*CWALL_MAX_SSIDREFS*CWALL_MAX_TYPES);
+ chwall_bin_pol->chwall_running_types_offset = 0; /* not set */
+ chwall_bin_pol->chwall_conflict_aggregate_offset = 0; /* not set */
+ ret += sizeof(struct acm_chwall_policy_buffer);
+ /* now push example ssids into the buffer (max_ssidrefs x max_types entries) */
+ /* check buffer size */
+ if ((buflen - ret) < (CWALL_MAX_TYPES*CWALL_MAX_SSIDREFS*sizeof(domaintype_t)))
+ return -1; /* not enough space */
+
+ ssidrefs = (domaintype_t *)(bufstart+ntohs(chwall_bin_pol->chwall_ssid_offset));
+ for(i=0; i< CWALL_MAX_SSIDREFS; i++) {
+ for (j=0; j< CWALL_MAX_TYPES; j++)
+ ssidrefs[i*CWALL_MAX_TYPES + j] = htons(0);
+ /* here, set type i for ssidref i; generally, a ssidref can have multiple chwall types */
+ if (i < CWALL_MAX_SSIDREFS)
+ ssidrefs[i*CWALL_MAX_TYPES + i] = htons(1);
+ }
+ ret += CWALL_MAX_TYPES*CWALL_MAX_SSIDREFS*sizeof(domaintype_t);
+ if ((buflen - ret) < (CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES*sizeof(domaintype_t)))
+ return -1; /* not enough space */
+
+ /* now the chinese wall policy conflict sets*/
+ conflicts = (domaintype_t *)(bufstart +
+ ntohs(chwall_bin_pol->chwall_conflict_sets_offset));
+ memset((void *)conflicts, 0, CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES*sizeof(domaintype_t));
+ /* just 1 conflict set [0]={2,3}, [1]={0,5,6} */
+ if (CWALL_MAX_TYPES > 3) {
+ conflicts[2] = htons(1); conflicts[3] = htons(1); /* {2,3} */
+ conflicts[CWALL_MAX_TYPES] = htons(1); conflicts[CWALL_MAX_TYPES+5] = htons(1);
+ conflicts[CWALL_MAX_TYPES+6] = htons(1);/* {0,5,6} */
+ }
+ ret += sizeof(domaintype_t)*CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES;
+ return ret;
+}
+
+int acm_domain_set_stepolicy(void *bufstart, int buflen) {
+#define STE_MAX_SSIDREFS 5
+#define STE_MAX_TYPES 5
+
+ struct acm_ste_policy_buffer *ste_bin_pol = (struct acm_ste_policy_buffer *)bufstart;
+ domaintype_t *ssidrefs;
+ int i,j, ret = 0;
+
+ ste_bin_pol->ste_max_types = htons(STE_MAX_TYPES);
+ ste_bin_pol->ste_max_ssidrefs = htons(STE_MAX_SSIDREFS);
+ ste_bin_pol->policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+ ste_bin_pol->ste_ssid_offset = htons(sizeof(struct acm_ste_policy_buffer));
+ ret += sizeof(struct acm_ste_policy_buffer);
+ /* check buffer size */
+ if ((buflen - ret) < (STE_MAX_TYPES*STE_MAX_SSIDREFS*sizeof(domaintype_t)))
+ return -1; /* not enough space */
+
+ ssidrefs = (domaintype_t *)(bufstart+ntohs(ste_bin_pol->ste_ssid_offset));
+ for(i=0; i< STE_MAX_SSIDREFS; i++) {
+ for (j=0; j< STE_MAX_TYPES; j++)
+ ssidrefs[i*STE_MAX_TYPES + j] = htons(0);
+ /* set type i in ssidref 0 and ssidref i */
+ ssidrefs[i] = htons(1); /* ssidref 0 has all types set */
+ if (i < STE_MAX_SSIDREFS)
+ ssidrefs[i*STE_MAX_TYPES + i] = htons(1);
+ }
+ ret += STE_MAX_TYPES*STE_MAX_SSIDREFS*sizeof(domaintype_t);
+ return ret;
+}
+
+#define MAX_PUSH_BUFFER 16384
+u8 push_buffer[MAX_PUSH_BUFFER];
+
+int acm_domain_setpolicy(int xc_handle)
+{
+ int ret;
+ struct acm_policy_buffer *bin_pol;
+ policy_op_t op;
+
+ /* future: read policy from file and set it */
+ bin_pol = (struct acm_policy_buffer *)push_buffer;
+ bin_pol->magic = htonl(ACM_MAGIC);
+ bin_pol->policyversion = htonl(POLICY_INTERFACE_VERSION);
+ bin_pol->primary_policy_code = htons(ACM_CHINESE_WALL_POLICY);
+ bin_pol->secondary_policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+
+ bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
+ bin_pol->primary_buffer_offset = htons(ntohl(bin_pol->len));
+ ret = acm_domain_set_chwallpolicy(push_buffer + ntohs(bin_pol->primary_buffer_offset),
+ MAX_PUSH_BUFFER - ntohs(bin_pol->primary_buffer_offset));
+ if (ret < 0) {
+ printf("ERROR creating chwallpolicy buffer.\n");
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+ bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+ ret = acm_domain_set_stepolicy(push_buffer + ntohs(bin_pol->secondary_buffer_offset),
+ MAX_PUSH_BUFFER - ntohs(bin_pol->secondary_buffer_offset));
+ if (ret < 0) {
+ printf("ERROR creating chwallpolicy buffer.\n");
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+
+ /* dump it and then push it down into xen/acm */
+ acm_dump_policy_buffer(push_buffer, ntohl(bin_pol->len));
+ op.cmd = POLICY_SETPOLICY;
+ op.u.setpolicy.pushcache = (void *)push_buffer;
+ op.u.setpolicy.pushcache_size = ntohl(bin_pol->len);
+ op.u.setpolicy.policy_type = ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ ret = do_policy_op(xc_handle, &op);
+
+ if (ret)
+ printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
+ else
+ printf("Successfully changed policy.\n");
+ return ret;
+}
+
+/******************************* get policy ******************************/
+
+#define PULL_CACHE_SIZE 8192
+u8 pull_buffer[PULL_CACHE_SIZE];
+int acm_domain_getpolicy(int xc_handle)
+{
+ policy_op_t op;
+ int ret;
+
+ memset(pull_buffer, 0x00, sizeof(pull_buffer));
+ op.cmd = POLICY_GETPOLICY;
+ op.u.getpolicy.pullcache = (void *)pull_buffer;
+ op.u.getpolicy.pullcache_size = sizeof(pull_buffer);
+ ret = do_policy_op(xc_handle, &op);
+ /* dump policy */
+ acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer));
+ return ret;
+}
+
+/************************ load binary policy ******************************/
+
+int acm_domain_loadpolicy(int xc_handle,
+ const char *filename)
+{
+ struct stat mystat;
+ int ret, fd;
+ off_t len;
+ u8 *buffer;
+
+ if ((ret = stat(filename, &mystat))) {
+ printf("File %s not found.\n",filename);
+ goto out;
+ }
+
+ len = mystat.st_size;
+ if ((buffer = malloc(len)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if ((fd = open(filename, O_RDONLY)) <= 0) {
+ ret = -ENOENT;
+ printf("File %s not found.\n",filename);
+ goto free_out;
+ }
+ if (len == read(fd, buffer, len)) {
+ policy_op_t op;
+ /* dump it and then push it down into xen/acm */
+ acm_dump_policy_buffer(buffer, len);
+ op.cmd = POLICY_SETPOLICY;
+ op.u.setpolicy.pushcache = (void *)buffer;
+ op.u.setpolicy.pushcache_size = len;
+ op.u.setpolicy.policy_type = ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ ret = do_policy_op(xc_handle, &op);
+
+ if (ret)
+ printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
+ else
+ printf("Successfully changed policy.\n");
+
+ } else {
+ ret = -1;
+ }
+ close(fd);
+ free_out:
+ free(buffer);
+ out:
+ return ret;
+}
+
+/************************ dump hook statistics ******************************/
+void
+dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
+{
+ printf("STE-Policy Security Hook Statistics:\n");
+ printf("ste: event_channel eval_count = %d\n", ntohl(ste_stats->ec_eval_count));
+ printf("ste: event_channel denied_count = %d\n", ntohl(ste_stats->ec_denied_count));
+ printf("ste: event_channel cache_hit_count = %d\n", ntohl(ste_stats->ec_cachehit_count));
+ printf("ste:\n");
+ printf("ste: grant_table eval_count = %d\n", ntohl(ste_stats->gt_eval_count));
+ printf("ste: grant_table denied_count = %d\n", ntohl(ste_stats->gt_denied_count));
+ printf("ste: grant_table cache_hit_count = %d\n", ntohl(ste_stats->gt_cachehit_count));
+}
+
+#define PULL_STATS_SIZE 8192
+int acm_domain_dumpstats(int xc_handle)
+{
+ u8 stats_buffer[PULL_STATS_SIZE];
+ policy_op_t op;
+ int ret;
+ struct acm_stats_buffer *stats;
+
+ memset(stats_buffer, 0x00, sizeof(stats_buffer));
+ op.cmd = POLICY_DUMPSTATS;
+ op.u.dumpstats.pullcache = (void *)stats_buffer;
+ op.u.dumpstats.pullcache_size = sizeof(stats_buffer);
+ ret = do_policy_op(xc_handle, &op);
+
+ if (ret < 0) {
+ printf("ERROR dumping policy stats. Use 'xm dmesg' to see details.\n");
+ return ret;
+ }
+ stats = (struct acm_stats_buffer *)stats_buffer;
+
+ printf("\nPolicy dump:\n");
+ printf("============\n");
+ printf("Magic = %x.\n", ntohl(stats->magic));
+ printf("PolVer = %x.\n", ntohl(stats->policyversion));
+ printf("Len = %x.\n", ntohl(stats->len));
+
+ switch(ntohs(stats->primary_policy_code)) {
+ case ACM_NULL_POLICY:
+ printf("NULL Policy: No statistics apply.\n");
+ break;
+ case ACM_CHINESE_WALL_POLICY:
+ printf("Chinese Wall Policy: No statistics apply.\n");
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ dump_ste_stats((struct acm_ste_stats_buffer *)(stats_buffer + ntohs(stats->primary_stats_offset)));
+ break;
+ default:
+ printf("UNKNOWN PRIMARY POLICY ERROR!\n");
+ }
+ switch(ntohs(stats->secondary_policy_code)) {
+ case ACM_NULL_POLICY:
+ printf("NULL Policy: No statistics apply.\n");
+ break;
+ case ACM_CHINESE_WALL_POLICY:
+ printf("Chinese Wall Policy: No statistics apply.\n");
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ dump_ste_stats((struct acm_ste_stats_buffer *)(stats_buffer + ntohs(stats->secondary_stats_offset)));
+ break;
+ default:
+ printf("UNKNOWN SECONDARY POLICY ERROR!\n");
+ }
+ return ret;
+}
+
+/***************************** main **************************************/
+
+void
+usage(char *progname){
+ printf("Use: %s \n"
+ "\t setpolicy\n"
+ "\t getpolicy\n"
+ "\t dumpstats\n"
+ "\t loadpolicy <binary policy file>\n", progname);
+ exit(-1);
+}
+
+int
+main(int argc, char **argv) {
+
+ int policycmd_fd;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ if ((policycmd_fd = open("/proc/xen/privcmd", O_RDONLY)) <= 0) {
+ printf("ERROR: Could not open xen policycmd device!\n");
+ exit(-1);
+ }
+
+ if (!strcmp(argv[1], "setpolicy")) {
+ if (argc != 2)
+ usage(argv[0]);
+ acm_domain_setpolicy(policycmd_fd);
+
+ } else if (!strcmp(argv[1], "getpolicy")) {
+ if (argc != 2)
+ usage(argv[0]);
+ acm_domain_getpolicy(policycmd_fd);
+
+ } else if (!strcmp(argv[1], "loadpolicy")) {
+ if (argc != 3)
+ usage(argv[0]);
+ acm_domain_loadpolicy(policycmd_fd, argv[2]);
+
+ } else if (!strcmp(argv[1], "dumpstats")) {
+ if (argc != 2)
+ usage(argv[0]);
+ acm_domain_dumpstats(policycmd_fd);
+
+ } else
+ usage(argv[0]);
+
+ close(policycmd_fd);
+ return 0;
+}
diff --git a/tools/python/setup.py b/tools/python/setup.py
index fabe80bd8b..e2a5b09ca1 100644
--- a/tools/python/setup.py
+++ b/tools/python/setup.py
@@ -17,7 +17,7 @@ library_dirs = [ XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/xenstore",
]
-libraries = [ "xc", "xenstore" ]
+libraries = [ "xc", "xenstore-pic" ]
xc = Extension("xc",
extra_compile_args = extra_compile_args,
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 13d60be08e..81721d961e 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -78,13 +78,14 @@ static PyObject *pyxc_domain_create(PyObject *self,
u32 dom = 0;
int ret;
+ u32 ssidref = 0xFFFFFFFF;
- static char *kwd_list[] = { "dom", NULL };
+ static char *kwd_list[] = { "dom", "ssidref", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &dom))
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, &dom, &ssidref))
return NULL;
- if ( (ret = xc_domain_create(xc->xc_handle, &dom)) < 0 )
+ if ( (ret = xc_domain_create(xc->xc_handle, ssidref, &dom)) < 0 )
return PyErr_SetFromErrno(xc_error);
return PyInt_FromLong(dom);
@@ -230,7 +231,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
}
info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
- ",s:l,s:L,s:l,s:i}",
+ ",s:l,s:L,s:l,s:i,s:i}",
"dom", info[i].domid,
"vcpus", info[i].vcpus,
"dying", info[i].dying,
@@ -242,6 +243,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
"mem_kb", info[i].nr_pages*4,
"cpu_time", info[i].cpu_time,
"maxmem_kb", info[i].max_memkb,
+ "ssidref", info[i].ssidref,
"shutdown_reason", info[i].shutdown_reason);
PyDict_SetItemString( info_dict, "vcpu_to_cpu", vcpu_list );
PyDict_SetItemString( info_dict, "cpumap", cpumap_list );
diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c
index 0da0fbcb3e..726b83e8e1 100644
--- a/tools/python/xen/lowlevel/xs/xs.c
+++ b/tools/python/xen/lowlevel/xs/xs.c
@@ -1,3 +1,8 @@
+/*
+ * Python interface to the Xen Store Daemon.
+ * Copyright (C) 2005 Mike Wray Hewlett-Packard
+ */
+
#include <Python.h>
#include <stdio.h>
@@ -47,35 +52,13 @@ static inline PyObject *pyvalue_str(char *val) {
: PyErr_SetFromErrno(PyExc_RuntimeError));
}
-static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds)
-{
- static char *kwd_spec[] = { "path", "data", "create", "excl", NULL };
- static char *arg_spec = "ss#|ii";
- char *path = NULL;
- char *data = NULL;
- int data_n = 0;
- int create = 0;
- int excl = 0;
-
- struct xs_handle *xh = xshandle(self);
- PyObject *val = NULL;
- int flags = 0;
- int xsval = 0;
-
- if (!xh)
- goto exit;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
- &path, &data, &data_n, &create, &excl))
- goto exit;
- if (create)
- flags |= O_CREAT;
- if (excl)
- flags |= O_EXCL;
- xsval = xs_write(xh, path, data, data_n, flags);
- val = pyvalue_int(xsval);
- exit:
- return val;
-}
+#define xspy_read_doc "\n" \
+ "Read data from a path.\n" \
+ " path [string]: xenstore path\n" \
+ "\n" \
+ "Returns: [string] data read.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds)
{
@@ -105,26 +88,55 @@ static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds)
return val;
}
-static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds)
+#define xspy_write_doc "\n" \
+ "Write data to a path.\n" \
+ " path [string] : xenstore path to write to\n." \
+ " data [string] : data to write.\n" \
+ " create [int] : create flag, default 0.\n" \
+ " excl [int] : exclusive flag, default 0.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
+static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwd_spec[] = { "path", NULL };
- static char *arg_spec = "s|";
+ static char *kwd_spec[] = { "path", "data", "create", "excl", NULL };
+ static char *arg_spec = "ss#|ii";
char *path = NULL;
+ char *data = NULL;
+ int data_n = 0;
+ int create = 0;
+ int excl = 0;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
+ int flags = 0;
int xsval = 0;
if (!xh)
goto exit;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+ &path, &data, &data_n, &create, &excl))
goto exit;
- xsval = xs_mkdir(xh, path);
+ if (create)
+ flags |= O_CREAT;
+ if (excl)
+ flags |= O_EXCL;
+ xsval = xs_write(xh, path, data, data_n, flags);
val = pyvalue_int(xsval);
exit:
return val;
}
+#define xspy_ls_doc "\n" \
+ "List a directory.\n" \
+ " path [string]: path to list.\n" \
+ "\n" \
+ "Returns: [string array] list of subdirectory names.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
@@ -153,6 +165,42 @@ static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds)
return val;
}
+#define xspy_mkdir_doc "\n" \
+ "Make a directory.\n" \
+ " path [string]: path to directory to create.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
+static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwd_spec[] = { "path", NULL };
+ static char *arg_spec = "s|";
+ char *path = NULL;
+
+ struct xs_handle *xh = xshandle(self);
+ PyObject *val = NULL;
+ int xsval = 0;
+
+ if (!xh)
+ goto exit;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
+ goto exit;
+ xsval = xs_mkdir(xh, path);
+ val = pyvalue_int(xsval);
+ exit:
+ return val;
+}
+
+#define xspy_rm_doc "\n" \
+ "Remove a path.\n" \
+ " path [string] : path to remove\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
@@ -173,6 +221,14 @@ static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds)
return val;
}
+#define xspy_get_permissions_doc "\n" \
+ "Get the permissions for a path\n" \
+ " path [string]: xenstore path.\n" \
+ "\n" \
+ "Returns: permissions array.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -209,6 +265,15 @@ static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
return val;
}
+#define xspy_set_permissions_doc "\n" \
+ "Set the permissions for a path\n" \
+ " path [string] : xenstore path.\n" \
+ " perms : permissions.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_set_permissions(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -275,12 +340,23 @@ static PyObject *xspy_set_permissions(PyObject *self, PyObject *args,
return val;
}
+#define xspy_watch_doc "\n" \
+ "Watch a path, get notifications when it changes.\n" \
+ " path [string] : xenstore path.\n" \
+ " priority [int] : watch priority (default 0).\n" \
+ " token [string] : returned in watch notification.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwd_spec[] = { "path", "priority", NULL };
- static char *arg_spec = "s|i";
+ static char *kwd_spec[] = { "path", "priority", "token", NULL };
+ static char *arg_spec = "s|is";
char *path = NULL;
int priority = 0;
+ char *token = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
@@ -289,14 +365,24 @@ static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
- &path, &priority))
+ &path, &priority, &token))
goto exit;
- xsval = xs_watch(xh, path, priority);
+ xsval = xs_watch(xh, path, token, priority);
val = pyvalue_int(xsval);
exit:
return val;
}
+#define xspy_read_watch_doc "\n" \
+ "Read a watch notification.\n" \
+ "The notification must be acknowledged by passing\n" \
+ "the token to acknowledge_watch().\n" \
+ " path [string]: xenstore path.\n" \
+ "\n" \
+ "Returns: [tuple] (path, token).\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -305,25 +391,39 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
- char *xsval = NULL;
+ char **xsval = NULL;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
xsval = xs_read_watch(xh);
- val = pyvalue_str(xsval);
+ if (!xsval) {
+ val = PyErr_SetFromErrno(PyExc_RuntimeError);
+ goto exit;
+ }
+ /* Create tuple (path, token). */
+ val = Py_BuildValue("(ss)", xsval[0], xsval[1]);
exit:
if (xsval)
free(xsval);
return val;
}
+#define xspy_acknowledge_watch_doc "\n" \
+ "Acknowledge a watch notification that has been read.\n" \
+ " token [string] : from the watch notification\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args,
PyObject *kwds)
{
- static char *kwd_spec[] = { NULL };
- static char *arg_spec = "";
+ static char *kwd_spec[] = { "token", NULL };
+ static char *arg_spec = "s";
+ char *token;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
@@ -331,19 +431,29 @@ static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args,
if (!xh)
goto exit;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token))
goto exit;
- xsval = xs_acknowledge_watch(xh);
+ xsval = xs_acknowledge_watch(xh, token);
val = pyvalue_int(xsval);
exit:
return val;
}
+#define xspy_unwatch_doc "\n" \
+ "Stop watching a path.\n" \
+ " path [string] : xenstore path.\n" \
+ " token [string] : token from the watch.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwd_spec[] = { "path", NULL };
- static char *arg_spec = "s|";
+ static char *kwd_spec[] = { "path", "token", NULL };
+ static char *arg_spec = "s|s";
char *path = NULL;
+ char *token = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
@@ -351,14 +461,24 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
if (!xh)
goto exit;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path,
+ &token))
goto exit;
- xsval = xs_unwatch(xh, path);
+ xsval = xs_unwatch(xh, path, token);
val = pyvalue_int(xsval);
exit:
return val;
}
+#define xspy_transaction_start_doc "\n" \
+ "Start a transaction on a path.\n" \
+ "Only one transaction can be active at a time.\n" \
+ " path [string]: xenstore path.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -380,6 +500,15 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
return val;
}
+#define xspy_transaction_end_doc "\n" \
+ "End the current transaction.\n" \
+ "Attempts to commit the transaction unless abort is true.\n" \
+ " abort [int]: abort flag (default 0).\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -401,6 +530,17 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
return val;
}
+#define xspy_introduce_domain_doc "\n" \
+ "Tell xenstore about a domain so it can talk to it.\n" \
+ " dom [int] : domain id\n" \
+ " page [long] : address of domain's xenstore page\n" \
+ " port [int] : port the domain is using for xenstore\n" \
+ " path [string]: path to the domain's data in xenstore\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -420,15 +560,21 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&dom, &page, &port, &path))
goto exit;
- printf("%s> dom=%u page=0x%08lx port=%u path=%s\n", __FUNCTION__, dom,
- page, port, path);
xsval = xs_introduce_domain(xh, dom, page, port, path);
- printf("%s> xsval=%d\n", __FUNCTION__, xsval);
val = pyvalue_int(xsval);
exit:
return val;
}
+#define xspy_release_domain_doc "\n" \
+ "Tell xenstore to release its channel to a domain.\n" \
+ "Unless this is done the domain will not be released.\n" \
+ " dom [int]: domain id\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_release_domain(PyObject *self, PyObject *args,
PyObject *kwds)
{
@@ -445,14 +591,19 @@ static PyObject *xspy_release_domain(PyObject *self, PyObject *args,
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&dom))
goto exit;
- printf("%s> dom=%u\n", __FUNCTION__, dom);
xsval = xs_release_domain(xh, dom);
- printf("%s> xsval=%d\n", __FUNCTION__, xsval);
val = pyvalue_int(xsval);
exit:
return val;
}
+#define xspy_close_doc "\n" \
+ "Close the connection to xenstore.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
@@ -473,6 +624,13 @@ static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds)
return val;
}
+#define xspy_shutdown_doc "\n" \
+ "Shutdown the xenstore daemon.\n" \
+ "\n" \
+ "Returns: [int] 0 on success.\n" \
+ "Raises RuntimeError on error.\n" \
+ "\n"
+
static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
@@ -492,59 +650,60 @@ static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds)
return val;
}
-#define XSPY_METH(_name) \
- #_name, \
- (PyCFunction) xspy_ ## _name, \
- (METH_VARARGS | METH_KEYWORDS)
-// mtime
-// ctime
+#define xspy_fileno_doc "\n" \
+ "Get the file descriptor of the xenstore socket.\n" \
+ "Allows an xs object to be passed to select().\n" \
+ "\n" \
+ "Returns: [int] file descriptor.\n" \
+ "\n"
+
+static PyObject *xspy_fileno(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwd_spec[] = { NULL };
+ static char *arg_spec = "";
+
+ struct xs_handle *xh = xshandle(self);
+ PyObject *val = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
+ goto exit;
+ val = PyInt_FromLong((xh ? xs_fileno(xh) : -1));
+ exit:
+ return val;
+}
+
+#define XSPY_METH(_name) { \
+ .ml_name = #_name, \
+ .ml_meth = (PyCFunction) xspy_ ## _name, \
+ .ml_flags = (METH_VARARGS | METH_KEYWORDS), \
+ .ml_doc = xspy_ ## _name ## _doc }
static PyMethodDef xshandle_methods[] = {
- { XSPY_METH(read),
- "read(path) : read data\n" },
- { XSPY_METH(write),
- "write(path, data, [creat], [excl]): write data\n" },
- { XSPY_METH(ls),
- "ls(path): list directory.\n" },
- { XSPY_METH(mkdir),
- "mkdir(path): make a directory.\n" },
- { XSPY_METH(rm),
- "rm(path): remove a path (dir must be empty).\n" },
- { XSPY_METH(get_permissions),
- "get_permissions(path)\n" },
- { XSPY_METH(set_permissions),
- "set_permissions(path)\n" },
- { XSPY_METH(watch),
- "watch(path)\n" },
- { XSPY_METH(read_watch),
- "read_watch()\n" },
- { XSPY_METH(acknowledge_watch),
- "acknowledge_watch()\n" },
- { XSPY_METH(unwatch),
- "unwatch()\n" },
- { XSPY_METH(transaction_start),
- "transaction_start()\n" },
- { XSPY_METH(transaction_end),
- "transaction_end([abort])\n" },
- { XSPY_METH(introduce_domain),
- "introduce_domain(dom, page, port)\n" },
- { XSPY_METH(release_domain),
- "release_domain(dom)\n" },
- { XSPY_METH(close),
- "close()\n" },
- { XSPY_METH(shutdown),
- "shutdown()\n" },
- { NULL, NULL, 0, NULL }
+ XSPY_METH(read),
+ XSPY_METH(write),
+ XSPY_METH(ls),
+ XSPY_METH(mkdir),
+ XSPY_METH(rm),
+ XSPY_METH(get_permissions),
+ XSPY_METH(set_permissions),
+ XSPY_METH(watch),
+ XSPY_METH(read_watch),
+ XSPY_METH(acknowledge_watch),
+ XSPY_METH(unwatch),
+ XSPY_METH(transaction_start),
+ XSPY_METH(transaction_end),
+ XSPY_METH(introduce_domain),
+ XSPY_METH(release_domain),
+ XSPY_METH(close),
+ XSPY_METH(shutdown),
+ XSPY_METH(fileno),
+ { /* Terminator. */ },
};
static PyObject *xshandle_getattr(PyObject *self, char *name)
{
PyObject *val = NULL;
- if (strcmp(name, "fileno") == 0) {
- struct xs_handle *xh = xshandle(self);
- val = PyInt_FromLong((xh ? xs_fileno(xh) : -1));
- } else
- val = Py_FindMethod(xshandle_methods, self, name);
+ val = Py_FindMethod(xshandle_methods, self, name);
return val;
}
@@ -604,9 +763,16 @@ static PyObject *xshandle_open(PyObject *self, PyObject *args, PyObject *kwds)
}
static PyMethodDef xs_methods[] = {
- { "open", (PyCFunction)xshandle_open, (METH_VARARGS | METH_KEYWORDS),
- "Open a connection to the xenstore daemon.\n" },
- { NULL, NULL, 0, NULL }
+ { .ml_name = "open",
+ .ml_meth = (PyCFunction)xshandle_open,
+ .ml_flags = (METH_VARARGS | METH_KEYWORDS),
+ .ml_doc = "\n"
+ "Open a connection to the xenstore daemon.\n"
+ "Returns: xs connection object.\n"
+ "Raises RuntimeError on error.\n"
+ "\n"
+ },
+ { /* Terminator. */ }
};
PyMODINIT_FUNC initxs (void)
diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c
index cd616e75bc..621de6272b 100644
--- a/tools/python/xen/lowlevel/xu/xu.c
+++ b/tools/python/xen/lowlevel/xu/xu.c
@@ -744,6 +744,14 @@ static PyObject *xu_message_get_payload(PyObject *self, PyObject *args)
C2P(mem_request_t, target, Int, Long);
C2P(mem_request_t, status, Int, Long);
return dict;
+ case TYPE(CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_OFF):
+ C2P(vcpu_hotplug_t, vcpu, Int, Long);
+ C2P(vcpu_hotplug_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_ON):
+ C2P(vcpu_hotplug_t, vcpu, Int, Long);
+ C2P(vcpu_hotplug_t, status, Int, Long);
+ return dict;
}
return PyString_FromStringAndSize((char *)xum->msg.msg, xum->msg.length);
@@ -909,6 +917,14 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
case TYPE(CMSG_MEM_REQUEST, CMSG_MEM_REQUEST_SET):
P2C(mem_request_t, target, u32);
break;
+ case TYPE(CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_OFF):
+ P2C(vcpu_hotplug_t, vcpu, u32);
+ P2C(vcpu_hotplug_t, status, u32);
+ break;
+ case TYPE(CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_ON):
+ P2C(vcpu_hotplug_t, vcpu, u32);
+ P2C(vcpu_hotplug_t, status, u32);
+ break;
case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED):
P2C(usbif_fe_interface_status_changed_t, status, u32);
P2C(usbif_fe_interface_status_changed_t, evtchn, u16);
diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py
index 012a8b8dcc..24812f4abb 100644
--- a/tools/python/xen/xend/XendClient.py
+++ b/tools/python/xen/xend/XendClient.py
@@ -271,6 +271,12 @@ class Xend:
'target' : mem_target })
return val
+ def xend_domain_vcpu_hotplug(self, id, vcpu, state):
+ return self.xendPost(self.domainurl(id),
+ {'op' : 'vcpu_hotplug',
+ 'vcpu' : vcpu,
+ 'state' : state })
+
def xend_domain_vif_limit(self, id, vif, credit, period):
return self.xendPost(self.domainurl(id),
{ 'op' : 'vif_limit_set',
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py
index ff688f6df1..3944b8578d 100644
--- a/tools/python/xen/xend/XendDomain.py
+++ b/tools/python/xen/xend/XendDomain.py
@@ -710,6 +710,18 @@ class XendDomain:
dominfo = self.domain_lookup(id)
return dominfo.mem_target_set(mem)
+ def domain_vcpu_hotplug(self, id, vcpu, state):
+ """Enable or disable VCPU vcpu in DOM id
+
+ @param id: domain
+ @param vcpu: target VCPU in domain
+ @param state: which state VCPU will become
+ @return: 0 on success, -1 on error
+ """
+
+ dominfo = self.domain_lookup(id)
+ return dominfo.vcpu_hotplug(vcpu, state)
+
def domain_dumpcore(self, id):
"""Save a core dump for a crashed domain.
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 16415d78a7..556050d3bf 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -157,7 +157,7 @@ class XendDomainInfo:
db = parentdb.addChild(uuid)
vm = cls(db)
vm.construct(config)
- vm.saveDB(sync=True)
+ vm.saveToDB(sync=True)
return vm
create = classmethod(create)
@@ -193,7 +193,7 @@ class XendDomainInfo:
recreate = classmethod(recreate)
- def restore(cls, parentdb, config, uuid=None):
+ def restore(cls, parentdb, config, uuid):
"""Create a domain and a VM object to do a restore.
@param parentdb: parent db
@@ -202,16 +202,22 @@ class XendDomainInfo:
"""
db = parentdb.addChild(uuid)
vm = cls(db)
- dom = xc.domain_create()
- vm.setdom(dom)
- vm.dom_construct(vm.id, config)
- vm.saveDB(sync=True)
+ ssidref = int(sxp.child_value(config, 'ssidref'))
+ log.debug('restoring with ssidref='+str(ssidref))
+ id = xc.domain_create(ssidref = ssidref)
+ vm.setdom(id)
+ try:
+ vm.restore = True
+ vm.construct(config)
+ finally:
+ vm.restore = False
+ vm.exportToDB(save=True, sync=True)
return vm
restore = classmethod(restore)
__exports__ = [
- DBVar('id', ty='str'),
+ DBVar('id', ty='int'),
DBVar('name', ty='str'),
DBVar('uuid', ty='str'),
DBVar('config', ty='sxpr'),
@@ -237,6 +243,7 @@ class XendDomainInfo:
self.start_time = None
self.name = None
self.memory = None
+ self.ssidref = None
self.image = None
self.channel = None
@@ -267,14 +274,17 @@ class XendDomainInfo:
def setDB(self, db):
self.db = db
- def saveDB(self, save=False, sync=False):
+ def saveToDB(self, save=False, sync=False):
self.db.saveDB(save=save, sync=sync)
def exportToDB(self, save=False, sync=False):
if self.channel:
- self.channel.saveToDB(self.db.addChild("channel"))
+ self.channel.saveToDB(self.db.addChild("channel"), save=save)
if self.store_channel:
- self.store_channel.saveToDB(self.db.addChild("store_channel"))
+ self.store_channel.saveToDB(self.db.addChild("store_channel"),
+ save=save)
+ if self.image:
+ self.image.exportToDB(save=save, sync=sync)
self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
def importFromDB(self):
@@ -309,6 +319,7 @@ class XendDomainInfo:
"""
self.info = info
self.memory = self.info['mem_kb'] / 1024
+ self.ssidref = self.info['ssidref']
def state_set(self, state):
self.state_updated.acquire()
@@ -316,7 +327,7 @@ class XendDomainInfo:
self.state = state
self.state_updated.notifyAll()
self.state_updated.release()
- self.saveDB()
+ self.saveToDB()
def state_wait(self, state):
self.state_updated.acquire()
@@ -325,14 +336,15 @@ class XendDomainInfo:
self.state_updated.release()
def __str__(self):
- s = "domain"
+ s = "<domain"
s += " id=" + str(self.id)
s += " name=" + self.name
s += " memory=" + str(self.memory)
+ s += " ssidref=" + str(self.ssidref)
console = self.getConsole()
if console:
s += " console=" + str(console.console_port)
- s += ""
+ s += ">"
return s
__repr__ = __str__
@@ -391,7 +403,8 @@ class XendDomainInfo:
sxpr = ['domain',
['id', self.id],
['name', self.name],
- ['memory', self.memory] ]
+ ['memory', self.memory],
+ ['ssidref', self.ssidref] ]
if self.uuid:
sxpr.append(['uuid', self.uuid])
if self.info:
@@ -422,15 +435,19 @@ class XendDomainInfo:
sxpr.append(self.channel.sxpr())
if self.store_channel:
sxpr.append(self.store_channel.sxpr())
+ if self.store_mfn:
+ sxpr.append(['store_mfn', self.store_mfn])
console = self.getConsole()
if console:
sxpr.append(console.sxpr())
+
if self.restart_count:
sxpr.append(['restart_count', self.restart_count])
if self.restart_state:
sxpr.append(['restart_state', self.restart_state])
if self.restart_time:
sxpr.append(['restart_time', str(self.restart_time)])
+
devs = self.sxpr_devices()
if devs:
sxpr.append(devs)
@@ -500,7 +517,7 @@ class XendDomainInfo:
self.configure_restart()
self.construct_image()
self.configure()
- self.exportToDB()
+ self.exportToDB(save=True)
except Exception, ex:
# Catch errors, cleanup and re-raise.
print 'Domain construction error:', ex
@@ -512,7 +529,7 @@ class XendDomainInfo:
def register_domain(self):
xd = get_component('xen.xend.XendDomain')
xd._add_domain(self)
- self.exportToDB()
+ self.exportToDB(save=True)
def configure_cpus(self, config):
try:
@@ -522,6 +539,7 @@ class XendDomainInfo:
self.memory = int(sxp.child_value(config, 'memory'))
if self.memory is None:
raise VmError('missing memory size')
+ self.ssidref = int(sxp.child_value(config, 'ssidref'))
cpu = sxp.child_value(config, 'cpu')
if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
xc.domain_pincpu(self.id, 0, 1<<int(cpu))
@@ -546,7 +564,7 @@ class XendDomainInfo:
"""
self.create_channel()
self.image.createImage()
- self.image.exportToDB()
+ self.exportToDB()
#if self.store_channel:
# self.db.introduceDomain(self.id,
# self.store_mfn,
@@ -558,7 +576,7 @@ class XendDomainInfo:
if self.dom_get(self.id):
return
self.id = None
- self.saveDB(sync=True)
+ self.saveToDB(sync=True)
try:
# Todo: eventually will have to wait for devices to signal
# destruction before can delete the db.
@@ -614,7 +632,7 @@ class XendDomainInfo:
"""
self.cleanup()
self.destroy_domain()
- self.saveDB()
+ self.saveToDB()
return 0
def is_terminated(self):
@@ -633,7 +651,7 @@ class XendDomainInfo:
def show(self):
"""Print virtual machine info.
"""
- print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory)
+ print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.id, self.name, self.memory, self.ssidref)
print "image:"
sxp.show(self.image)
print "]"
@@ -649,14 +667,13 @@ class XendDomainInfo:
cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
except:
raise VmError('invalid cpu')
- dom = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
+ id = self.image.initDomain(self.id, self.memory, self.ssidref, cpu, self.cpu_weight)
log.debug('init_domain> Created domain=%d name=%s memory=%d',
- dom, self.name, self.memory)
- if not self.restore:
- self.setdom(dom)
+ id, self.name, self.memory)
+ self.setdom(id)
def openChannel(self, key, local, remote):
- """Create a channel to the domain.
+ """Create a control channel to the domain.
If saved info is available recreate the channel.
@param key db key for the saved data (if any)
@@ -670,6 +687,11 @@ class XendDomainInfo:
return chan
def eventChannel(self, key):
+ """Create an event channel to the domain.
+ If saved info is available recreate the channel.
+
+ @param key db key for the saved data (if any)
+ """
db = self.db.addChild(key)
return EventChannel.restoreFromDB(db, 0, self.id)
@@ -701,6 +723,7 @@ class XendDomainInfo:
ctrl.initController(reboot=True)
else:
self.create_configured_devices()
+ self.image.createDeviceModel()
def device_create(self, dev_config):
"""Create a new device.
@@ -832,11 +855,12 @@ class XendDomainInfo:
self.state = STATE_VM_OK
self.shutdown_pending = None
self.restart_check()
+ self.exportToDB()
self.restart_state = STATE_RESTART_BOOTING
if self.bootloader:
self.config = self.bootloader_config()
self.construct(self.config)
- self.saveDB()
+ self.saveToDB()
finally:
self.restart_state = None
@@ -910,23 +934,6 @@ class XendDomainInfo:
backend = blkif.getBackend(0)
backend.connect(recreate=self.recreate)
- def dom_construct(self, dom, config):
- """Construct a vm for an existing domain.
-
- @param dom: domain id
- @param config: domain configuration
- """
- d = dom_get(dom)
- if not d:
- raise VmError("Domain not found: %d" % dom)
- try:
- self.restore = True
- self.setdom(dom)
- self.memory = d['mem_kb']/1024
- self.construct(config)
- finally:
- self.restore = False
-
def configure_fields(self):
"""Process the vm configuration fields using the registered handlers.
"""
@@ -949,6 +956,18 @@ class XendDomainInfo:
msg = messages.packMsg('mem_request_t', { 'target' : target * (1 << 8)} )
self.channel.writeRequest(msg)
+ def vcpu_hotplug(self, vcpu, state):
+ """Disable or enable VCPU in domain.
+ """
+ log.error("Holly Shit! %d %d\n" % (vcpu, state))
+ if self.channel:
+ if int(state) == 0:
+ msg = messages.packMsg('vcpu_hotplug_off_t', { 'vcpu' : vcpu} )
+ else:
+ msg = messages.packMsg('vcpu_hotplug_on_t', { 'vcpu' : vcpu} )
+
+ self.channel.writeRequest(msg)
+
def shutdown(self, reason, key=0):
msgtype = shutdown_messages.get(reason)
if not msgtype:
@@ -1011,6 +1030,7 @@ addImageHandlerClass(VmxImageHandler)
# Ignore the fields we already handle.
add_config_handler('name', vm_field_ignore)
add_config_handler('memory', vm_field_ignore)
+add_config_handler('ssidref', vm_field_ignore)
add_config_handler('cpu', vm_field_ignore)
add_config_handler('cpu_weight', vm_field_ignore)
add_config_handler('console', vm_field_ignore)
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
index e0d70581bf..5abc121e86 100644
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -1,4 +1,4 @@
-import os
+import os, string
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.xend import sxp
@@ -6,6 +6,8 @@ from xen.xend.XendError import VmError
from xen.xend.XendLogging import log
from xen.xend.xenstore import DBVar
+from xen.xend.server import channel
+
class ImageHandler:
"""Abstract base class for image handlers.
@@ -96,8 +98,8 @@ class ImageHandler:
self.db = vm.db.addChild('/image')
self.config = config
- def exportToDB(self, save=False):
- self.db.exportToDB(self, fields=self.__exports__, save=save)
+ def exportToDB(self, save=False, sync=False):
+ self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
def importFromDB(self):
self.db.importFromDB(self, fields=self.__exports__)
@@ -109,7 +111,7 @@ class ImageHandler:
except OSError, ex:
log.warning("error removing bootloader file '%s': %s", f, ex)
- def initDomain(self, dom, memory, cpu, cpu_weight):
+ def initDomain(self, dom, memory, ssidref, cpu, cpu_weight):
"""Initial domain create.
@return domain id
@@ -117,14 +119,14 @@ class ImageHandler:
mem_kb = self.getDomainMemory(memory)
if not self.vm.restore:
- dom = xc.domain_create(dom = dom or 0)
+ dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
# if bootloader, unlink here. But should go after buildDomain() ?
if self.vm.bootloader:
self.unlink(self.kernel)
self.unlink(self.ramdisk)
if dom <= 0:
raise VmError('Creating domain failed: name=%s' % self.vm.name)
- log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom)
+ log.debug("initDomain: cpu=%d mem_kb=%d ssidref=%d dom=%d", cpu, mem_kb, ssidref, dom)
# xc.domain_setuuid(dom, uuid)
xc.domain_setcpuweight(dom, cpu_weight)
xc.domain_setmaxmem(dom, mem_kb)
@@ -303,7 +305,7 @@ class VmxImageHandler(ImageHandler):
+ " -f %s" % device_config
+ self.vncParams()
+ " -d %d" % self.vm.getDomain()
- + " -p %d" % self.device_channel['port1']
+ + " -p %d" % (int(self.device_channel.port1)-1)
+ " -m %s" % self.vm.memory)
def vncParams(self):
diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py
index 255e6157bf..fc8fd4420b 100644
--- a/tools/python/xen/xend/server/SrvDomain.py
+++ b/tools/python/xen/xend/server/SrvDomain.py
@@ -180,6 +180,14 @@ class SrvDomain(SrvDir):
val = fn(req.args, {'dom': self.dom.id})
return val
+ def op_vcpu_hotplug(self, op, req):
+ fn = FormFn(self.xd.domain_vcpu_hotplug,
+ [['dom', 'int'],
+ ['vcpu', 'int'],
+ ['state', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
def render_POST(self, req):
return self.perform(req)
diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py
index d6f6291716..7fcc7c5cf7 100644
--- a/tools/python/xen/xend/server/SrvDomainDir.py
+++ b/tools/python/xen/xend/server/SrvDomainDir.py
@@ -142,6 +142,7 @@ class SrvDomainDir(SrvDir):
% (url, d.name, d.name))
req.write('id=%s' % d.id)
req.write('memory=%d'% d.memory)
+ req.write('ssidref=%d'% d.ssidref)
req.write('</li>')
req.write('</ul>')
diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py
index 75a76e8bda..dac65c426b 100755
--- a/tools/python/xen/xend/server/blkif.py
+++ b/tools/python/xen/xend/server/blkif.py
@@ -50,6 +50,9 @@ class BlkifBackend:
def getId(self):
return self.id
+ def getEvtchn(self):
+ return self.evtchn
+
def closeEvtchn(self):
if self.evtchn:
channel.eventChannelClose(self.evtchn)
@@ -167,6 +170,7 @@ class BlkDev(Dev):
DBVar('params', ty='str'),
DBVar('node', ty='str'),
DBVar('device', ty='long'),
+ DBVar('dev_handle', ty='long'),
DBVar('start_sector', ty='long'),
DBVar('nr_sectors', ty='long'),
]
@@ -192,6 +196,13 @@ class BlkDev(Dev):
self.backendId = 0
self.configure(self.config, recreate=recreate)
+ def exportToDB(self, save=False):
+ Dev.exportToDB(self, save=save)
+ backend = self.getBackend()
+ if backend and backend.evtchn:
+ db = self.db.addChild("evtchn")
+ backend.evtchn.saveToDB(db, save=save)
+
def init(self, recreate=False, reboot=False):
self.frontendDomain = self.getDomain()
self.frontendChannel = self.getChannel()
diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py
index 00f451a7b8..defe76f106 100755
--- a/tools/python/xen/xend/server/channel.py
+++ b/tools/python/xen/xend/server/channel.py
@@ -81,7 +81,7 @@ class EventChannel(dict):
evtchn_close(self.dom1, self.port1)
evtchn_close(self.dom2, self.port2)
- def saveToDB(self, db):
+ def saveToDB(self, db, save=False):
"""Save the event channel to the db so it can be restored later,
using restoreFromDB() on the class.
@@ -91,7 +91,7 @@ class EventChannel(dict):
db['dom2'] = str(self.dom2)
db['port1'] = str(self.port1)
db['port2'] = str(self.port2)
- db.saveDB()
+ db.saveDB(save=save)
def sxpr(self):
return ['event-channel',
@@ -339,7 +339,7 @@ class Channel:
# Make sure the port will deliver all the messages.
self.port.register(TYPE_WILDCARD)
- def saveToDB(self, db):
+ def saveToDB(self, db, save=False):
"""Save the channel ports to the db so the channel can be restored later,
using restoreFromDB() on the factory.
@@ -348,7 +348,7 @@ class Channel:
if self.closed: return
db['local_port'] = str(self.getLocalPort())
db['remote_port'] = str(self.getRemotePort())
- db.saveDB()
+ db.saveDB(save=save)
def getKey(self):
"""Get the channel key.
diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py
index 743ace4aec..e0aa04a37a 100755
--- a/tools/python/xen/xend/server/console.py
+++ b/tools/python/xen/xend/server/console.py
@@ -214,7 +214,8 @@ class ConsoleDev(Dev, protocol.ServerFactory):
self.unix_listener = reactor.listenUNIX(path, self)
if xroot.get_xend_http_server():
interface = xroot.get_console_address()
- self.tcp_listener = reactor.listenTCP(self.console_port, self, interface=interface)
+ self.tcp_listener = reactor.listenTCP(
+ self.console_port, self, interface=interface)
finally:
self.lock.release()
diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py
index 0cea725e3c..84fc738e68 100644
--- a/tools/python/xen/xend/server/messages.py
+++ b/tools/python/xen/xend/server/messages.py
@@ -309,6 +309,24 @@ mem_request_formats = {
msg_formats.update(mem_request_formats)
#============================================================================
+# Domain vcpu hotplug message.
+#============================================================================
+
+CMSG_VCPU_HOTPLUG = 10
+CMSG_VCPU_HOTPLUG_OFF = 0
+CMSG_VCPU_HOTPLUG_ON = 1
+
+vcpu_hotplug_formats = {
+ 'vcpu_hotplug_off_t':
+ (CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_OFF),
+
+ 'vcpu_hotplug_on_t':
+ (CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_ON)
+ }
+
+msg_formats.update(vcpu_hotplug_formats)
+
+#============================================================================
class Msg:
pass
diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py
index 0a49842522..8d89f73605 100755
--- a/tools/python/xen/xend/server/netif.py
+++ b/tools/python/xen/xend/server/netif.py
@@ -66,11 +66,9 @@ class NetDev(Dev):
DBVar('be_mac', ty='mac'),
DBVar('bridge', ty='str'),
DBVar('script', ty='str'),
- #DBVar('ipaddr'),
DBVar('credit', ty='int'),
DBVar('period', ty='int'),
DBVar('vifname', ty='str'),
- DBVar('evtchn'), #todo: export fields (renamed)
]
def __init__(self, controller, id, config, recreate=False):
@@ -89,9 +87,16 @@ class NetDev(Dev):
self.bridge = None
self.script = None
self.ipaddr = None
+ self.mtu = None
self.vifname = None
self.configure(self.config, recreate=recreate)
+ def exportToDB(self, save=False):
+ Dev.exportToDB(self, save=save)
+ if self.evtchn:
+ db = self.db.addChild("evtchn")
+ self.evtchn.saveToDB(db, save=save)
+
def init(self, recreate=False, reboot=False):
self.destroyed = False
self.status = NETIF_INTERFACE_STATUS_DISCONNECTED
@@ -128,6 +133,15 @@ class NetDev(Dev):
val = None
return val
+ def _get_config_mtu(self, config):
+ mtu = sxp.child_value(config, 'mtu')
+ if not mtu: return None
+ try:
+ mtu = int(mtu)
+ except:
+ raise XendError("invalid mtu: %s" & mtu)
+ return mtu
+
def configure(self, config, change=False, recreate=False):
if change:
return self.reconfigure(config)
@@ -152,6 +166,7 @@ class NetDev(Dev):
self.bridge = sxp.child_value(config, 'bridge')
self.script = sxp.child_value(config, 'script')
self.ipaddr = self._get_config_ipaddr(config) or []
+ self.mtu = self._get_config_mtu(config)
self._config_credit_limit(config)
try:
@@ -183,6 +198,7 @@ class NetDev(Dev):
bridge = sxp.child_value(config, 'bridge')
script = sxp.child_value(config, 'script')
ipaddr = self._get_config_ipaddr(config)
+ mtu = self._get_config_mtu(config)
xd = get_component('xen.xend.XendDomain')
backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id
@@ -199,6 +215,8 @@ class NetDev(Dev):
changes['script'] = script
if (ipaddr is not None) and (ipaddr != self.ipaddr):
changes['ipaddr'] = ipaddr
+ if (mtu is not None) and (mtu != self.mtu):
+ changes['mtu'] = mtu
if changes:
self.vifctl("down")
diff --git a/tools/python/xen/xend/xenstore/xsnode.py b/tools/python/xen/xend/xenstore/xsnode.py
index ae770219ab..94b264c3cf 100644
--- a/tools/python/xen/xend/xenstore/xsnode.py
+++ b/tools/python/xen/xend/xenstore/xsnode.py
@@ -2,7 +2,9 @@ import errno
import os
import os.path
import select
+import socket
import sys
+import threading
import time
from xen.lowlevel import xs
@@ -12,18 +14,26 @@ from xen.xend.PrettyPrint import prettyprint
SELECT_TIMEOUT = 2.0
def getEventPath(event):
- return os.path.join("/_event", event)
+ if event and event.startswith("/"):
+ event = event[1:]
+ return os.path.join("/event", event)
def getEventIdPath(event):
- return os.path.join(eventPath(event), "@eid")
+ return os.path.join(getEventPath(event), "@eid")
class Subscription:
- def __init__(self, event, fn, id):
- self.event = event
+ def __init__(self, path, fn, sid):
+ self.path = path
self.watcher = None
self.fn = fn
- self.id = id
+ self.sid = sid
+
+ def getPath(self):
+ return self.path
+
+ def getSid(self):
+ return self.sid
def watch(self, watcher):
self.watcher = watcher
@@ -34,56 +44,61 @@ class Subscription:
if watcher:
self.watcher = None
watcher.delSubs(self)
+ return watcher
- def notify(self, event):
+ def notify(self, token, path, val):
try:
- self.fn(event, id)
- except SystemExitException:
+ self.fn(self, token, path, val)
+ except SystemExit:
raise
- except:
+ except Exception, ex:
pass
class Watcher:
- def __init__(self, store, event):
- self.path = getEventPath(event)
- self.eidPath = getEventIdPath(event)
+ def __init__(self, store, path):
+ self.path = path
store.mkdirs(self.path)
- if not store.exists(self.eidPath):
- store.writeInt(self.eidPath, 0)
self.xs = None
- self.subs = []
+ self.subscriptions = []
- def __getattr__(self, k, v):
- if k == "fileno":
- if self.xs:
- return self.xs.fileno
- else:
- return -1
+ def fileno(self):
+ if self.xs:
+ return self.xs.fileno()
else:
- return self.__dict__.get(k, v)
+ return -1
+
+ def getPath(self):
+ return self.path
+
+ def getToken(self):
+ return self.path
def addSubs(self, subs):
- self.subs.append(subs)
+ self.subscriptions.append(subs)
self.watch()
def delSubs(self, subs):
- self.subs.remove(subs)
- if len(self.subs) == 0:
+ self.subscriptions.remove(subs)
+ if len(self.subscriptions) == 0:
self.unwatch()
- def getEvent(self):
- return self.event
-
def watch(self):
if self.xs: return
self.xs = xs.open()
- self.xs.watch(path)
+ self.xs.watch(path=self.getPath(), token=self.getToken())
def unwatch(self):
if self.xs:
- self.xs.unwatch(self.path)
- self.xs.close()
+## Possibly crashes xenstored.
+## try:
+## self.xs.unwatch(path=self.getPath(), token=self.getToken())
+## except Exception, ex:
+## print 'Watcher>unwatch>', ex
+ try:
+ self.xs.close()
+ except Exception, ex:
+ pass
self.xs = None
def watching(self):
@@ -91,23 +106,47 @@ class Watcher:
def getNotification(self):
p = self.xs.read_watch()
- self.xs.acknowledge_watch()
- eid = self.xs.readInt(self.eidPath)
+ self.xs.acknowledge_watch(p[1])
return p
- def notify(self, subs):
- p = self.getNotification()
- for s in subs:
- s.notify(p)
-
+ def notify(self):
+ try:
+ (path, token) = self.getNotification()
+ if path.endswith("@eid"):
+ pass
+ else:
+ val = self.xs.read(path)
+ for subs in self.subscriptions:
+ subs.notify(token, path, val)
+ except SystemExit:
+ raise
+ except Exception, ex:
+ raise
+
+class EventWatcher(Watcher):
+
+ def __init__(self, store, path, event):
+ Watcher.__init__(self, store, path)
+ self.event = event
+ self.eidPath = getEventIdPath(event)
+ if not store.exists(self.eidPath):
+ store.write(self.eidPath, str(0))
+
+ def getEvent(self):
+ return self.event
+
+ def getToken(self):
+ return self.event
+
class XenStore:
+ xs = None
+ watchThread = None
+ subscription_id = 1
+
def __init__(self):
- self.xs = None
- #self.xs = xs.open()
- self.subscription = {}
- self.subscription_id = 0
- self.events = {}
+ self.subscriptions = {}
+ self.watchers = {}
self.write("/", "")
def getxs(self):
@@ -118,9 +157,11 @@ class XenStore:
self.xs = xs.open()
ex = None
break
+ except SystemExit:
+ raise
except Exception, ex:
- print >>stderr, "Exception connecting to xsdaemon:", ex
- print >>stderr, "Trying again..."
+ print >>sys.stderr, "Exception connecting to xenstored:", ex
+ print >>sys.stderr, "Trying again..."
time.sleep(1)
else:
raise ex
@@ -214,73 +255,91 @@ class XenStore:
def write(self, path, data, create=True, excl=False):
self.mkdirs(path)
- self.getxs().write(path, data, create=create, excl=excl)
+ try:
+ self.getxs().write(path, data, create=create, excl=excl)
+ except Exception, ex:
+ raise
def begin(self, path):
- self.getxs().begin_transaction(path)
+ self.getxs().transaction_start(path)
def commit(self, abandon=False):
- self.getxs().end_transaction(abort=abandon)
+ self.getxs().transaction_end(abort=abandon)
+
+ def watch(self, path, fn):
+ watcher = self.watchers.get(path)
+ if not watcher:
+ watcher = self.addWatcher(Watcher(self, path))
+ return self.addSubscription(watcher, fn)
+
+ def unwatch(self, sid):
+ s = self.subscriptions.get(sid)
+ if not s: return
+ del self.subscriptions[s.sid]
+ watcher = s.unwatch()
+ if watcher and not watcher.watching():
+ try:
+ del self.watchers[watcher.getPath()]
+ except:
+ pass
def subscribe(self, event, fn):
- watcher = self.watchEvent(event)
- self.subscription_id += 1
- subs = Subscription(event, fn, self.subscription_id)
- self.subscription[subs.id] = subs
- subs.watch(watcher)
- return subs.id
+ path = getEventPath(event)
+ watcher = self.watchers.get(path)
+ if not watcher:
+ watcher = self.addWatcher(EventWatcher(self, path, event))
+ return self.addSubscription(watcher, fn)
- def unsubscribe(self, sid):
- s = self.subscription.get(sid)
- if not s: return
- del self.subscription[s.id]
- s.unwatch()
- unwatchEvent(s.event)
+ unsubscribe = unwatch
def sendEvent(self, event, data):
eventPath = getEventPath(event)
eidPath = getEventIdPath(event)
try:
- self.begin(eventPath)
+ #self.begin(eventPath)
self.mkdirs(eventPath)
+ eid = 1
if self.exists(eidPath):
- eid = self.readInt(eidPath)
- eid += 1
- else:
- eid = 1
- self.writeInt(eidPath, eid)
+ try:
+ eid = int(self.read(eidPath))
+ eid += 1
+ except Exception, ex:
+ pass
+ self.write(eidPath, str(eid))
self.write(os.path.join(eventPath, str(eid)), data)
finally:
- self.commit()
+ #self.commit()
+ pass
- def watchEvent(self, event):
- if event in self.events:
- return
- watcher = Watcher(event)
- self.watchers[watcher.getEvent()] = watcher
+ def addWatcher(self, watcher):
+ self.watchers[watcher.getPath()] = watcher
self.watchStart()
return watcher
- def unwatchEvent(self, event):
- watcher = self.watchers.get(event)
- if not watcher:
- return
- if not watcher.watching():
- del self.watchers[event]
+ def addSubscription(self, watcher, fn):
+ self.subscription_id += 1
+ subs = Subscription(watcher.getPath(), fn, self.subscription_id)
+ self.subscriptions[subs.sid] = subs
+ subs.watch(watcher)
+ return subs.sid
def watchStart(self):
if self.watchThread: return
-
+ self.watchThread = threading.Thread(name="Watcher",
+ target=self.watchMain)
+ self.watchThread.setDaemon(True)
+ self.watchThread.start()
+
def watchMain(self):
try:
while True:
if self.watchThread is None: return
- if not self.events:
+ if not self.watchers:
return
rd = self.watchers.values()
try:
- (rd, wr, er) = select.select(rd, [], [], SELECT_TIMEOUT)
- for watcher in rd:
+ (srd, swr, ser) = select.select(rd, [], [], SELECT_TIMEOUT)
+ for watcher in srd:
watcher.notify()
except socket.error, ex:
if ex.args[0] in (EAGAIN, EINTR):
@@ -304,6 +363,15 @@ def getXenStore():
xenstore = XenStore()
return xenstore
+def sendEvent(event, val):
+ getXenStore.sendEvent(event, val)
+
+def subscribe(event, fn):
+ return getXenStore().subscribe(event, fn)
+
+def unsubscribe(sid):
+ getXenStore().unsubscribe(sid)
+
class XenNode:
def __init__(self, path="/", create=True):
@@ -315,6 +383,9 @@ class XenNode:
else:
raise ValueError("path does not exist: '%s'" % path)
+ def getStore(self):
+ return self.store
+
def relPath(self, path=""):
if not path:
return self.path
@@ -344,9 +415,7 @@ class XenNode:
return None
def setData(self, data, path=""):
- path = self.relPath(path)
- #print 'XenNode>setData>', 'path=', path, 'data=', data
- return self.store.write(path, data)
+ return self.store.write(self.relPath(path), data)
def getLock(self):
return None
@@ -376,6 +445,24 @@ class XenNode:
def releaseDomain(self, dom):
self.store.releaseDomain(dom)
+ def watch(self, fn, path=""):
+ """Watch a path for changes. The path is relative
+ to the node and defaults to the node itself.
+ """
+ return self.store.watch(self.relPath(path), fn)
+
+ def unwatch(self, sid):
+ return self.store.unwatch(sid)
+
+ def subscribe(self, event, fn):
+ return self.store.subscribe(event, fn)
+
+ def unsubscribe(self, sid):
+ self.store.unsubscribe(sid)
+
+ def sendEvent(self, event, data):
+ return self.store.sendEvent(event, data)
+
def __repr__(self):
return "<XenNode %s>" % self.path
diff --git a/tools/python/xen/xend/xenstore/xsobj.py b/tools/python/xen/xend/xenstore/xsobj.py
index b1c9a4f1d1..e16bf43e83 100644
--- a/tools/python/xen/xend/xenstore/xsobj.py
+++ b/tools/python/xen/xend/xenstore/xsobj.py
@@ -1,6 +1,8 @@
import string
import types
+from xen.xend.XendLogging import log
+
from xen.xend import sxp
from xsnode import XenNode
from xen.util.mac import macToString, macFromString
@@ -14,14 +16,19 @@ def hasAttr(obj, attr):
return hasattr(obj, attr)
def getAttr(obj, attr):
- if isinstance(obj, dict):
- return dict.get(attr)
- else:
- return getattr(obj, attr, None)
+ try:
+ if isinstance(obj, dict):
+ return obj.get(attr)
+ else:
+ return getattr(obj, attr, None)
+ except AttributeError:
+ return None
+ except LookupError:
+ return None
def setAttr(obj, attr, val):
if isinstance(obj, dict):
- dict[attr] = val
+ obj[attr] = val
else:
setattr(obj, attr, val)
@@ -48,15 +55,15 @@ class DBConverter:
getConverter = classmethod(getConverter)
- def convertToDB(cls, val, ty=None):
- return cls.getConverter(ty).toDB(val)
+ def exportTypeToDB(cls, db, path, val, ty=None):
+ return cls.getConverter(ty).exportToDB(db, path, val)
- convertToDB = classmethod(convertToDB)
+ exportTypeToDB = classmethod(exportTypeToDB)
- def convertFromDB(cls, val, ty=None):
- return cls.getConverter(ty).fromDB(val)
+ def importTypeFromDB(cls, db, path, ty=None):
+ return cls.getConverter(ty).importFromDB(db, path)
- convertFromDB = classmethod(convertFromDB)
+ importTypeFromDB = classmethod(importTypeFromDB)
# Must define in subclass.
name = None
@@ -69,6 +76,26 @@ class DBConverter:
raise ValueError("invalid converter name: '%s'" % self.name)
self.converters[self.name] = self
+ def exportToDB(self, db, path, val):
+ if val is None:
+ return
+ try:
+ data = self.toDB(val)
+ except Exception, ex:
+ raise
+ setattr(db, path, data)
+
+ def importFromDB(self, db, path):
+ data = getAttr(db, path)
+ if data is None:
+ val = None
+ else:
+ try:
+ val = self.fromDB(data.getData())
+ except Exception, ex:
+ raise
+ return val
+
def toDB(self, val):
raise NotImplementedError()
@@ -178,10 +205,12 @@ class DBVar:
self.attr = varpath[-1]
def exportToDB(self, db, obj):
- self.setDB(db, self.getObj(obj))
+ val = self.getObj(obj)
+ DBConverter.exportTypeToDB(db, self.path, val, ty=self.ty)
def importFromDB(self, db, obj):
- self.setObj(obj, self.getDB(db))
+ val = DBConverter.importTypeFromDB(db, self.path, ty=self.ty)
+ self.setObj(obj, val)
def getObj(self, obj):
o = obj
@@ -200,23 +229,6 @@ class DBVar:
return
setAttr(o, self.attr, val)
- def getDB(self, db):
- try:
- data = getattr(db, self.path)
- except AttributeError:
- return None
- return DBConverter.convertFromDB(data, ty=self.ty)
-
- def setDB(self, db, val):
- # Don't set in db if val is None.
- #print 'DBVar>setDB>', self.path, 'val=', val
- if val is None:
- return
- data = DBConverter.convertToDB(val, ty=self.ty)
- #print 'DBVar>setDB>', self.path, 'data=', data
- setattr(db, self.path, data)
-
-
class DBMap(dict):
"""A persistent map. Extends dict with persistence.
Set and get values using the usual map syntax:
@@ -314,6 +326,21 @@ class DBMap(dict):
traceback.print_exc()
print 'DBMap>releaseDomain>', ex
pass # todo: don't ignore
+
+ def watch(self, fn, path=""):
+ return self.__db__.watch(fn, path=path)
+
+ def unwatch(self, sid):
+ return self.__db__.unwatch(sid)
+
+ def subscribe(self, event, fn):
+ return self.__db__.subscribe(event, fn)
+
+ def unsubscribe(self, sid):
+ return self.__db__.unsubscribe(sid)
+
+ def sendEvent(self, event, val):
+ return self.__db__.sendEvent(event, val)
def transactionBegin(self):
# Begin a transaction.
@@ -328,12 +355,6 @@ class DBMap(dict):
# We have changed values, what do we do?
pass
- def watch(self, fn):
- pass
-
- def unwatch(self, watch):
- pass
-
def checkName(self, k):
if k == "":
raise ValueError("invalid key, empty string")
@@ -456,6 +477,9 @@ class DBMap(dict):
n = n._addChild(x)
return n
+ def getDB(self):
+ return self.__db__
+
def setDB(self, db):
if (db is not None) and not isinstance(db, XenNode):
raise ValueError("invalid db")
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 23001cc458..d2219f9668 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -120,6 +120,10 @@ gopts.var('memory', val='MEMORY',
fn=set_int, default=128,
use="Domain memory in MB.")
+gopts.var('ssidref', val='SSIDREF',
+ fn=set_u32, default=0xffffffff,
+ use="Security Identifier.")
+
gopts.var('maxmem', val='MEMORY',
fn=set_int, default=None,
use="Maximum domain memory in MB.")
@@ -405,7 +409,8 @@ def make_config(opts, vals):
config = ['vm',
['name', vals.name ],
- ['memory', vals.memory ]]
+ ['memory', vals.memory ],
+ ['ssidref', vals.ssidref ]]
if vals.maxmem:
config.append(['maxmem', vals.maxmem])
if vals.cpu is not None:
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index d02a190ac4..bcc3ded274 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -399,14 +399,19 @@ class ProgList(Prog):
d['port'] = sxp.child_value(console, 'console_port')
else:
d['port'] = ''
- print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s"
- % d)
+ if ((int(sxp.child_value(info, 'ssidref', '-1'))) != -1):
+ d['ssidref1'] = int(sxp.child_value(info, 'ssidref', '-1')) & 0xffff
+ d['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '-1')) >> 16) & 0xffff
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s s:%(ssidref2)02x/p:%(ssidref1)02x" % d)
+ else:
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s" % d)
def show_vcpus(self, doms):
print 'Name Id VCPU CPU CPUMAP'
for dom in doms:
info = server.xend_domain(dom)
- vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '?').replace('-','')
+ # XXX this is quite broken for cpu's > 9
+ vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '?').replace('-1','#')
cpumap = sxp.child_value(info, 'cpumap', [])
mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
count = 0
@@ -415,7 +420,10 @@ class ProgList(Prog):
d['name'] = sxp.child_value(info, 'name', '??')
d['dom'] = int(sxp.child_value(info, 'id', '-1'))
d['vcpu'] = int(count)
- d['cpu'] = int(cpu)
+ if cpu == "#":
+ d['cpu'] = int("-1")
+ else:
+ d['cpu'] = int(cpu)
d['cpumap'] = int(cpumap[count])&mask
count = count + 1
print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" % d)
@@ -568,6 +576,35 @@ MEMORY_TARGET megabytes"""
xm.prog(ProgBalloon)
+class ProgVcpuhotplug(Prog):
+ group = 'domain'
+ name = 'vcpu-hotplug'
+ info = """Enable or disable a VCPU in a domain."""
+
+ def help(self, args):
+ print args[0], "DOM VCPU [0|1]"
+ print """\nRequest virtual processor VCPU to be disabled or enabled in
+domain DOM"""
+
+ def main(self, args):
+ if len(args) != 4: self.err("%s: Invalid arguments(s)" % args[0])
+ name = args[1]
+ vcpu = int(args[2])
+ state = int(args[3])
+ dom = server.xend_domain(name)
+ id = sxp.child_value(dom, 'id')
+ vcpu_to_cpu = sxp.child_value(dom, 'vcpu_to_cpu', '-1')
+ # only send state change if states differ
+ try:
+ # (down going up) or (up going down)
+ if (vcpu_to_cpu[vcpu] == "-1" and state == 1) or \
+ (vcpu_to_cpu[vcpu] != "-1" and state == 0):
+ server.xend_domain_vcpu_hotplug(id, vcpu, state)
+ except IndexError:
+ print "Invalid VCPU(%d)"%(vcpu)
+
+xm.prog(ProgVcpuhotplug)
+
class ProgDomid(Prog):
group = 'domain'
name = 'domid'
diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py
index f92c82dfe6..30900450dc 100644
--- a/tools/python/xen/xm/opts.py
+++ b/tools/python/xen/xm/opts.py
@@ -451,6 +451,13 @@ def set_bool(opt, k, v):
else:
opt.opts.err('Invalid value:' +v)
+def set_u32(opt, k, v):
+ """Set an option to an u32 value."""
+ try:
+ v = u32(v)
+ except:
+ opt.opts.err('Invalid value: ' + str(v))
+ opt.set(v)
def set_value(opt, k, v):
"""Set an option to a value."""
diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 408078efba..9bd744e951 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -20,17 +20,15 @@ BASECFLAGS+= -I$(XEN_ROOT)/xen/include/public
BASECFLAGS+= -I.
CFLAGS += $(BASECFLAGS)
-ifeq ($(XEN_TARGET_ARCH),x86_64)
CFLAGS += -fPIC
-endif
LDFLAGS=$(PROFILE) -L$(XEN_LIBXC)
TESTDIR=`pwd`/testsuite/tmp
TESTFLAGS=-DTESTING
TESTENV=XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR)
-all: xen xenstored libxenstore.a
+all: xen xenstored libxenstore.a libxenstore-pic.a
-testcode: xen xs_test xenstored_test xs_random
+testcode: xen xs_test xenstored_test xs_random xs_dom0_test
xen:
ln -sf $(XEN_ROOT)/xen/include/public $@
@@ -44,8 +42,9 @@ xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_te
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_watch_stress: xs_watch_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
-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: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
+xs_test.o xs_stress.o xs_watch_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: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
xenstored_%_test.o: xenstored_%.c
$(COMPILE.c) -o $@ $<
@@ -56,10 +55,19 @@ xs_test_lib.o: xs.c
talloc_test.o: talloc.c
$(COMPILE.c) -o $@ $<
-libxenstore.a: libxenstore.a(xs.o) libxenstore.a(xs_lib.o)
+LIB_OBJS := xs.o xs_lib.o
+
+LIB_OBJS_A := $(patsubst %.o,libxenstore.a(%.o),$(LIB_OBJS))
+LIB_OBJS_PIC := $(patsubst %.o,libxenstore-pic.a(%.opic),$(LIB_OBJS))
+
+libxenstore.a: $(LIB_OBJS_A)
+
+libxenstore-pic.a: $(LIB_OBJS_PIC)
clean: testsuite-clean
- rm -f *.o *.a xs_test xenstored xenstored_test xs_random xs_stress xen
+ rm -f *.o *.opic *.a
+ rm -f xen xenstored xs_random xs_stress xs_watch_stress
+ rm -f xs_test xenstored_test xs_dom0_test
-$(RM) $(PROG_DEP)
check: testsuite-run randomcheck stresstest
@@ -78,9 +86,14 @@ randomcheck: xs_random xenstored_test
$(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED)
$(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
-stresstest: xs_stress xenstored_test
+stresstest: xs_stress xs_watch_stress xenstored_test
+ rm -rf $(TESTDIR)/store
+ export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret
rm -rf $(TESTDIR)/store
- export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 10000; ret=$$?; kill $$PID; exit $$ret
+ export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret
+
+xs_dom0_test: xs_dom0_test.o utils.o
+ $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@
TAGS:
etags `find . -name '*.[ch]'`
@@ -88,7 +101,7 @@ TAGS:
tarball: clean
cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/
-install: xenstored libxenstore.a
+install: xenstored libxenstore.a libxenstore-pic.a
$(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored
$(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored
$(INSTALL_DIR) -p $(DESTDIR)/usr/sbin
@@ -96,7 +109,11 @@ install: xenstored libxenstore.a
$(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin
$(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)
$(INSTALL_DATA) libxenstore.a $(DESTDIR)/usr/$(LIBDIR)
+ $(INSTALL_DATA) libxenstore-pic.a $(DESTDIR)/usr/$(LIBDIR)
$(INSTALL_DATA) xs.h $(DESTDIR)/usr/include
$(INSTALL_DATA) xs_lib.h $(DESTDIR)/usr/include
-include $(PROG_DEP)
+
+# never delete any intermediate files.
+.SECONDARY:
diff --git a/tools/xenstore/testsuite/07watch.sh b/tools/xenstore/testsuite/07watch.sh
index bedce6ad5b..e6156ea7f8 100644
--- a/tools/xenstore/testsuite/07watch.sh
+++ b/tools/xenstore/testsuite/07watch.sh
@@ -3,30 +3,118 @@
# Watch something, write to it, check watch has fired.
[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e '1 watch /test 100\n2 write /test create contents2\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/test" ]
+[ "`echo -e '1 watch /test token 100
+2 write /test create contents2
+1 waitwatch
+1 ackwatch token' | ./xs_test 2>&1`" = "1:/test:token" ]
# Check that reads don't set it off.
-[ "`echo -e '1 watch /test 100\n2 read /test\n1 waitwatch' | ./xs_test 2>&1`" = "2:contents2
+[ "`echo -e '1 watch /test token 100
+2 read /test
+1 waitwatch' | ./xs_test 2>&1`" = "2:contents2
1:waitwatch timeout" ]
-# mkdir, setperm and rm should (also /tests watching dirs)
+# mkdir, setperm and rm should (also tests watching dirs)
[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e '1 watch /dir 100\n2 mkdir /dir/newdir\n1 waitwatch\n1 ackwatch\n2 setperm /dir/newdir 0 READ\n1 waitwatch\n1 ackwatch\n2 rm /dir/newdir\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/newdir
-1:/dir/newdir
-1:/dir/newdir" ]
+[ "`echo -e '1 watch /dir token 100
+2 mkdir /dir/newdir
+1 waitwatch
+1 ackwatch token
+2 setperm /dir/newdir 0 READ
+1 waitwatch
+1 ackwatch token
+2 rm /dir/newdir
+1 waitwatch
+1 ackwatch token' | ./xs_test 2>&1`" = "1:/dir/newdir:token
+1:/dir/newdir:token
+1:/dir/newdir:token" ]
# ignore watches while doing commands, should work.
-[ "`echo -e 'watch /dir 100\nwrite /dir/test create contents\nread /dir/test\nwaitwatch\nackwatch' | ./xs_test 2>&1`" = "contents
-/dir/test" ]
+[ "`echo -e 'watch /dir token 100
+write /dir/test create contents
+read /dir/test
+waitwatch
+ackwatch token' | ./xs_test 2>&1`" = "contents
+/dir/test:token" ]
# watch priority /test.
-[ "`echo -e '1 watch /dir 1\n3 watch /dir 3\n2 watch /dir 2\nwrite /dir/test create contents\n3 waitwatch\n3 ackwatch\n2 waitwatch\n2 ackwatch\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "3:/dir/test
-2:/dir/test
-1:/dir/test" ]
+[ "`echo -e '1 watch /dir token1 1
+3 watch /dir token3 3
+2 watch /dir token2 2
+write /dir/test create contents
+3 waitwatch
+3 ackwatch token3
+2 waitwatch
+2 ackwatch token2
+1 waitwatch
+1 ackwatch token1' | ./xs_test 2>&1`" = "3:/dir/test:token3
+2:/dir/test:token2
+1:/dir/test:token1" ]
# If one dies (without acking), the other should still get ack.
-[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 waitwatch\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "2:/dir/test
-1:/dir/test" ]
+[ "`echo -e '1 watch /dir token1 0
+2 watch /dir token2 1
+write /dir/test create contents
+2 waitwatch
+2 close
+1 waitwatch
+1 ackwatch token1' | ./xs_test 2>&1`" = "2:/dir/test:token2
+1:/dir/test:token1" ]
# If one dies (without reading at all), the other should still get ack.
-[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/test" ]
+[ "`echo -e '1 watch /dir token1 0
+2 watch /dir token2 1
+write /dir/test create contents
+2 close
+1 waitwatch
+1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
+
+# unwatch
+[ "`echo -e '1 watch /dir token1 0
+1 unwatch /dir token1
+1 watch /dir token2 0
+2 write /dir/test2 create contents
+1 waitwatch
+1 unwatch /dir token2' | ./xs_test 2>&1`" = "1:/dir/test2:token2" ]
+
+# unwatch while watch pending.
+[ "`echo -e '1 watch /dir token1 0
+2 watch /dir token2 1
+write /dir/test create contents
+2 unwatch /dir token2
+1 waitwatch
+1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
+
+# check we only get notified once.
+[ "`echo -e '1 watch /test token 100
+2 write /test create contents2
+1 waitwatch
+1 ackwatch token
+1 waitwatch' | ./xs_test 2>&1`" = "1:/test:token
+1:waitwatch timeout" ]
+
+# watches are queued in order.
+[ "`echo -e '1 watch / token 100
+2 write /test1 create contents
+2 write /test2 create contents
+2 write /test3 create contents
+1 waitwatch
+1 ackwatch token
+1 waitwatch
+1 ackwatch token
+1 waitwatch
+1 ackwatch token' | ./xs_test 2>&1`" = "1:/test1:token
+1:/test2:token
+1:/test3:token" ]
+
+# Creation of subpaths should be covered correctly.
+[ "`echo -e '1 watch / token 100
+2 write /test/subnode create contents2
+2 write /test/subnode/subnode create contents2
+1 waitwatch
+1 ackwatch token
+1 waitwatch
+1 ackwatch token
+1 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
+1:/test/subnode/subnode:token
+1:waitwatch timeout" ]
diff --git a/tools/xenstore/testsuite/10domain-homedir.sh b/tools/xenstore/testsuite/10domain-homedir.sh
new file mode 100644
index 0000000000..a3587d2a5e
--- /dev/null
+++ b/tools/xenstore/testsuite/10domain-homedir.sh
@@ -0,0 +1,12 @@
+#! /bin/sh
+# Test domain "implicit" paths.
+
+# Create a domain, write an entry using implicit path, read using implicit
+[ "`echo -e 'mkdir /home
+introduce 1 100 7 /home
+1 write entry1 create contents
+read /home/entry1
+dir /home' | ./xs_test 2>&1`" = "handle is 1
+contents
+entry1" ]
+
diff --git a/tools/xenstore/testsuite/11domain-watch.sh b/tools/xenstore/testsuite/11domain-watch.sh
new file mode 100644
index 0000000000..f42fb5f8c6
--- /dev/null
+++ b/tools/xenstore/testsuite/11domain-watch.sh
@@ -0,0 +1,51 @@
+#! /bin/sh
+# Test watching from a domain.
+
+# Watch something, write to it, check watch has fired.
+[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ]
+[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
+
+[ "`echo -e 'introduce 1 100 7 /my/home
+1 watch /test token 100
+write /test create contents2
+1 waitwatch
+1 ackwatch token
+1 unwatch /test token
+release 1' | ./xs_test 2>&1`" = "handle is 1
+1:/test:token" ]
+
+# ignore watches while doing commands, should work.
+[ "`echo -e 'introduce 1 100 7 /my/home
+1 watch /dir token 100
+1 write /dir/test create contents
+1 read /dir/test
+1 waitwatch
+1 ackwatch token
+release 1' | ./xs_test 2>&1`" = "handle is 1
+1:contents
+1:/dir/test:token" ]
+
+# unwatch
+[ "`echo -e 'introduce 1 100 7 /my/home
+1 watch /dir token1 0
+1 unwatch /dir token1
+1 watch /dir token2 0
+2 write /dir/test2 create contents
+1 waitwatch
+1 unwatch /dir token2
+release 1' | ./xs_test 2>&1`" = "handle is 1
+1:/dir/test2:token2" ]
+
+# unwatch while watch pending.
+[ "`echo -e 'introduce 1 100 7 /my/home
+introduce 2 101 8 /my/secondhome
+1 watch /dir token1 0
+2 watch /dir token2 1
+write /dir/test create contents
+2 unwatch /dir token2
+1 waitwatch
+1 ackwatch token1
+release 1
+release 2' | ./xs_test 2>&1`" = "handle is 1
+handle is 2
+1:/dir/test:token1" ]
diff --git a/tools/xenstore/testsuite/12readonly.sh b/tools/xenstore/testsuite/12readonly.sh
new file mode 100644
index 0000000000..5e7501a2e6
--- /dev/null
+++ b/tools/xenstore/testsuite/12readonly.sh
@@ -0,0 +1,40 @@
+#! /bin/sh
+# Test that read only connection can't alter store.
+
+[ "`echo 'write /test create contents' | ./xs_test 2>&1`" = "" ]
+
+# These are all valid.
+[ "`echo 'dir /
+read /test
+getperm /test
+watch /test token 0
+unwatch /test token
+start /
+commit
+start /
+abort' | ./xs_test --readonly 2>&1`" = "test
+contents
+0 NONE" ]
+
+# These don't work
+[ "`echo 'write /test2 create contents' | ./xs_test --readonly 2>&1`" = "FATAL: write: Read-only file system" ]
+[ "`echo 'write /test create contents' | ./xs_test --readonly 2>&1`" = "FATAL: write: Read-only file system" ]
+[ "`echo 'setperm /test 100 NONE' | ./xs_test --readonly 2>&1`" = "FATAL: setperm: Read-only file system" ]
+[ "`echo 'setperm /test 100 NONE' | ./xs_test --readonly 2>&1`" = "FATAL: setperm: Read-only file system" ]
+[ "`echo 'shutdown' | ./xs_test --readonly 2>&1`" = "FATAL: shutdown: Read-only file system" ]
+[ "`echo 'introduce 1 100 7 /home' | ./xs_test --readonly 2>&1`" = "FATAL: introduce: Read-only file system" ]
+
+# Check that watches work like normal.
+set -m
+[ "`echo 'watch / token 0
+waitwatch
+ackwatch token' | ./xs_test --readonly 2>&1`" = "/test:token" ] &
+
+[ "`echo 'write /test create contents' | ./xs_test 2>&1`" = "" ]
+if wait; then :; else
+ echo Readonly wait test failed: $?
+ exit 1
+fi
+
+
+
diff --git a/tools/xenstore/testsuite/test.sh b/tools/xenstore/testsuite/test.sh
index 5718e84a15..3f0055842d 100755
--- a/tools/xenstore/testsuite/test.sh
+++ b/tools/xenstore/testsuite/test.sh
@@ -9,7 +9,7 @@ run_test()
mkdir $XENSTORED_ROOTDIR
# Weird failures with this.
if type valgrind >/dev/null 2>&1; then
- valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid &
+ valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid 2> testsuite/tmp/xenstored_errors &
while [ ! -s /tmp/pid ]; do sleep 0; done
PID=`cat /tmp/pid`
rm /tmp/pid
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1df00f37b4..9f7ff2e1ce 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -122,6 +122,33 @@ void __attribute__((noreturn)) corrupt(struct connection *conn,
_exit(2);
}
+static char *sockmsg_string(enum xsd_sockmsg_type type)
+{
+ switch (type) {
+ case XS_DEBUG: return "DEBUG";
+ case XS_SHUTDOWN: return "SHUTDOWN";
+ case XS_DIRECTORY: return "DIRECTORY";
+ case XS_READ: return "READ";
+ case XS_GET_PERMS: return "GET_PERMS";
+ case XS_WATCH: return "WATCH";
+ case XS_WATCH_ACK: return "WATCH_ACK";
+ case XS_UNWATCH: return "UNWATCH";
+ case XS_TRANSACTION_START: return "TRANSACTION_START";
+ case XS_TRANSACTION_END: return "TRANSACTION_END";
+ case XS_INTRODUCE: return "INTRODUCE";
+ case XS_RELEASE: return "RELEASE";
+ case XS_GETDOMAINPATH: return "GETDOMAINPATH";
+ case XS_WRITE: return "WRITE";
+ case XS_MKDIR: return "MKDIR";
+ case XS_RM: return "RM";
+ case XS_SET_PERMS: return "SET_PERMS";
+ case XS_WATCH_EVENT: return "WATCH_EVENT";
+ case XS_ERROR: return "ERROR";
+ default:
+ return "**UNKNOWN**";
+ }
+}
+
static bool write_message(struct connection *conn)
{
int ret;
@@ -129,8 +156,9 @@ static bool write_message(struct connection *conn)
if (out->inhdr) {
if (verbose)
- xprintf("Writing msg %i out to %p\n",
- out->hdr.msg.type, conn);
+ xprintf("Writing msg %s (%s) out to %p\n",
+ sockmsg_string(out->hdr.msg.type),
+ out->buffer, conn);
ret = conn->write(conn, out->hdr.raw + out->used,
sizeof(out->hdr) - out->used);
if (ret < 0)
@@ -148,9 +176,6 @@ static bool write_message(struct connection *conn)
return true;
}
- if (verbose)
- xprintf("Writing data len %i out to %p\n",
- out->hdr.msg.len, conn);
ret = conn->write(conn, out->buffer + out->used,
out->hdr.msg.len - out->used);
@@ -162,10 +187,7 @@ static bool write_message(struct connection *conn)
return true;
conn->out = NULL;
-
- /* If this was an event, we wait for ack, otherwise we're done. */
- if (!is_watch_event(conn, out))
- talloc_free(out);
+ talloc_free(out);
queue_next_event(conn);
return true;
@@ -402,7 +424,7 @@ static bool valid_chars(const char *node)
"0123456789-/_@") == strlen(node));
}
-static bool is_valid_nodename(const char *node)
+bool is_valid_nodename(const char *node)
{
/* Must start in /. */
if (!strstarts(node, "/"))
@@ -601,17 +623,24 @@ static int check_with_parents(struct connection *conn, const char *node,
return errnum;
}
+char *canonicalize(struct connection *conn, const char *node)
+{
+ const char *prefix;
+
+ if (!node || strstarts(node, "/"))
+ return (char *)node;
+ prefix = get_implicit_path(conn);
+ if (prefix)
+ return talloc_asprintf(node, "%s/%s", prefix, node);
+ return (char *)node;
+}
+
bool check_node_perms(struct connection *conn, const char *node,
enum xs_perm_type perm)
{
struct xs_permissions *perms;
unsigned int num;
- if (!node) {
- errno = EINVAL;
- return false;
- }
-
if (!node || !is_valid_nodename(node)) {
errno = EINVAL;
return false;
@@ -651,6 +680,7 @@ static bool send_directory(struct connection *conn, const char *node)
DIR *dir;
struct dirent *dirent;
+ node = canonicalize(conn, node);
if (!check_node_perms(conn, node, XS_PERM_READ))
return send_error(conn, errno);
@@ -680,6 +710,7 @@ static bool do_read(struct connection *conn, const char *node)
unsigned int size;
int *fd;
+ node = canonicalize(conn, node);
if (!check_node_perms(conn, node, XS_PERM_READ))
return send_error(conn, errno);
@@ -750,7 +781,7 @@ static bool do_write(struct connection *conn, struct buffered_data *in)
if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
return send_error(conn, EINVAL);
- node = vec[0];
+ node = canonicalize(conn, vec[0]);
if (!within_transaction(conn->transaction, node))
return send_error(conn, EROFS);
@@ -804,6 +835,7 @@ static bool do_write(struct connection *conn, struct buffered_data *in)
static bool do_mkdir(struct connection *conn, const char *node)
{
+ node = canonicalize(conn, node);
if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE))
return send_error(conn, errno);
@@ -826,6 +858,7 @@ static bool do_rm(struct connection *conn, const char *node)
{
char *tmppath, *path;
+ node = canonicalize(conn, node);
if (!check_node_perms(conn, node, XS_PERM_WRITE))
return send_error(conn, errno);
@@ -848,6 +881,7 @@ static bool do_rm(struct connection *conn, const char *node)
add_change_node(conn->transaction, node);
send_ack(conn, XS_RM);
+ /* FIXME: traverse and fire watches for ALL of them! */
fire_watches(conn->transaction, node);
return false;
}
@@ -858,6 +892,7 @@ static bool do_get_perms(struct connection *conn, const char *node)
char *strings;
unsigned int len, num;
+ node = canonicalize(conn, node);
if (!check_node_perms(conn, node, XS_PERM_READ))
return send_error(conn, errno);
@@ -883,7 +918,7 @@ static bool do_set_perms(struct connection *conn, struct buffered_data *in)
return send_error(conn, EINVAL);
/* First arg is node name. */
- node = in->buffer;
+ node = canonicalize(conn, in->buffer);
in->buffer += strlen(in->buffer) + 1;
num--;
@@ -968,10 +1003,10 @@ static bool process_message(struct connection *conn, struct buffered_data *in)
return do_watch(conn, in);
case XS_WATCH_ACK:
- return do_watch_ack(conn);
+ return do_watch_ack(conn, onearg(in));
case XS_UNWATCH:
- return do_unwatch(conn, onearg(in));
+ return do_unwatch(conn, in);
case XS_TRANSACTION_START:
return do_transaction_start(conn, onearg(in));
@@ -1015,13 +1050,13 @@ static void consider_message(struct connection *conn)
}
if (verbose)
- xprintf("Got message %i len %i from %p\n",
- type, conn->in->hdr.msg.len, conn);
+ xprintf("Got message %s len %i from %p\n",
+ sockmsg_string(type), conn->in->hdr.msg.len, conn);
/* We might get a command while waiting for an ack: this means
* the other end discarded it: we will re-transmit. */
if (type != XS_WATCH_ACK)
- reset_watch_event(conn);
+ conn->waiting_for_ack = false;
/* Careful: process_message may free connection. We detach
* "in" beforehand and allocate the new buffer to avoid
@@ -1136,7 +1171,6 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
new->blocked = false;
new->out = new->waiting_reply = NULL;
- new->event = NULL;
new->fd = -1;
new->id = 0;
new->domain = NULL;
@@ -1203,6 +1237,42 @@ static void time_relative_to_now(struct timeval *tv)
}
}
+#ifdef TESTING
+/* Useful for running under debugger. */
+void dump_connection(void)
+{
+ struct connection *i;
+
+ list_for_each_entry(i, &connections, list) {
+ printf("Connection %p:\n", i);
+ if (i->id)
+ printf(" id = %i\n", i->id);
+ if (i->blocked)
+ printf(" blocked on = %s\n", i->blocked);
+ if (i->waiting_for_ack)
+ printf(" waiting_for_ack TRUE\n");
+ if (!i->in->inhdr || i->in->used)
+ printf(" got %i bytes of %s\n",
+ i->in->used, i->in->inhdr ? "header" : "data");
+ if (i->out)
+ printf(" sending message %s (%s) out\n",
+ sockmsg_string(i->out->hdr.msg.type),
+ i->out->buffer);
+ if (i->waiting_reply)
+ printf(" ... and behind is queued %s (%s)\n",
+ sockmsg_string(i->waiting_reply->hdr.msg.type),
+ i->waiting_reply->buffer);
+#if 0
+ if (i->transaction)
+ dump_transaction(i);
+ if (i->domain)
+ dump_domain(i);
+#endif
+ dump_watches(i);
+ }
+}
+#endif
+
static struct option options[] = { { "no-fork", 0, NULL, 'N' },
{ "verbose", 0, NULL, 'V' },
{ "output-pid", 0, NULL, 'P' },
@@ -1314,6 +1384,7 @@ int main(int argc, char *argv[])
timerclear(&tv);
shortest_transaction_timeout(&tv);
+ shortest_watch_ack_timeout(&tv);
if (timerisset(&tv)) {
time_relative_to_now(&tv);
tvp = &tv;
@@ -1351,8 +1422,15 @@ int main(int argc, char *argv[])
}
}
- if (tvp)
+ /* Flush output for domain connections, */
+ list_for_each_entry(i, &connections, list)
+ if (i->domain && i->out)
+ handle_output(i);
+
+ if (tvp) {
check_transaction_timeout();
+ check_watch_ack_timeout();
+ }
/* If transactions ended, we might be able to do more work. */
unblock_connections();
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0d0ebcaae0..a82ae8b22e 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -16,8 +16,10 @@
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_INTERNAL_H
-#define _XENSTORED_INTERNAL_H
+
+#ifndef _XENSTORED_CORE_H
+#define _XENSTORED_CORE_H
+
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
@@ -59,8 +61,8 @@ struct connection
/* Is this a read-only connection? */
bool can_write;
- /* Our current event. If all used, we're waiting for ack. */
- struct watch_event *event;
+ /* Are we waiting for a watch event ack? */
+ bool waiting_for_ack;
/* Buffered incoming data. */
struct buffered_data *in;
@@ -105,6 +107,9 @@ bool send_ack(struct connection *conn, enum xsd_sockmsg_type type);
/* Send an error: error is usually "errno". */
bool send_error(struct connection *conn, int error);
+/* Canonicalize this path if possible. */
+char *canonicalize(struct connection *conn, const char *node);
+
/* Check permissions on this node. */
bool check_node_perms(struct connection *conn, const char *node,
enum xs_perm_type perm);
@@ -121,6 +126,10 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
void handle_input(struct connection *conn);
void handle_output(struct connection *conn);
+/* Is this a valid node name? */
+bool is_valid_nodename(const char *node);
+
/* Convenient talloc-style destructor for paths. */
int destroy_path(void *path);
-#endif /* _XENSTORED_INTERNAL_H */
+
+#endif /* _XENSTORED_CORE_H */
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index a6f69ddf5b..8b154c49e4 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -65,11 +65,6 @@ struct domain
static LIST_HEAD(domains);
-void domain_set_conn(struct domain *domain, struct connection *conn)
-{
- domain->conn = conn;
-}
-
struct ringbuf_head
{
u32 write; /* Next place to write to */
@@ -268,6 +263,9 @@ bool do_introduce(struct connection *conn, struct buffered_data *in)
if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
return send_error(conn, EINVAL);
+ if (conn->id != 0)
+ return send_error(conn, EACCES);
+
if (!conn->can_write)
return send_error(conn, EROFS);
@@ -275,10 +273,9 @@ bool do_introduce(struct connection *conn, struct buffered_data *in)
domain = talloc(in, struct domain);
domain->domid = atoi(vec[0]);
domain->port = atoi(vec[2]);
- domain->path = talloc_strdup(domain, vec[3]);
- talloc_set_destructor(domain, destroy_domain);
- if (!domain->port || !domain->domid)
+ if (!domain->port || !domain->domid || !is_valid_nodename(vec[3]))
return send_error(conn, EINVAL);
+ domain->path = talloc_strdup(domain, vec[3]);
domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
getpagesize(),
PROT_READ|PROT_WRITE,
@@ -286,6 +283,9 @@ bool do_introduce(struct connection *conn, struct buffered_data *in)
if (!domain->page)
return send_error(conn, errno);
+ list_add(&domain->list, &domains);
+ talloc_set_destructor(domain, destroy_domain);
+
/* One in each half of page. */
domain->input = domain->page;
domain->output = domain->page + getpagesize()/2;
@@ -298,7 +298,6 @@ bool do_introduce(struct connection *conn, struct buffered_data *in)
domain->conn->domain = domain;
talloc_steal(domain->conn, domain);
- list_add(&domain->list, &domains);
return send_ack(conn, XS_INTRODUCE);
}
@@ -327,6 +326,9 @@ bool do_release(struct connection *conn, const char *domid_str)
if (!domid)
return send_error(conn, EINVAL);
+ if (conn->id != 0)
+ return send_error(conn, EACCES);
+
domain = find_domain_by_domid(domid);
if (!domain)
return send_error(conn, ENOENT);
@@ -365,6 +367,14 @@ static int close_xc_handle(void *_handle)
return 0;
}
+/* Returns the implicit path of a connection (only domains have this) */
+const char *get_implicit_path(const struct connection *conn)
+{
+ if (!conn->domain)
+ return NULL;
+ return conn->domain->path;
+}
+
/* Returns the event channel handle. */
int domain_init(void)
{
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 20e85a54b5..74dc34e8e5 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -16,6 +16,7 @@
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_DOMAIN_H
#define _XENSTORED_DOMAIN_H
@@ -33,6 +34,7 @@ bool do_get_domain_path(struct connection *conn, const char *domid_str);
/* Returns the event channel handle */
int domain_init(void);
-void domain_set_conn(struct domain *domain, struct connection *conn);
+/* Returns the implicit path of a connection (only domains have this) */
+const char *get_implicit_path(const struct connection *conn);
#endif /* _XENSTORED_DOMAIN_H */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ca37307f8c..dd70579109 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -201,6 +201,7 @@ bool do_transaction_start(struct connection *conn, const char *node)
if (conn->transaction)
return send_error(conn, EBUSY);
+ node = canonicalize(conn, node);
if (!check_node_perms(conn, node, XS_PERM_READ))
return send_error(conn, errno);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 2df83e1a54..d0e00f53c2 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -21,6 +21,8 @@
#include <sys/types.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
#include "talloc.h"
#include "list.h"
#include "xenstored_watch.h"
@@ -28,6 +30,8 @@
#include "utils.h"
#include "xenstored_test.h"
+/* FIXME: time out unacked watches. */
+
/* We create this if anyone is interested "node", then we pass it from
* watch to watch as each connection acks it.
*/
@@ -39,7 +43,10 @@ struct watch_event
/* Watch we are currently attached to. */
struct watch *watch;
- struct buffered_data *data;
+ struct timeval timeout;
+
+ /* Name of node which changed. */
+ char *node;
};
struct watch
@@ -50,72 +57,63 @@ struct watch
/* Current outstanding events applying to this watch. */
struct list_head events;
+ char *token;
char *node;
struct connection *conn;
};
static LIST_HEAD(watches);
-static void reset_event(struct watch_event *event)
-{
- event->data->inhdr = true;
- event->data->used = 0;
-}
-
-/* We received a non-ACK response: re-queue any watch we just sent. */
-void reset_watch_event(struct connection *conn)
-{
- if (waiting_for_ack(conn))
- reset_event(conn->event);
-}
-
-/* We're waiting if we have an event and we sent it all. */
-bool waiting_for_ack(struct connection *conn)
+static struct watch_event *get_first_event(struct connection *conn)
{
- if (!conn->event)
- return false;
+ struct watch *watch;
+ struct watch_event *event;
- if (conn->event->data->inhdr)
- return false;
- return conn->event->data->used == conn->event->data->hdr.msg.len;
-}
+ /* Find first watch with an event. */
+ list_for_each_entry(watch, &watches, list) {
+ if (watch->conn != conn)
+ continue;
-bool is_watch_event(struct connection *conn, struct buffered_data *out)
-{
- return (conn->event && out == conn->event->data);
+ event = list_top(&watch->events, struct watch_event, list);
+ if (event)
+ return event;
+ }
+ return NULL;
}
/* Look through our watches: if any of them have an event, queue it. */
void queue_next_event(struct connection *conn)
{
- struct watch *watch;
+ struct watch_event *event;
+ char *buffer;
+ unsigned int len;
- /* We had a reply queued already? Send it. */
+ /* We had a reply queued already? Send it: other end will
+ * discard watch. */
if (conn->waiting_reply) {
conn->out = conn->waiting_reply;
conn->waiting_reply = NULL;
+ conn->waiting_for_ack = false;
return;
}
- /* If we're waiting for ack, don't queue more. */
- if (waiting_for_ack(conn))
+ /* If we're already waiting for ack, don't queue more. */
+ if (conn->waiting_for_ack)
return;
- /* Find a good event to send. */
- if (!conn->event) {
- list_for_each_entry(watch, &watches, list) {
- if (watch->conn != conn)
- continue;
+ event = get_first_event(conn);
+ if (!event)
+ return;
- conn->event = list_top(&watch->events,
- struct watch_event, list);
- if (conn->event)
- break;
- }
- if (!conn->event)
- return;
- }
+ /* If we decide to cancel, we will reset this. */
+ conn->waiting_for_ack = true;
- conn->out = conn->event->data;
+ /* Create reply from path and token */
+ len = strlen(event->node) + 1 + strlen(event->watch->token) + 1;
+ buffer = talloc_array(conn, char, len);
+ strcpy(buffer, event->node);
+ strcpy(buffer+strlen(event->node)+1, event->watch->token);
+ send_reply(conn, XS_WATCH_EVENT, buffer, len);
+ talloc_free(buffer);
}
/* Watch on DIR applies to DIR, DIR/FILE, but not DIRLONG. */
@@ -160,14 +158,15 @@ void fire_watches(struct transaction *trans, const char *node)
/* Create and fill in info about event. */
event = talloc(talloc_autofree_context(), struct watch_event);
- event->data = new_buffer(event);
- event->data->hdr.msg.type = XS_WATCH_EVENT;
- event->data->hdr.msg.len = strlen(node) + 1;
- event->data->buffer = talloc_strdup(event->data, node);
+ event->node = talloc_strdup(event, node);
/* Tie event to this watch. */
event->watch = watch;
- list_add(&event->list, &watch->events);
+ list_add_tail(&event->list, &watch->events);
+
+ /* Warn if not finished after thirty seconds. */
+ gettimeofday(&event->timeout, NULL);
+ event->timeout.tv_sec += 30;
/* If connection not doing anything, queue this. */
if (!watch->conn->out)
@@ -178,16 +177,15 @@ void fire_watches(struct transaction *trans, const char *node)
static void move_event_onwards(struct watch_event *event)
{
list_del(&event->list);
- reset_event(event);
/* Remove from this watch, and find next watch to put this on. */
- event->watch = find_next_watch(event->watch, event->data->buffer);
+ event->watch = find_next_watch(event->watch, event->node);
if (!event->watch) {
talloc_free(event);
return;
}
- list_add(&event->list, &event->watch->events);
+ list_add_tail(&event->list, &event->watch->events);
/* If connection not doing anything, queue this. */
if (!event->watch->conn->out)
@@ -199,10 +197,6 @@ static int destroy_watch(void *_watch)
struct watch *watch = _watch;
struct watch_event *event;
- /* Forget about sending out or waiting for acks for this watch. */
- if (watch->conn->event && watch->conn->event->watch == watch)
- watch->conn->event = NULL;
-
/* If we have pending events, pass them on to others. */
while ((event = list_top(&watch->events, struct watch_event, list)))
move_event_onwards(event);
@@ -227,21 +221,59 @@ static void insert_watch(struct watch *watch)
list_add_tail(&watch->list, &watches);
}
+void shortest_watch_ack_timeout(struct timeval *tv)
+{
+ struct watch *watch;
+
+ list_for_each_entry(watch, &watches, list) {
+ struct watch_event *i;
+ list_for_each_entry(i, &watch->events, list) {
+ if (!timerisset(&i->timeout))
+ continue;
+ if (!timerisset(tv) || timercmp(&i->timeout, tv, <))
+ *tv = i->timeout;
+ }
+ }
+}
+
+void check_watch_ack_timeout(void)
+{
+ struct watch *watch;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ list_for_each_entry(watch, &watches, list) {
+ struct watch_event *i, *tmp;
+ list_for_each_entry_safe(i, tmp, &watch->events, list) {
+ if (!timerisset(&i->timeout))
+ continue;
+ if (timercmp(&i->timeout, &now, <)) {
+ xprintf("Warning: timeout on watch event %s"
+ " token %s\n",
+ i->node, watch->token);
+ timerclear(&i->timeout);
+ }
+ }
+ }
+}
+
bool do_watch(struct connection *conn, struct buffered_data *in)
{
struct watch *watch;
- char *vec[2];
+ char *vec[3];
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
return send_error(conn, EINVAL);
+ vec[0] = canonicalize(conn, vec[0]);
if (!check_node_perms(conn, vec[0], XS_PERM_READ))
return send_error(conn, errno);
watch = talloc(conn, struct watch);
watch->node = talloc_strdup(watch, vec[0]);
+ watch->token = talloc_strdup(watch, vec[1]);
watch->conn = conn;
- watch->priority = strtoul(vec[1], NULL, 0);
+ watch->priority = strtoul(vec[2], NULL, 0);
INIT_LIST_HEAD(&watch->events);
insert_watch(watch);
@@ -249,31 +281,58 @@ bool do_watch(struct connection *conn, struct buffered_data *in)
return send_ack(conn, XS_WATCH);
}
-bool do_watch_ack(struct connection *conn)
+bool do_watch_ack(struct connection *conn, const char *token)
{
struct watch_event *event;
- if (!waiting_for_ack(conn))
+ if (!conn->waiting_for_ack)
return send_error(conn, ENOENT);
- /* Remove this watch event. */
- event = conn->event;
- conn->event = NULL;
+ event = get_first_event(conn);
+ if (!streq(event->watch->token, token))
+ return send_error(conn, EINVAL);
move_event_onwards(event);
+ conn->waiting_for_ack = false;
return send_ack(conn, XS_WATCH_ACK);
}
-bool do_unwatch(struct connection *conn, const char *node)
+bool do_unwatch(struct connection *conn, struct buffered_data *in)
{
struct watch *watch;
+ char *node, *vec[2];
+
+ if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
+ return send_error(conn, EINVAL);
+ node = canonicalize(conn, vec[0]);
list_for_each_entry(watch, &watches, list) {
- if (watch->conn == conn
- && streq(watch->node, node)) {
+ if (watch->conn != conn)
+ continue;
+
+ if (streq(watch->node, node) && streq(watch->token, vec[1])) {
talloc_free(watch);
return send_ack(conn, XS_UNWATCH);
}
}
return send_error(conn, ENOENT);
}
+
+#ifdef TESTING
+void dump_watches(struct connection *conn)
+{
+ struct watch *watch;
+ struct watch_event *event;
+
+ /* Find first watch with an event. */
+ list_for_each_entry(watch, &watches, list) {
+ if (watch->conn != conn)
+ continue;
+
+ printf(" watch on %s token %s prio %i\n",
+ watch->node, watch->token, watch->priority);
+ list_for_each_entry(event, &watch->events, list)
+ printf(" event: %s\n", event->node);
+ }
+}
+#endif
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 656ce4c36b..e9c0ad8f0b 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -16,13 +16,15 @@
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_WATCH_H
#define _XENSTORED_WATCH_H
+
#include "xenstored_core.h"
bool do_watch(struct connection *conn, struct buffered_data *in);
-bool do_watch_ack(struct connection *conn);
-bool do_unwatch(struct connection *conn, const char *node);
+bool do_watch_ack(struct connection *conn, const char *token);
+bool do_unwatch(struct connection *conn, struct buffered_data *in);
/* Is this a watch event message for this connection? */
bool is_watch_event(struct connection *conn, struct buffered_data *out);
@@ -30,13 +32,15 @@ bool is_watch_event(struct connection *conn, struct buffered_data *out);
/* Look through our watches: if any of them have an event, queue it. */
void queue_next_event(struct connection *conn);
-/* Is this connection waiting for a watch acknowledgement? */
-bool waiting_for_ack(struct connection *conn);
-
-/* Reset event if we were sending one */
-void reset_watch_event(struct connection *conn);
-
/* Fire all watches. */
void fire_watches(struct transaction *trans, const char *node);
+/* Find shortest timeout: if any, reduce tv (may already be set). */
+void shortest_watch_ack_timeout(struct timeval *tv);
+
+/* Check for watches which may have timed out. */
+void check_watch_ack_timeout(void);
+
+void dump_watches(struct connection *conn);
+
#endif /* _XENSTORED_WATCH_H */
diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c
index d6e41380f9..c11e02ae1e 100644
--- a/tools/xenstore/xs.c
+++ b/tools/xenstore/xs.c
@@ -131,6 +131,7 @@ static int get_error(const char *errorstring)
return xsd_errors[i].errnum;
}
+/* Adds extra nul terminator, because we generally (always?) hold strings. */
static void *read_reply(int fd, enum xsd_sockmsg_type *type, unsigned int *len)
{
struct xsd_sockmsg msg;
@@ -140,7 +141,7 @@ static void *read_reply(int fd, enum xsd_sockmsg_type *type, unsigned int *len)
if (!read_all(fd, &msg, sizeof(msg)))
return NULL;
- ret = malloc(msg.len);
+ ret = malloc(msg.len + 1);
if (!ret)
return NULL;
@@ -154,13 +155,13 @@ static void *read_reply(int fd, enum xsd_sockmsg_type *type, unsigned int *len)
*type = msg.type;
if (len)
*len = msg.len;
+ ((char *)ret)[msg.len] = '\0';
return ret;
}
/* Send message to xs, get malloc'ed reply. NULL and set errno on error. */
static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type,
- const struct iovec *iovec,
- unsigned int num_vecs,
+ const struct iovec *iovec, unsigned int num_vecs,
unsigned int *len)
{
struct xsd_sockmsg msg;
@@ -270,9 +271,9 @@ char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num)
return ret;
}
-/* Get the value of a single file.
+/* Get the value of a single file, nul terminated.
* Returns a malloced value: call free() on it after use.
- * len indicates length in bytes.
+ * len indicates length in bytes, not including the nul.
*/
void *xs_read(struct xs_handle *h, const char *path, unsigned int *len)
{
@@ -330,8 +331,7 @@ bool xs_rm(struct xs_handle *h, const char *path)
* Returns malloced array, or NULL: call free() after use.
*/
struct xs_permissions *xs_get_permissions(struct xs_handle *h,
- const char *path,
- unsigned int *num)
+ const char *path, unsigned int *num)
{
char *strings;
unsigned int len;
@@ -400,61 +400,75 @@ unwind:
/* Watch a node for changes (poll on fd to detect, or call read_watch()).
* When the node (or any child) changes, fd will become readable.
+ * Token is returned when watch is read, to allow matching.
* Priority indicates order if multiple watchers: higher is first.
* Returns false on failure.
*/
-bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority)
+bool xs_watch(struct xs_handle *h, const char *path, const char *token,
+ unsigned int priority)
{
char prio[MAX_STRLEN(priority)];
- struct iovec iov[2];
+ struct iovec iov[3];
sprintf(prio, "%u", priority);
iov[0].iov_base = (void *)path;
iov[0].iov_len = strlen(path) + 1;
- iov[1].iov_base = prio;
- iov[1].iov_len = strlen(prio) + 1;
+ iov[1].iov_base = (void *)token;
+ iov[1].iov_len = strlen(token) + 1;
+ iov[2].iov_base = prio;
+ iov[2].iov_len = strlen(prio) + 1;
return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
}
/* Find out what node change was on (will block if nothing pending).
- * Returns malloced path, or NULL: call free() after use.
+ * Returns array of two pointers: path and token, or NULL.
+ * Call free() after use.
*/
-char *xs_read_watch(struct xs_handle *h)
+char **xs_read_watch(struct xs_handle *h)
{
struct xsd_sockmsg msg;
- char *path;
+ char **ret;
if (!read_all(h->fd, &msg, sizeof(msg)))
return NULL;
assert(msg.type == XS_WATCH_EVENT);
- path = malloc(msg.len);
- if (!path)
+ ret = malloc(sizeof(char *)*2 + msg.len);
+ if (!ret)
return NULL;
- if (!read_all(h->fd, path, msg.len)) {
- free_no_errno(path);
+ ret[0] = (char *)(ret + 2);
+ if (!read_all(h->fd, ret[0], msg.len)) {
+ free_no_errno(ret);
return NULL;
}
- return path;
+ ret[1] = ret[0] + strlen(ret[0]) + 1;
+ return ret;
}
/* Acknowledge watch on node. Watches must be acknowledged before
* any other watches can be read.
* Returns false on failure.
*/
-bool xs_acknowledge_watch(struct xs_handle *h)
+bool xs_acknowledge_watch(struct xs_handle *h, const char *token)
{
- return xs_bool(xs_single(h, XS_WATCH_ACK, "OK", NULL));
+ return xs_bool(xs_single(h, XS_WATCH_ACK, token, NULL));
}
/* Remove a watch on a node.
* Returns false on failure (no watch on that node).
*/
-bool xs_unwatch(struct xs_handle *h, const char *path)
+bool xs_unwatch(struct xs_handle *h, const char *path, const char *token)
{
- return xs_bool(xs_single(h, XS_UNWATCH, path, NULL));
+ struct iovec iov[2];
+
+ iov[0].iov_base = (char *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (char *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_bool(xs_talkv(h, XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
}
/* Start a transaction: changes by others will not be seen during this
@@ -488,11 +502,8 @@ bool xs_transaction_end(struct xs_handle *h, bool abort)
* This tells the store daemon about a shared memory page and event channel
* associated with a domain: the domain uses these to communicate.
*/
-bool xs_introduce_domain(struct xs_handle *h,
- domid_t domid,
- unsigned long mfn,
- unsigned int eventchn,
- const char *path)
+bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn,
+ unsigned int eventchn, const char *path)
{
char domid_str[MAX_STRLEN(domid)];
char mfn_str[MAX_STRLEN(mfn)];
@@ -515,8 +526,7 @@ bool xs_introduce_domain(struct xs_handle *h,
return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL));
}
-bool xs_release_domain(struct xs_handle *h,
- domid_t domid)
+bool xs_release_domain(struct xs_handle *h, domid_t domid)
{
char domid_str[MAX_STRLEN(domid)];
diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h
index ff9481c3a6..09d5a20937 100644
--- a/tools/xenstore/xs.h
+++ b/tools/xenstore/xs.h
@@ -1,5 +1,3 @@
-#ifndef _XS_H
-#define _XS_H
/*
Xen Store Daemon providing simple tree-like database.
Copyright (C) 2005 Rusty Russell IBM Corporation
@@ -19,11 +17,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* On failure, these routines set errno. */
+#ifndef _XS_H
+#define _XS_H
+
#include "xs_lib.h"
struct xs_handle;
+/* On failure, these routines set errno. */
+
/* Connect to the xs daemon.
* Returns a handle or NULL.
*/
@@ -43,17 +45,17 @@ void xs_daemon_close(struct xs_handle *);
*/
char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num);
-/* Get the value of a single file.
+/* Get the value of a single file, nul terminated.
* Returns a malloced value: call free() on it after use.
- * len indicates length in bytes.
+ * len indicates length in bytes, not including the nul.
*/
void *xs_read(struct xs_handle *h, const char *path, unsigned int *len);
/* Write the value of a single file.
* Returns false on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
*/
-bool xs_write(struct xs_handle *h, const char *path, const void *data, unsigned int len,
- int createflags);
+bool xs_write(struct xs_handle *h, const char *path, const void *data,
+ unsigned int len, int createflags);
/* Create a new directory.
* Returns false on failure.
@@ -69,42 +71,42 @@ bool xs_rm(struct xs_handle *h, const char *path);
* Returns malloced array, or NULL: call free() after use.
*/
struct xs_permissions *xs_get_permissions(struct xs_handle *h,
- const char *path,
- unsigned int *num);
+ const char *path, unsigned int *num);
/* Set permissions of node (must be owner).
* Returns false on failure.
*/
-bool xs_set_permissions(struct xs_handle *h,
- const char *path,
- struct xs_permissions *perms,
- unsigned int num_perms);
+bool xs_set_permissions(struct xs_handle *h, const char *path,
+ struct xs_permissions *perms, unsigned int num_perms);
/* Watch a node for changes (poll on fd to detect, or call read_watch()).
* When the node (or any child) changes, fd will become readable.
+ * Token is returned when watch is read, to allow matching.
* Priority indicates order if multiple watchers: higher is first.
* Returns false on failure.
*/
-bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority);
+bool xs_watch(struct xs_handle *h, const char *path, const char *token,
+ unsigned int priority);
/* Return the FD to poll on to see if a watch has fired. */
int xs_fileno(struct xs_handle *h);
/* Find out what node change was on (will block if nothing pending).
- * Returns malloced path, or NULL: call free() after use.
+ * Returns array of two pointers: path and token, or NULL.
+ * Call free() after use.
*/
-char *xs_read_watch(struct xs_handle *h);
+char **xs_read_watch(struct xs_handle *h);
/* Acknowledge watch on node. Watches must be acknowledged before
* any other watches can be read.
* Returns false on failure.
*/
-bool xs_acknowledge_watch(struct xs_handle *h);
+bool xs_acknowledge_watch(struct xs_handle *h, const char *token);
/* Remove a watch on a node.
* Returns false on failure (no watch on that node).
*/
-bool xs_unwatch(struct xs_handle *h, const char *path);
+bool xs_unwatch(struct xs_handle *h, const char *path, const char *token);
/* Start a transaction: changes by others will not be seen during this
* transaction, and changes will not be visible to others until end.
@@ -125,11 +127,8 @@ bool xs_transaction_end(struct xs_handle *h, bool abort);
* This tells the store daemon about a shared memory page, event channel
* and store path associated with a domain: the domain uses these to communicate.
*/
-bool xs_introduce_domain(struct xs_handle *h,
- domid_t domid,
- unsigned long mfn,
- unsigned int eventchn,
- const char *path);
+bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn,
+ unsigned int eventchn, const char *path);
/* Release a domain.
* Tells the store domain to release the memory page to the domain.
diff --git a/tools/xenstore/xs_dom0_test.c b/tools/xenstore/xs_dom0_test.c
new file mode 100644
index 0000000000..8b3b5e695a
--- /dev/null
+++ b/tools/xenstore/xs_dom0_test.c
@@ -0,0 +1,43 @@
+/* Test introduction of domain 0 */
+#include <linux/ioctl.h>
+#include <sys/ioctl.h>
+#include "xs.h"
+#include "utils.h"
+#include <xc.h>
+#include <xen/linux/privcmd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+int main()
+{
+ int h, local = 0, kernel = 0;
+ long err;
+ void *page;
+
+ h = xc_interface_open();
+ if (h < 0)
+ barf_perror("Failed to open xc");
+
+ if (xc_evtchn_bind_interdomain(h, DOMID_SELF, 0, &local, &kernel) != 0)
+ barf_perror("Failed to bind interdomain");
+
+ printf("Got ports %i & %i\n", local, kernel);
+
+ err = ioctl(h, IOCTL_PRIVCMD_INITDOMAIN_STORE, kernel);
+ if (err < 0)
+ barf_perror("Failed to initialize store");
+ printf("Got mfn %li\n", err);
+
+ page = xc_map_foreign_range(h, 0, getpagesize(), PROT_READ|PROT_WRITE,
+ err);
+ if (!page)
+ barf_perror("Failed to map page %li", err);
+ printf("Mapped page at %p\n", page);
+ printf("Page says %s\n", (char *)page);
+ munmap(page, getpagesize());
+ printf("unmapped\n");
+
+ return 0;
+}
+
diff --git a/tools/xenstore/xs_lib.c b/tools/xenstore/xs_lib.c
index 3f4f4b0899..cc9f9e1706 100644
--- a/tools/xenstore/xs_lib.c
+++ b/tools/xenstore/xs_lib.c
@@ -67,7 +67,7 @@ bool xs_write_all(int fd, const void *data, unsigned int len)
/* Convert strings to permissions. False if a problem. */
bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num,
- const char *strings)
+ const char *strings)
{
const char *p;
char *end;
@@ -138,4 +138,3 @@ unsigned int xs_count_strings(const char *strings, unsigned int len)
return num;
}
-
diff --git a/tools/xenstore/xs_lib.h b/tools/xenstore/xs_lib.h
index 76ea9b67fe..97b72c8c7e 100644
--- a/tools/xenstore/xs_lib.h
+++ b/tools/xenstore/xs_lib.h
@@ -1,5 +1,3 @@
-#ifndef _XR_LIB_H
-#define _XR_LIB_H
/*
Common routines between Xen store user library and daemon.
Copyright (C) 2005 Rusty Russell IBM Corporation
@@ -18,6 +16,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
+#ifndef _XS_LIB_H
+#define _XS_LIB_H
+
#include <stdbool.h>
#include <limits.h>
#include <xc.h>
@@ -52,7 +54,7 @@ bool xs_write_all(int fd, const void *data, unsigned int len);
/* Convert strings to permissions. False if a problem. */
bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num,
- const char *strings);
+ const char *strings);
/* Convert permissions to a string (up to len MAX_STRLEN(domid_t)+1). */
bool xs_perm_to_string(const struct xs_permissions *perm, char *buffer);
diff --git a/tools/xenstore/xs_stress.c b/tools/xenstore/xs_stress.c
index 9c480b1553..0c257e465b 100644
--- a/tools/xenstore/xs_stress.c
+++ b/tools/xenstore/xs_stress.c
@@ -50,7 +50,7 @@ static void work(unsigned int cycles, unsigned int childnum)
}
if (streq(lockdir, ""))
strcpy(lockdir, "/");
-
+
if (!xs_transaction_start(h, lockdir))
barf_perror("%i: starting transaction %i on %s",
childnum, i, lockdir);
diff --git a/tools/xenstore/xs_test.c b/tools/xenstore/xs_test.c
index 4d769e220d..6ce5d701af 100644
--- a/tools/xenstore/xs_test.c
+++ b/tools/xenstore/xs_test.c
@@ -173,9 +173,9 @@ static void __attribute__((noreturn)) usage(void)
" getperm <path>\n"
" setperm <path> <id> <flags> ...\n"
" shutdown\n"
- " watch <path> <prio>\n"
+ " watch <path> <token> <prio>\n"
" waitwatch\n"
- " ackwatch\n"
+ " ackwatch <token>\n"
" unwatch <path> <token>\n"
" close\n"
" start <node>\n"
@@ -240,6 +240,8 @@ static void do_read(unsigned int handle, char *path)
if (!value)
failed(handle);
+ /* It's supposed to nul terminate for us. */
+ assert(value[len] == '\0');
if (handle)
printf("%i:%.*s\n", handle, len, value);
else
@@ -261,7 +263,7 @@ static void do_write(unsigned int handle, char *path, char *flags, char *data)
else
barf("write flags 'none', 'create' or 'excl' only");
- if (!xs_write(handles[handle], path, data, strlen(data)+1, f))
+ if (!xs_write(handles[handle], path, data, strlen(data), f))
failed(handle);
}
@@ -358,36 +360,37 @@ static void do_shutdown(unsigned int handle)
failed(handle);
}
-static void do_watch(unsigned int handle, const char *node, const char *pri)
+static void do_watch(unsigned int handle, const char *node, const char *token,
+ const char *pri)
{
- if (!xs_watch(handles[handle], node, atoi(pri)))
+ if (!xs_watch(handles[handle], node, token, atoi(pri)))
failed(handle);
}
static void do_waitwatch(unsigned int handle)
{
- char *node;
+ char **vec;
- node = xs_read_watch(handles[handle]);
- if (!node)
+ vec = xs_read_watch(handles[handle]);
+ if (!vec)
failed(handle);
if (handle)
- printf("%i:%s\n", handle, node);
+ printf("%i:%s:%s\n", handle, vec[0], vec[1]);
else
- printf("%s\n", node);
- free(node);
+ printf("%s:%s\n", vec[0], vec[1]);
+ free(vec);
}
-static void do_ackwatch(unsigned int handle)
+static void do_ackwatch(unsigned int handle, const char *token)
{
- if (!xs_acknowledge_watch(handles[handle]))
+ if (!xs_acknowledge_watch(handles[handle], token))
failed(handle);
}
-static void do_unwatch(unsigned int handle, const char *node)
+static void do_unwatch(unsigned int handle, const char *node, const char *token)
{
- if (!xs_unwatch(handles[handle], node))
+ if (!xs_unwatch(handles[handle], node, token))
failed(handle);
}
@@ -613,13 +616,13 @@ int main(int argc, char *argv[])
else if (streq(command, "shutdown"))
do_shutdown(handle);
else if (streq(command, "watch"))
- do_watch(handle, arg(line, 1), arg(line, 2));
+ do_watch(handle, arg(line, 1), arg(line, 2), arg(line, 3));
else if (streq(command, "waitwatch"))
do_waitwatch(handle);
else if (streq(command, "ackwatch"))
- do_ackwatch(handle);
+ do_ackwatch(handle, arg(line, 1));
else if (streq(command, "unwatch"))
- do_unwatch(handle, arg(line, 1));
+ do_unwatch(handle, arg(line, 1), arg(line, 2));
else if (streq(command, "close")) {
xs_daemon_close(handles[handle]);
handles[handle] = NULL;
diff --git a/tools/xenstore/xs_watch_stress.c b/tools/xenstore/xs_watch_stress.c
new file mode 100644
index 0000000000..91431e2376
--- /dev/null
+++ b/tools/xenstore/xs_watch_stress.c
@@ -0,0 +1,120 @@
+/* Stress test for watch code: two processes communicating by watches */
+#include "xs.h"
+#include "utils.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ int childpid, status, fds[2];
+ bool parent;
+ unsigned int i, acks = 0;
+ struct xs_handle *h;
+ char *data;
+ unsigned int len;
+ const char *path, *otherpath;
+
+ pipe(fds);
+ childpid = fork();
+ if (childpid == -1)
+ barf_perror("Failed fork");
+ parent = (childpid != 0);
+
+ h = xs_daemon_open();
+ if (!h)
+ barf_perror("Could not connect to daemon");
+
+ if (!xs_watch(h, "/", "token", 0))
+ barf_perror("Could not set watch");
+
+ if (parent) {
+ char c;
+
+ if (read(fds[0], &c, 1) != 1)
+ barf("Child exited");
+
+ path = "/parent";
+ otherpath = "/child";
+ /* Create initial node. */
+ if (!xs_write(h, path, "0", 2, O_CREAT))
+ barf_perror("Write to %s failed", path);
+ } else {
+ path = "/child";
+ otherpath = "/parent";
+
+ if (write(fds[1], "", 1) != 1)
+ barf_perror("Write to parent failed");
+ }
+
+ for (i = 0; i < (argv[1] ? (unsigned)atoi(argv[1]) : 100);) {
+ char **vec;
+
+ vec = xs_read_watch(h);
+ if (!vec)
+ barf_perror("Read watch failed");
+
+ if (!streq(vec[1], "token"))
+ barf("Watch token %s bad", vec[1]);
+ if (streq(vec[0], otherpath)) {
+ char number[32];
+
+ data = xs_read(h, otherpath, &len);
+ if (!data)
+ barf_perror("reading %s", otherpath);
+ sprintf(number, "%i", atoi(data) + 1);
+ free(data);
+ if (!xs_write(h, path, number, strlen(number) + 1,
+ O_CREAT))
+ barf_perror("writing %s", path);
+ i++;
+ } else if (!streq(vec[0], path))
+ barf_perror("Watch fired on unknown path %s", vec[0]);
+ xs_acknowledge_watch(h, vec[1]);
+ acks++;
+ free(vec);
+ }
+
+ if (!parent) {
+ while (acks != 2 * i - 1) {
+ char **vec;
+ vec = xs_read_watch(h);
+ if (!vec)
+ barf_perror("Watch failed");
+ if (!streq(vec[0], path))
+ barf_perror("Watch fired path %s", vec[0]);
+ if (!streq(vec[1], "token"))
+ barf("Watch token %s bad", vec[1]);
+ free(vec);
+
+ printf("Expect %i events, only got %i\n",
+ 2 * i - 1, acks);
+ acks++;
+ }
+ exit(0);
+ }
+
+ if (acks != 2 * i)
+ barf("Parent got %i watch events\n", acks);
+
+ printf("Waiting for %i\n", childpid);
+ if (waitpid(childpid, &status, 0) != childpid)
+ barf_perror("Child wait failed");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ barf_perror("Child status %i", status);
+
+ data = xs_read(h, path, &len);
+ if (atoi(data) != 2 * (int)i)
+ barf("%s count is %s\n", path, data);
+ free(data);
+ data = xs_read(h, otherpath, &len);
+ if (atoi(data) != 2 * (int)i - 1)
+ barf("%s count is %s\n", otherpath, data);
+ free(data);
+ printf("Success!\n");
+ exit(0);
+}
diff --git a/xen/Makefile b/xen/Makefile
index e71898cf4d..16ba9c2046 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -46,6 +46,7 @@ clean: delete-unfresh-files
$(MAKE) -C tools clean
$(MAKE) -C common clean
$(MAKE) -C drivers clean
+ $(MAKE) -C acm clean
$(MAKE) -C arch/$(TARGET_ARCH) clean
rm -f include/asm *.o $(TARGET)* *~ core
rm -f include/asm-*/asm-offsets.h
@@ -58,6 +59,9 @@ $(TARGET): delete-unfresh-files
$(MAKE) include/asm-$(TARGET_ARCH)/asm-offsets.h
$(MAKE) -C common
$(MAKE) -C drivers
+ifdef ACM_USE_SECURITY_POLICY
+ $(MAKE) -C acm
+endif
$(MAKE) -C arch/$(TARGET_ARCH)
# drivers/char/console.o may contain static banner/compile info. Blow it away.
@@ -109,7 +113,7 @@ include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s
.PHONY: default debug install dist clean delete-unfresh-files TAGS tags
-SUBDIRS = arch/$(TARGET_ARCH) common drivers
+SUBDIRS = acm arch/$(TARGET_ARCH) common drivers
define all_sources
( find include/asm-$(TARGET_ARCH) -name SCCS -prune -o -name '*.h' -print; \
find include -type d -name SCCS -prune -o \( -name "asm-*" -o \
diff --git a/xen/Rules.mk b/xen/Rules.mk
index 221882814a..76489cfa4b 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -35,6 +35,9 @@ OBJS += $(patsubst %.c,%.o,$(C_SRCS))
ALL_OBJS := $(BASEDIR)/common/common.o
ALL_OBJS += $(BASEDIR)/drivers/char/driver.o
ALL_OBJS += $(BASEDIR)/drivers/acpi/driver.o
+ifdef ACM_USE_SECURITY_POLICY
+ALL_OBJS += $(BASEDIR)/acm/acm.o
+endif
ALL_OBJS += $(BASEDIR)/arch/$(TARGET_ARCH)/arch.o
diff --git a/xen/acm/Makefile b/xen/acm/Makefile
new file mode 100644
index 0000000000..b212041afa
--- /dev/null
+++ b/xen/acm/Makefile
@@ -0,0 +1,15 @@
+
+include $(BASEDIR)/Rules.mk
+OBJS = acm_core.o
+OBJS += acm_policy.o
+OBJS += acm_simple_type_enforcement_hooks.o
+OBJS += acm_chinesewall_hooks.o
+OBJS += acm_null_hooks.o
+
+default: acm.o
+
+acm.o: $(OBJS)
+ $(LD) $(LDFLAGS) -r -o acm.o $(OBJS)
+
+clean:
+ rm -f *.o *~ core
diff --git a/xen/acm/acm_chinesewall_hooks.c b/xen/acm/acm_chinesewall_hooks.c
new file mode 100644
index 0000000000..938716d3f9
--- /dev/null
+++ b/xen/acm/acm_chinesewall_hooks.c
@@ -0,0 +1,503 @@
+/****************************************************************
+ * acm_chinesewall_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype Chinese Wall Policy for Xen
+ * This code implements the hooks that are called
+ * throughout Xen operations and decides authorization
+ * based on domain types and Chinese Wall conflict type
+ * sets. The CHWALL policy decides if a new domain can be started
+ * based on the types of running domains and the type of the
+ * new domain to be started. If the new domain's type is in
+ * conflict with types of running domains, then this new domain
+ * is not allowed to be created. A domain can have multiple types,
+ * in which case all types of a new domain must be conflict-free
+ * with all types of already running domains.
+ *
+ */
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/acm.h>
+#include <asm/atomic.h>
+#include <acm/acm_core.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+/* local cache structures for chinese wall policy */
+struct chwall_binary_policy chwall_bin_pol;
+
+/*
+ * Initializing chinese wall policy (will be filled by policy partition
+ * using setpolicy command)
+ */
+int acm_init_chwall_policy(void)
+{
+ /* minimal startup policy; policy write-locked already */
+ chwall_bin_pol.max_types = 1;
+ chwall_bin_pol.max_ssidrefs = 1;
+ chwall_bin_pol.max_conflictsets = 1;
+ chwall_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types);
+ chwall_bin_pol.conflict_sets = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types);
+ chwall_bin_pol.running_types = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
+ chwall_bin_pol.conflict_aggregate_set = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
+
+ if ((chwall_bin_pol.conflict_sets == NULL) || (chwall_bin_pol.running_types == NULL) ||
+ (chwall_bin_pol.ssidrefs == NULL) || (chwall_bin_pol.conflict_aggregate_set == NULL))
+ return ACM_INIT_SSID_ERROR;
+
+ /* initialize state */
+ memset((void *)chwall_bin_pol.ssidrefs, 0, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types*sizeof(domaintype_t));
+ memset((void *)chwall_bin_pol.conflict_sets, 0, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types*sizeof(domaintype_t));
+ memset((void *)chwall_bin_pol.running_types, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
+ memset((void *)chwall_bin_pol.conflict_aggregate_set, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
+ return ACM_OK;
+}
+
+static int
+chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
+{
+ struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
+ traceprintk("%s.\n", __func__);
+ if (chwall_ssidp == NULL)
+ return ACM_INIT_SSID_ERROR;
+ /*
+ * depending on wheter chwall is primary or secondary, get the respective
+ * part of the global ssidref (same way we'll get the partial ssid pointer)
+ */
+ chwall_ssidp->chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ if (chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
+ printkd("%s: ERROR chwall_ssidref(%x) > max(%x).\n",
+ __func__, chwall_ssidp->chwall_ssidref, chwall_bin_pol.max_ssidrefs-1);
+ xfree(chwall_ssidp);
+ return ACM_INIT_SSID_ERROR;
+ }
+ (*chwall_ssid) = chwall_ssidp;
+ printkd("%s: determined chwall_ssidref to %x.\n",
+ __func__, chwall_ssidp->chwall_ssidref);
+ return ACM_OK;
+}
+
+static void
+chwall_free_domain_ssid(void *chwall_ssid)
+{
+ traceprintk("%s.\n", __func__);
+ if (chwall_ssid != NULL)
+ xfree(chwall_ssid);
+ return;
+}
+
+
+/* dump chinese wall cache; policy read-locked already */
+static int
+chwall_dump_policy(u8 *buf, u16 buf_size) {
+ struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
+ int ret = 0;
+
+ chwall_buf->chwall_max_types = htons(chwall_bin_pol.max_types);
+ chwall_buf->chwall_max_ssidrefs = htons(chwall_bin_pol.max_ssidrefs);
+ chwall_buf->policy_code = htons(ACM_CHINESE_WALL_POLICY);
+ chwall_buf->chwall_ssid_offset = htons(sizeof(struct acm_chwall_policy_buffer));
+ chwall_buf->chwall_max_conflictsets = htons(chwall_bin_pol.max_conflictsets);
+ chwall_buf->chwall_conflict_sets_offset =
+ htons(
+ ntohs(chwall_buf->chwall_ssid_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs *
+ chwall_bin_pol.max_types);
+
+ chwall_buf->chwall_running_types_offset =
+ htons(
+ ntohs(chwall_buf->chwall_conflict_sets_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets *
+ chwall_bin_pol.max_types);
+
+ chwall_buf->chwall_conflict_aggregate_offset =
+ htons(
+ ntohs(chwall_buf->chwall_running_types_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_types);
+
+ ret = ntohs(chwall_buf->chwall_conflict_aggregate_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_types;
+
+ /* now copy buffers over */
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_ssid_offset)),
+ chwall_bin_pol.ssidrefs,
+ chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types);
+
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_conflict_sets_offset)),
+ chwall_bin_pol.conflict_sets,
+ chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types);
+
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_running_types_offset)),
+ chwall_bin_pol.running_types,
+ chwall_bin_pol.max_types);
+
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_conflict_aggregate_offset)),
+ chwall_bin_pol.conflict_aggregate_set,
+ chwall_bin_pol.max_types);
+ return ret;
+}
+
+/* adapt security state (running_types and conflict_aggregate_set) to all running
+ * domains; chwall_init_state is called when a policy is changed to bring the security
+ * information into a consistent state and to detect violations (return != 0).
+ * from a security point of view, we simulate that all running domains are re-started
+ */
+static int
+chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, domaintype_t *ssidrefs, domaintype_t *conflict_sets,
+ domaintype_t *running_types, domaintype_t *conflict_aggregate_set)
+{
+ int violation = 0, i, j;
+ struct chwall_ssid *chwall_ssid;
+ ssidref_t chwall_ssidref;
+ struct domain **pd;
+
+ write_lock(&domlist_lock);
+ /* go through all domains and adjust policy as if this domain was started now */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ chwall_ssid = GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)(*pd)->ssid);
+ chwall_ssidref = chwall_ssid->chwall_ssidref;
+ traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
+ __func__, (*pd)->domain_id, chwall_ssidref);
+ /* a) adjust types ref-count for running domains */
+ for (i=0; i< chwall_buf->chwall_max_types; i++)
+ running_types[i] +=
+ ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i];
+
+ /* b) check for conflict */
+ for (i=0; i< chwall_buf->chwall_max_types; i++)
+ if (conflict_aggregate_set[i] &&
+ ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i]) {
+ printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
+ violation = 1;
+ goto out;
+ }
+ /* set violation and break out of the loop */
+ /* c) adapt conflict aggregate set for this domain (notice conflicts) */
+ for (i=0; i<chwall_buf->chwall_max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_buf->chwall_max_types; j++)
+ if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
+ ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_buf->chwall_max_types; j++)
+ if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
+ !ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j])
+ conflict_aggregate_set[j]++;
+ }
+ }
+ out:
+ write_unlock(&domlist_lock);
+ return violation;
+ /* returning "violation != 0" means that the currently running set of domains would
+ * not be possible if the new policy had been enforced before starting them; for chinese
+ * wall, this means that the new policy includes at least one conflict set of which
+ * more than one type is currently running */
+}
+
+static int
+chwall_set_policy(u8 *buf, u16 buf_size)
+{
+ /* policy write-locked already */
+ struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
+ void *ssids = NULL, *conflict_sets = NULL, *running_types = NULL, *conflict_aggregate_set = NULL;
+
+ /* rewrite the policy due to endianess */
+ chwall_buf->policy_code = ntohs(chwall_buf->policy_code);
+ chwall_buf->chwall_max_types = ntohs(chwall_buf->chwall_max_types);
+ chwall_buf->chwall_max_ssidrefs = ntohs(chwall_buf->chwall_max_ssidrefs);
+ chwall_buf->chwall_max_conflictsets = ntohs(chwall_buf->chwall_max_conflictsets);
+ chwall_buf->chwall_ssid_offset = ntohs(chwall_buf->chwall_ssid_offset);
+ chwall_buf->chwall_conflict_sets_offset = ntohs(chwall_buf->chwall_conflict_sets_offset);
+ chwall_buf->chwall_running_types_offset = ntohs(chwall_buf->chwall_running_types_offset);
+ chwall_buf->chwall_conflict_aggregate_offset = ntohs(chwall_buf->chwall_conflict_aggregate_offset);
+
+ /* 1. allocate new buffers */
+ ssids = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types*chwall_buf->chwall_max_ssidrefs);
+ conflict_sets = xmalloc_array(domaintype_t, chwall_buf->chwall_max_conflictsets*chwall_buf->chwall_max_types);
+ running_types = xmalloc_array(domaintype_t,chwall_buf->chwall_max_types);
+ conflict_aggregate_set = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
+
+ if ((ssids == NULL)||(conflict_sets == NULL)||(running_types == NULL)||(conflict_aggregate_set == NULL))
+ goto error_free;
+
+ /* 2. set new policy */
+ if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) *
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs > buf_size)
+ goto error_free;
+ arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset,
+ sizeof(domaintype_t),
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs);
+
+ if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) *
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets > buf_size)
+ goto error_free;
+
+ arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset,
+ sizeof(domaintype_t),
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets);
+
+ /* we also use new state buffers since max_types can change */
+ memset(running_types, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
+ memset(conflict_aggregate_set, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
+
+ /* 3. now re-calculate the state for the new policy based on running domains;
+ * this can fail if new policy is conflicting with running domains */
+ if (chwall_init_state(chwall_buf, ssids, conflict_sets, running_types, conflict_aggregate_set)) {
+ printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
+ goto error_free; /* new policy conflicts with running domains */
+ }
+ /* 4. free old policy buffers, replace with new ones */
+ chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
+ chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
+ chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets;
+ if (chwall_bin_pol.ssidrefs != NULL)
+ xfree(chwall_bin_pol.ssidrefs);
+ if (chwall_bin_pol.conflict_aggregate_set != NULL)
+ xfree(chwall_bin_pol.conflict_aggregate_set);
+ if (chwall_bin_pol.running_types != NULL)
+ xfree(chwall_bin_pol.running_types);
+ if (chwall_bin_pol.conflict_sets != NULL)
+ xfree(chwall_bin_pol.conflict_sets);
+ chwall_bin_pol.ssidrefs = ssids;
+ chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set;
+ chwall_bin_pol.running_types = running_types;
+ chwall_bin_pol.conflict_sets = conflict_sets;
+ return ACM_OK;
+
+error_free:
+ printk("%s: ERROR setting policy.\n", __func__);
+ if (ssids != NULL) xfree(ssids);
+ if (conflict_sets != NULL) xfree(conflict_sets);
+ if (running_types != NULL) xfree(running_types);
+ if (conflict_aggregate_set != NULL) xfree(conflict_aggregate_set);
+ return -EFAULT;
+}
+
+static int
+chwall_dump_stats(u8 *buf, u16 len)
+{
+ /* no stats for Chinese Wall Policy */
+ return 0;
+}
+
+/***************************
+ * Authorization functions
+ ***************************/
+
+
+/* -------- DOMAIN OPERATION HOOKS -----------*/
+
+static int
+chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ ssidref_t chwall_ssidref;
+ int i,j;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) {
+ printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED; /* catching and indicating config error */
+ }
+ if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
+ printk("%s: ERROR chwall_ssidref > max(%x).\n",
+ __func__, chwall_bin_pol.max_ssidrefs-1);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED;
+ }
+ /* A: chinese wall check for conflicts */
+ for (i=0; i< chwall_bin_pol.max_types; i++)
+ if (chwall_bin_pol.conflict_aggregate_set[i] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i]) {
+ printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED;
+ }
+
+ /* B: chinese wall conflict set adjustment (so that other
+ * other domains simultaneously created are evaluated against this new set)*/
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]++;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_PERMITTED;
+}
+
+static void
+chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
+{
+ int i,j;
+ ssidref_t chwall_ssidref;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ /* adjust types ref-count for running domains */
+ for (i=0; i< chwall_bin_pol.max_types; i++)
+ chwall_bin_pol.running_types[i] +=
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
+ if (domid) {
+ read_unlock(&acm_bin_pol_rwlock);
+ return;
+ }
+ /* Xen does not call pre-create hook for DOM0;
+ * to consider type conflicts of any domain with DOM0, we need
+ * to adjust the conflict_aggregate for DOM0 here the same way it
+ * is done for non-DOM0 domains in the pre-hook */
+ printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n",
+ __func__, ssidref, chwall_ssidref);
+
+ /* chinese wall conflict set adjustment (so that other
+ * other domains simultaneously created are evaluated against this new set)*/
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]++;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return;
+}
+
+static void
+chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ int i, j;
+ ssidref_t chwall_ssidref;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ /* roll-back: re-adjust conflicting types aggregate */
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]--;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+}
+
+
+static void
+chwall_post_domain_destroy(void *object_ssid, domid_t id)
+{
+ int i,j;
+ struct chwall_ssid *chwall_ssidp =
+ GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)object_ssid);
+ ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref;
+
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ /* adjust running types set */
+ for (i=0; i< chwall_bin_pol.max_types; i++)
+ chwall_bin_pol.running_types[i] -=
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
+
+ /* roll-back: re-adjust conflicting types aggregate */
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]--;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return;
+}
+
+struct acm_operations acm_chinesewall_ops = {
+ /* policy management services */
+ .init_domain_ssid = chwall_init_domain_ssid,
+ .free_domain_ssid = chwall_free_domain_ssid,
+ .dump_binary_policy = chwall_dump_policy,
+ .set_binary_policy = chwall_set_policy,
+ .dump_statistics = chwall_dump_stats,
+ /* domain management control hooks */
+ .pre_domain_create = chwall_pre_domain_create,
+ .post_domain_create = chwall_post_domain_create,
+ .fail_domain_create = chwall_fail_domain_create,
+ .post_domain_destroy = chwall_post_domain_destroy,
+ /* event channel control hooks */
+ .pre_eventchannel_unbound = NULL,
+ .fail_eventchannel_unbound = NULL,
+ .pre_eventchannel_interdomain = NULL,
+ .fail_eventchannel_interdomain = NULL,
+ /* grant table control hooks */
+ .pre_grant_map_ref = NULL,
+ .fail_grant_map_ref = NULL,
+ .pre_grant_setup = NULL,
+ .fail_grant_setup = NULL,
+};
diff --git a/xen/acm/acm_core.c b/xen/acm/acm_core.c
new file mode 100644
index 0000000000..fe5bacdb6d
--- /dev/null
+++ b/xen/acm/acm_core.c
@@ -0,0 +1,205 @@
+/****************************************************************
+ * acm_core.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype access control module (ACM)
+ * This file handles initialization of the ACM
+ * as well as initializing/freeing security
+ * identifiers for domains (it calls on active
+ * policy hook functions).
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+/* debug:
+ * include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE;
+ * define/undefine this constant to receive / suppress any
+ * security hook debug output of sHype
+ *
+ * include/public/acm.h defines a constant ACM_DEBUG
+ * define/undefine this constant to receive non-hook-related
+ * debug output.
+ */
+
+/* function prototypes */
+void acm_init_chwall_policy(void);
+void acm_init_ste_policy(void);
+
+extern struct acm_operations acm_chinesewall_ops,
+ acm_simple_type_enforcement_ops, acm_null_ops;
+
+/* global ops structs called by the hooks */
+struct acm_operations *acm_primary_ops = NULL;
+/* called in hook if-and-only-if primary succeeds */
+struct acm_operations *acm_secondary_ops = NULL;
+
+/* acm global binary policy (points to 'local' primary and secondary policies */
+struct acm_binary_policy acm_bin_pol;
+/* acm binary policy lock */
+rwlock_t acm_bin_pol_rwlock = RW_LOCK_UNLOCKED;
+
+/* until we have endian support in Xen, we discover it at runtime */
+u8 little_endian = 1;
+void acm_set_endian(void)
+{
+ u32 test = 1;
+ if (*((u8 *)&test) == 1) {
+ printk("ACM module running in LITTLE ENDIAN.\n");
+ little_endian = 1;
+ } else {
+ printk("ACM module running in BIG ENDIAN.\n");
+ little_endian = 0;
+ }
+}
+
+/* initialize global security policy for Xen; policy write-locked already */
+static void
+acm_init_binary_policy(void *primary, void *secondary)
+{
+ acm_bin_pol.primary_policy_code = 0;
+ acm_bin_pol.secondary_policy_code = 0;
+ acm_bin_pol.primary_binary_policy = primary;
+ acm_bin_pol.secondary_binary_policy = secondary;
+}
+
+int
+acm_init(void)
+{
+ int ret = -EINVAL;
+
+ acm_set_endian();
+ write_lock(&acm_bin_pol_rwlock);
+
+ if (ACM_USE_SECURITY_POLICY == ACM_CHINESE_WALL_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_init_chwall_policy();
+ acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
+ acm_primary_ops = &acm_chinesewall_ops;
+ acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+ acm_secondary_ops = &acm_null_ops;
+ ret = ACM_OK;
+ } else if (ACM_USE_SECURITY_POLICY == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_init_ste_policy();
+ acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ acm_primary_ops = &acm_simple_type_enforcement_ops;
+ acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+ acm_secondary_ops = &acm_null_ops;
+ ret = ACM_OK;
+ } else if (ACM_USE_SECURITY_POLICY == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_init_chwall_policy();
+ acm_init_ste_policy();
+ acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
+ acm_primary_ops = &acm_chinesewall_ops;
+ acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ acm_secondary_ops = &acm_simple_type_enforcement_ops;
+ ret = ACM_OK;
+ } else if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
+ acm_primary_ops = &acm_null_ops;
+ acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+ acm_secondary_ops = &acm_null_ops;
+ ret = ACM_OK;
+ }
+ write_unlock(&acm_bin_pol_rwlock);
+
+ if (ret != ACM_OK)
+ return -EINVAL;
+ printk("%s: Enforcing Primary %s, Secondary %s.\n", __func__,
+ ACM_POLICY_NAME(acm_bin_pol.primary_policy_code), ACM_POLICY_NAME(acm_bin_pol.secondary_policy_code));
+ return ACM_OK;
+}
+
+
+int
+acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
+{
+ struct acm_ssid_domain *ssid;
+ struct domain *subj = find_domain_by_id(id);
+ int ret1, ret2;
+
+ if (subj == NULL) {
+ printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
+ return ACM_NULL_POINTER_ERROR;
+ }
+ if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
+ return ACM_INIT_SSID_ERROR;
+
+ ssid->datatype = DOMAIN;
+ ssid->subject = subj;
+ ssid->domainid = subj->domain_id;
+ ssid->primary_ssid = NULL;
+ ssid->secondary_ssid = NULL;
+
+ if (ACM_USE_SECURITY_POLICY != ACM_NULL_POLICY)
+ ssid->ssidref = ssidref;
+ else
+ ssid->ssidref = ACM_DEFAULT_SSID;
+
+ subj->ssid = ssid;
+ /* now fill in primary and secondary parts; we only get here through hooks */
+ if (acm_primary_ops->init_domain_ssid != NULL)
+ ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
+ else
+ ret1 = ACM_OK;
+
+ if (acm_secondary_ops->init_domain_ssid != NULL)
+ ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
+ else
+ ret2 = ACM_OK;
+
+ if ((ret1 != ACM_OK) || (ret2 != ACM_OK)) {
+ printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
+ __func__, subj->domain_id);
+ acm_free_domain_ssid(ssid);
+ put_domain(subj);
+ return ACM_INIT_SSID_ERROR;
+ }
+ printk("%s: assigned domain %x the ssidref=%x.\n", __func__, id, ssid->ssidref);
+ put_domain(subj);
+ return ACM_OK;
+}
+
+
+int
+acm_free_domain_ssid(struct acm_ssid_domain *ssid)
+{
+ domid_t id;
+
+ /* domain is already gone, just ssid is left */
+ if (ssid == NULL) {
+ printk("%s: ACM_NULL_POINTER ERROR.\n", __func__);
+ return ACM_NULL_POINTER_ERROR;
+ }
+ id = ssid->domainid;
+ ssid->subject = NULL;
+
+ if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
+ acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
+ ssid->primary_ssid = NULL;
+ if (acm_secondary_ops->free_domain_ssid != NULL)
+ acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
+ ssid->secondary_ssid = NULL;
+ xfree(ssid);
+ printkd("%s: Freed individual domain ssid (domain=%02x).\n",__func__, id);
+ return ACM_OK;
+}
diff --git a/xen/acm/acm_null_hooks.c b/xen/acm/acm_null_hooks.c
new file mode 100644
index 0000000000..6433cbfed6
--- /dev/null
+++ b/xen/acm/acm_null_hooks.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * acm_null_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+#include <acm/acm_hooks.h>
+
+static int
+null_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
+{
+ return ACM_OK;
+}
+
+
+static void
+null_free_domain_ssid(void *chwall_ssid)
+{
+ return;
+}
+
+
+static int
+null_dump_binary_policy(u8 *buf, u16 buf_size)
+{
+ return 0;
+}
+
+
+
+static int
+null_set_binary_policy(u8 *buf, u16 buf_size)
+{
+ return -1;
+}
+
+
+static int
+null_dump_stats(u8 *buf, u16 buf_size)
+{
+ /* no stats for NULL policy */
+ return 0;
+}
+
+
+/* now define the hook structure similarly to LSM */
+struct acm_operations acm_null_ops = {
+ .init_domain_ssid = null_init_domain_ssid,
+ .free_domain_ssid = null_free_domain_ssid,
+ .dump_binary_policy = null_dump_binary_policy,
+ .set_binary_policy = null_set_binary_policy,
+ .dump_statistics = null_dump_stats,
+ /* domain management control hooks */
+ .pre_domain_create = NULL,
+ .post_domain_create = NULL,
+ .fail_domain_create = NULL,
+ .post_domain_destroy = NULL,
+ /* event channel control hooks */
+ .pre_eventchannel_unbound = NULL,
+ .fail_eventchannel_unbound = NULL,
+ .pre_eventchannel_interdomain = NULL,
+ .fail_eventchannel_interdomain = NULL,
+ /* grant table control hooks */
+ .pre_grant_map_ref = NULL,
+ .fail_grant_map_ref = NULL,
+ .pre_grant_setup = NULL,
+ .fail_grant_setup = NULL
+
+};
diff --git a/xen/acm/acm_policy.c b/xen/acm/acm_policy.c
new file mode 100644
index 0000000000..3e08130d43
--- /dev/null
+++ b/xen/acm/acm_policy.c
@@ -0,0 +1,197 @@
+/****************************************************************
+ * acm_policy.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * support for network-byte-order binary policies
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * sHype access control policy management for Xen.
+ * This interface allows policy tools in authorized
+ * domains to interact with the Xen access control module
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/policy_ops.h>
+#include <acm/acm_core.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+int
+acm_set_policy(void *buf, u16 buf_size, u16 policy)
+{
+ u8 *policy_buffer = NULL;
+ struct acm_policy_buffer *pol;
+
+ if (policy != ACM_USE_SECURITY_POLICY) {
+ printk("%s: Loading incompatible policy (running: %s).\n", __func__,
+ ACM_POLICY_NAME(ACM_USE_SECURITY_POLICY));
+ return -EFAULT;
+ }
+ /* now check correct buffer sizes for policy combinations */
+ if (policy == ACM_NULL_POLICY) {
+ printkd("%s: NULL Policy, no policy needed.\n", __func__);
+ goto out;
+ }
+ if (buf_size < sizeof(struct acm_policy_buffer))
+ return -EFAULT;
+ /* 1. copy buffer from domain */
+ if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
+ goto error_free;
+ if (copy_from_user(policy_buffer, buf, buf_size)) {
+ printk("%s: Error copying!\n",__func__);
+ goto error_free;
+ }
+ /* 2. some sanity checking */
+ pol = (struct acm_policy_buffer *)policy_buffer;
+
+ if ((ntohl(pol->magic) != ACM_MAGIC) ||
+ (ntohs(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) ||
+ (ntohs(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code)) {
+ printkd("%s: Wrong policy magics!\n", __func__);
+ goto error_free;
+ }
+ if (buf_size != ntohl(pol->len)) {
+ printk("%s: ERROR in buf size.\n", __func__);
+ goto error_free;
+ }
+
+ /* get bin_policy lock and rewrite policy (release old one) */
+ write_lock(&acm_bin_pol_rwlock);
+
+ /* 3. now get/set primary policy data */
+ if (acm_primary_ops->set_binary_policy(buf + ntohs(pol->primary_buffer_offset),
+ ntohs(pol->secondary_buffer_offset) -
+ ntohs(pol->primary_buffer_offset))) {
+ goto error_lock_free;
+ }
+ /* 4. now get/set secondary policy data */
+ if (acm_secondary_ops->set_binary_policy(buf + ntohs(pol->secondary_buffer_offset),
+ ntohl(pol->len) -
+ ntohs(pol->secondary_buffer_offset))) {
+ goto error_lock_free;
+ }
+ write_unlock(&acm_bin_pol_rwlock);
+ out:
+ printk("%s: Done .\n", __func__);
+ if (policy_buffer != NULL)
+ xfree(policy_buffer);
+ return ACM_OK;
+
+ error_lock_free:
+ write_unlock(&acm_bin_pol_rwlock);
+ error_free:
+ printk("%s: Error setting policy.\n", __func__);
+ if (policy_buffer != NULL)
+ xfree(policy_buffer);
+ return -ENOMEM;
+}
+
+int
+acm_get_policy(void *buf, u16 buf_size)
+{
+ u8 *policy_buffer;
+ int ret;
+ struct acm_policy_buffer *bin_pol;
+
+ if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
+ return -ENOMEM;
+
+ read_lock(&acm_bin_pol_rwlock);
+ /* future: read policy from file and set it */
+ bin_pol = (struct acm_policy_buffer *)policy_buffer;
+ bin_pol->magic = htonl(ACM_MAGIC);
+ bin_pol->policyversion = htonl(POLICY_INTERFACE_VERSION);
+ bin_pol->primary_policy_code = htons(acm_bin_pol.primary_policy_code);
+ bin_pol->secondary_policy_code = htons(acm_bin_pol.secondary_policy_code);
+
+ bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
+ bin_pol->primary_buffer_offset = htons(ntohl(bin_pol->len));
+ bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+
+ ret = acm_primary_ops->dump_binary_policy (policy_buffer + ntohs(bin_pol->primary_buffer_offset),
+ buf_size - ntohs(bin_pol->primary_buffer_offset));
+ if (ret < 0) {
+ printk("%s: ERROR creating chwallpolicy buffer.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+ bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+
+ ret = acm_secondary_ops->dump_binary_policy(policy_buffer + ntohs(bin_pol->secondary_buffer_offset),
+ buf_size - ntohs(bin_pol->secondary_buffer_offset));
+ if (ret < 0) {
+ printk("%s: ERROR creating chwallpolicy buffer.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+ read_unlock(&acm_bin_pol_rwlock);
+ if (copy_to_user(buf, policy_buffer, ntohl(bin_pol->len)))
+ return -EFAULT;
+ xfree(policy_buffer);
+ return ACM_OK;
+}
+
+int
+acm_dump_statistics(void *buf, u16 buf_size)
+{
+ /* send stats to user space */
+ u8 *stats_buffer;
+ int len1, len2;
+ struct acm_stats_buffer acm_stats;
+
+ if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL)
+ return -ENOMEM;
+
+ read_lock(&acm_bin_pol_rwlock);
+
+ len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer),
+ buf_size - sizeof(struct acm_stats_buffer));
+ if (len1 < 0)
+ goto error_lock_free;
+
+ len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1,
+ buf_size - sizeof(struct acm_stats_buffer) - len1);
+ if (len2 < 0)
+ goto error_lock_free;
+
+ acm_stats.magic = htonl(ACM_MAGIC);
+ acm_stats.policyversion = htonl(POLICY_INTERFACE_VERSION);
+ acm_stats.primary_policy_code = htons(acm_bin_pol.primary_policy_code);
+ acm_stats.secondary_policy_code = htons(acm_bin_pol.secondary_policy_code);
+ acm_stats.primary_stats_offset = htons(sizeof(struct acm_stats_buffer));
+ acm_stats.secondary_stats_offset = htons(sizeof(struct acm_stats_buffer) + len1);
+ acm_stats.len = htonl(sizeof(struct acm_stats_buffer) + len1 + len2);
+ memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
+
+ if (copy_to_user(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2))
+ goto error_lock_free;
+
+ read_unlock(&acm_bin_pol_rwlock);
+ xfree(stats_buffer);
+ return ACM_OK;
+
+ error_lock_free:
+ read_unlock(&acm_bin_pol_rwlock);
+ xfree(stats_buffer);
+ return -EFAULT;
+}
+
+/*eof*/
diff --git a/xen/acm/acm_simple_type_enforcement_hooks.c b/xen/acm/acm_simple_type_enforcement_hooks.c
new file mode 100644
index 0000000000..17e75deca8
--- /dev/null
+++ b/xen/acm/acm_simple_type_enforcement_hooks.c
@@ -0,0 +1,638 @@
+/****************************************************************
+ * acm_simple_type_enforcement_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * support for network order binary policies
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * sHype Simple Type Enforcement for Xen
+ * STE allows to control which domains can setup sharing
+ * (eventchannels right now) with which other domains. Hooks
+ * are defined and called throughout Xen when domains bind to
+ * shared resources (setup eventchannels) and a domain is allowed
+ * to setup sharing with another domain if and only if both domains
+ * share at least on common type.
+ *
+ */
+#include <xen/lib.h>
+#include <asm/types.h>
+#include <asm/current.h>
+#include <acm/acm_hooks.h>
+#include <asm/atomic.h>
+#include <acm/acm_endian.h>
+
+/* local cache structures for chinese wall policy */
+struct ste_binary_policy ste_bin_pol;
+
+static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
+ int i;
+ for(i=0; i< ste_bin_pol.max_types; i++)
+ if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
+ ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
+ printkd("%s: common type #%02x.\n", __func__, i);
+ return 1;
+ }
+ return 0;
+}
+
+/* Helper function: return = (subj and obj share a common type) */
+static int share_common_type(struct domain *subj, struct domain *obj)
+{
+ ssidref_t ref_s, ref_o;
+ int ret;
+
+ if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
+ return 0;
+ read_lock(&acm_bin_pol_rwlock);
+ /* lookup the policy-local ssids */
+ ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
+ ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
+ /* check whether subj and obj share a common ste type */
+ ret = have_common_type(ref_s, ref_o);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ret;
+}
+
+/*
+ * Initializing chinese wall policy (will be filled by policy partition
+ * using setpolicy command)
+ */
+int acm_init_ste_policy(void)
+{
+ /* minimal startup policy; policy write-locked already */
+ ste_bin_pol.max_types = 1;
+ ste_bin_pol.max_ssidrefs = 1;
+ ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 1);
+
+ if (ste_bin_pol.ssidrefs == NULL)
+ return ACM_INIT_SSID_ERROR;
+
+ /* initialize state */
+ ste_bin_pol.ssidrefs[0] = 1;
+
+ /* init stats */
+ atomic_set(&(ste_bin_pol.ec_eval_count), 0);
+ atomic_set(&(ste_bin_pol.ec_denied_count), 0);
+ atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
+ atomic_set(&(ste_bin_pol.gt_eval_count), 0);
+ atomic_set(&(ste_bin_pol.gt_denied_count), 0);
+ atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
+ return ACM_OK;
+}
+
+
+/* ste initialization function hooks */
+static int
+ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref)
+{
+ int i;
+ struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);
+ traceprintk("%s.\n", __func__);
+
+ if (ste_ssidp == NULL)
+ return ACM_INIT_SSID_ERROR;
+
+ /* get policy-local ssid reference */
+ ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
+ if (ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) {
+ printkd("%s: ERROR ste_ssidref (%x) > max(%x).\n",
+ __func__, ste_ssidp->ste_ssidref, ste_bin_pol.max_ssidrefs-1);
+ xfree(ste_ssidp);
+ return ACM_INIT_SSID_ERROR;
+ }
+ /* clean ste cache */
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ ste_ssidp->ste_cache[i].valid = FREE;
+
+ (*ste_ssid) = ste_ssidp;
+ printkd("%s: determined ste_ssidref to %x.\n",
+ __func__, ste_ssidp->ste_ssidref);
+ return ACM_OK;
+}
+
+
+static void
+ste_free_domain_ssid(void *ste_ssid)
+{
+ traceprintk("%s.\n", __func__);
+ if (ste_ssid != NULL)
+ xfree(ste_ssid);
+ return;
+}
+
+/* dump type enforcement cache; policy read-locked already */
+static int
+ste_dump_policy(u8 *buf, u16 buf_size) {
+ struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
+ int ret = 0;
+
+ ste_buf->ste_max_types = htons(ste_bin_pol.max_types);
+ ste_buf->ste_max_ssidrefs = htons(ste_bin_pol.max_ssidrefs);
+ ste_buf->policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+ ste_buf->ste_ssid_offset = htons(sizeof(struct acm_ste_policy_buffer));
+ ret = ntohs(ste_buf->ste_ssid_offset) +
+ sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
+
+ /* now copy buffer over */
+ arrcpy(buf + ntohs(ste_buf->ste_ssid_offset),
+ ste_bin_pol.ssidrefs,
+ sizeof(domaintype_t),
+ ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
+
+ return ret;
+}
+
+/* ste_init_state is called when a policy is changed to detect violations (return != 0).
+ * from a security point of view, we simulate that all running domains are re-started and
+ * all sharing decisions are replayed to detect violations or current sharing behavior
+ * (right now: event_channels, future: also grant_tables)
+ */
+static int
+ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
+{
+ int violation = 1;
+ struct ste_ssid *ste_ssid, *ste_rssid;
+ ssidref_t ste_ssidref, ste_rssidref;
+ struct domain **pd, *rdom;
+ domid_t rdomid;
+ grant_entry_t sha_copy;
+ int port, i;
+
+ read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
+ /* go through all domains and adjust policy as if this domain was started now */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ ste_ssidref = ste_ssid->ste_ssidref;
+ traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
+ __func__, (*pd)->domain_id, ste_ssidref);
+ /* a) check for event channel conflicts */
+ for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
+ spin_lock(&(*pd)->evtchn_lock);
+ if ((*pd)->evtchn[port] == NULL) {
+ spin_unlock(&(*pd)->evtchn_lock);
+ continue;
+ }
+ if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
+ rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
+ rdomid = rdom->domain_id;
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ } else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
+ rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
+ if ((rdom = find_domain_by_id(rdomid)) == NULL) {
+ printk("%s: Error finding domain to id %x!\n", __func__, rdomid);
+ goto out;
+ }
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ put_domain(rdom);
+ } else {
+ spin_unlock(&(*pd)->evtchn_lock);
+ continue; /* port unused */
+ }
+ spin_unlock(&(*pd)->evtchn_lock);
+
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n",
+ __func__, (*pd)->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);
+ /* check whether on subj->ssid, obj->ssid share a common type*/
+ if (!have_common_type(ste_ssidref, ste_rssidref)) {
+ printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
+ __func__, (*pd)->domain_id, rdomid);
+ goto out;
+ }
+ }
+ /* b) check for grant table conflicts on shared pages */
+ if ((*pd)->grant_table->shared == NULL) {
+ printkd("%s: Grant ... sharing for domain %x not setup!\n", __func__, (*pd)->domain_id);
+ continue;
+ }
+ for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) {
+ sha_copy = (*pd)->grant_table->shared[i];
+ if ( sha_copy.flags ) {
+ printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
+ __func__, (*pd)->domain_id, i, sha_copy.flags, sha_copy.domid,
+ (unsigned long)sha_copy.frame);
+ rdomid = sha_copy.domid;
+ if ((rdom = find_domain_by_id(rdomid)) == NULL) {
+ printkd("%s: domain not found ERROR!\n", __func__);
+ goto out;
+ };
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ put_domain(rdom);
+ if (!have_common_type(ste_ssidref, ste_rssidref)) {
+ printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
+ __func__, (*pd)->domain_id, rdomid);
+ goto out;
+ }
+ }
+ }
+ }
+ violation = 0;
+ out:
+ read_unlock(&domlist_lock);
+ return violation;
+ /* returning "violation != 0" means that existing sharing between domains would not
+ * have been allowed if the new policy had been enforced before the sharing; for ste,
+ * this means that there are at least 2 domains that have established sharing through
+ * event-channels or grant-tables but these two domains don't have no longer a common
+ * type in their typesets referenced by their ssidrefs */
+}
+
+/* set new policy; policy write-locked already */
+static int
+ste_set_policy(u8 *buf, u16 buf_size)
+{
+ struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
+ void *ssidrefsbuf;
+ struct ste_ssid *ste_ssid;
+ struct domain **pd;
+ int i;
+
+ /* Convert endianess of policy */
+ ste_buf->policy_code = ntohs(ste_buf->policy_code);
+ ste_buf->ste_max_types = ntohs(ste_buf->ste_max_types);
+ ste_buf->ste_max_ssidrefs = ntohs(ste_buf->ste_max_ssidrefs);
+ ste_buf->ste_ssid_offset = ntohs(ste_buf->ste_ssid_offset);
+
+ /* 1. create and copy-in new ssidrefs buffer */
+ ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
+ if (ssidrefsbuf == NULL) {
+ return -ENOMEM;
+ }
+ if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
+ goto error_free;
+
+ arrcpy(ssidrefsbuf,
+ buf + ste_buf->ste_ssid_offset,
+ sizeof(domaintype_t),
+ ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
+
+ /* 2. now re-calculate sharing decisions based on running domains;
+ * this can fail if new policy is conflicting with sharing of running domains
+ * now: reject violating new policy; future: adjust sharing through revoking sharing */
+ if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
+ printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
+ goto error_free; /* new policy conflicts with sharing of running domains */
+ }
+ /* 3. replace old policy (activate new policy) */
+ ste_bin_pol.max_types = ste_buf->ste_max_types;
+ ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
+ if (ste_bin_pol.ssidrefs)
+ xfree(ste_bin_pol.ssidrefs);
+ ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
+
+ /* clear all ste caches */
+ read_lock(&domlist_lock);
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ ste_ssid->ste_cache[i].valid = FREE;
+ }
+ read_unlock(&domlist_lock);
+ return ACM_OK;
+
+error_free:
+ printk("%s: ERROR setting policy.\n", __func__);
+ if (ssidrefsbuf != NULL) xfree(ssidrefsbuf);
+ return -EFAULT;
+}
+
+static int
+ste_dump_stats(u8 *buf, u16 buf_len)
+{
+ struct acm_ste_stats_buffer stats;
+
+#ifdef ACM_DEBUG
+ int i;
+ struct ste_ssid *ste_ssid;
+ struct domain **pd;
+
+ printk("ste: Decision caches:\n");
+ /* go through all domains and adjust policy as if this domain was started now */
+ read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ printk("ste: Cache Domain %02x.\n", (*pd)->domain_id);
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ printk("\t\tcache[%02x] = %s, domid=%x.\n", i,
+ (ste_ssid->ste_cache[i].valid == VALID) ?
+ "VALID" : "FREE",
+ (ste_ssid->ste_cache[i].valid == VALID) ?
+ ste_ssid->ste_cache[i].id : 0xffffffff);
+ }
+ read_unlock(&domlist_lock);
+ /* init stats */
+ printk("STE-Policy Security Hook Statistics:\n");
+ printk("ste: event_channel eval_count = %x\n", atomic_read(&(ste_bin_pol.ec_eval_count)));
+ printk("ste: event_channel denied_count = %x\n", atomic_read(&(ste_bin_pol.ec_denied_count)));
+ printk("ste: event_channel cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.ec_cachehit_count)));
+ printk("ste:\n");
+ printk("ste: grant_table eval_count = %x\n", atomic_read(&(ste_bin_pol.gt_eval_count)));
+ printk("ste: grant_table denied_count = %x\n", atomic_read(&(ste_bin_pol.gt_denied_count)));
+ printk("ste: grant_table cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.gt_cachehit_count)));
+#endif
+
+ if (buf_len < sizeof(struct acm_ste_stats_buffer))
+ return -ENOMEM;
+
+ /* now send the hook counts to user space */
+ stats.ec_eval_count = htonl(atomic_read(&ste_bin_pol.ec_eval_count));
+ stats.gt_eval_count = htonl(atomic_read(&ste_bin_pol.gt_eval_count));
+ stats.ec_denied_count = htonl(atomic_read(&ste_bin_pol.ec_denied_count));
+ stats.gt_denied_count = htonl(atomic_read(&ste_bin_pol.gt_denied_count));
+ stats.ec_cachehit_count = htonl(atomic_read(&ste_bin_pol.ec_cachehit_count));
+ stats.gt_cachehit_count = htonl(atomic_read(&ste_bin_pol.gt_cachehit_count));
+ memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
+ return sizeof(struct acm_ste_stats_buffer);
+}
+
+
+/* we need to go through this before calling the hooks,
+ * returns 1 == cache hit */
+static int inline
+check_cache(struct domain *dom, domid_t rdom) {
+ struct ste_ssid *ste_ssid;
+ int i;
+
+ printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(dom)->ssid);
+
+ for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
+ if ((ste_ssid->ste_cache[i].valid == VALID) &&
+ (ste_ssid->ste_cache[i].id == rdom)) {
+ printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* we only get here if there is NO entry yet; no duplication check! */
+static void inline
+cache_result(struct domain *subj, struct domain *obj) {
+ struct ste_ssid *ste_ssid;
+ int i;
+ printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(subj)->ssid);
+ for(i=0; i< ACM_TE_CACHE_SIZE; i++)
+ if (ste_ssid->ste_cache[i].valid == FREE)
+ break;
+ if (i< ACM_TE_CACHE_SIZE) {
+ ste_ssid->ste_cache[i].valid = VALID;
+ ste_ssid->ste_cache[i].id = obj->domain_id;
+ } else
+ printk ("Cache of dom %x is full!\n", subj->domain_id);
+}
+
+/* deletes entries for domain 'id' from all caches (re-use) */
+static void inline
+clean_id_from_cache(domid_t id)
+{
+ struct ste_ssid *ste_ssid;
+ int i;
+ struct domain **pd;
+
+ printkd("deleting cache for dom %x.\n", id);
+
+ read_lock(&domlist_lock); /* look through caches of all domains */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ if ((ste_ssid->ste_cache[i].valid == VALID) &&
+ (ste_ssid->ste_cache[i].id = id))
+ ste_ssid->ste_cache[i].valid = FREE;
+ }
+ read_unlock(&domlist_lock);
+}
+
+/***************************
+ * Authorization functions
+ **************************/
+
+static int
+ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ /* check for ssidref in range for policy */
+ ssidref_t ste_ssidref;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
+ if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
+ printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED; /* catching and indicating config error */
+ }
+ if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
+ printk("%s: ERROR ste_ssidref > max(%x).\n",
+ __func__, ste_bin_pol.max_ssidrefs-1);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_PERMITTED;
+}
+
+static void
+ste_post_domain_destroy(void *subject_ssid, domid_t id)
+{
+ /* clean all cache entries for destroyed domain (might be re-used) */
+ clean_id_from_cache(id);
+}
+
+/* -------- EVENTCHANNEL OPERATIONS -----------*/
+static int
+ste_pre_eventchannel_unbound(domid_t id) {
+ struct domain *subj, *obj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n",
+ __func__, current->domain->domain_id, id);
+
+ if (check_cache(current->domain, id)) {
+ atomic_inc(&ste_bin_pol.ec_cachehit_count);
+ return ACM_ACCESS_PERMITTED;
+ }
+ atomic_inc(&ste_bin_pol.ec_eval_count);
+ subj = current->domain;
+ obj = find_domain_by_id(id);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.ec_denied_count);
+ ret = ACM_ACCESS_DENIED;
+ }
+ if (obj != NULL)
+ put_domain(obj);
+ return ret;
+}
+
+static int
+ste_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
+{
+ struct domain *subj, *obj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n", __func__,
+ (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
+ (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
+
+ /* following is a bit longer but ensures that we
+ * "put" only domains that we where "find"-ing
+ */
+ if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
+ if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
+
+ subj = find_domain_by_id(id1);
+ obj = find_domain_by_id(id2);
+ if ((subj == NULL) || (obj == NULL)) {
+ ret = ACM_ACCESS_DENIED;
+ goto out;
+ }
+ /* cache check late, but evtchn is not on performance critical path */
+ if (check_cache(subj, obj->domain_id)) {
+ atomic_inc(&ste_bin_pol.ec_cachehit_count);
+ ret = ACM_ACCESS_PERMITTED;
+ goto out;
+ }
+ atomic_inc(&ste_bin_pol.ec_eval_count);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.ec_denied_count);
+ ret = ACM_ACCESS_DENIED;
+ }
+ out:
+ if (obj != NULL)
+ put_domain(obj);
+ if (subj != NULL)
+ put_domain(subj);
+ return ret;
+}
+
+/* -------- SHARED MEMORY OPERATIONS -----------*/
+
+static int
+ste_pre_grant_map_ref (domid_t id) {
+ struct domain *obj, *subj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n", __func__,
+ current->domain->domain_id, id);
+
+ if (check_cache(current->domain, id)) {
+ atomic_inc(&ste_bin_pol.gt_cachehit_count);
+ return ACM_ACCESS_PERMITTED;
+ }
+ atomic_inc(&ste_bin_pol.gt_eval_count);
+ subj = current->domain;
+ obj = find_domain_by_id(id);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.gt_denied_count);
+ printkd("%s: ACCESS DENIED!\n", __func__);
+ ret = ACM_ACCESS_DENIED;
+ }
+ if (obj != NULL)
+ put_domain(obj);
+ return ret;
+}
+
+/* since setting up grant tables involves some implicit information
+ flow from the creating domain to the domain that is setup, we
+ check types in addition to the general authorization */
+static int
+ste_pre_grant_setup (domid_t id) {
+ struct domain *obj, *subj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n", __func__,
+ current->domain->domain_id, id);
+
+ if (check_cache(current->domain, id)) {
+ atomic_inc(&ste_bin_pol.gt_cachehit_count);
+ return ACM_ACCESS_PERMITTED;
+ }
+ atomic_inc(&ste_bin_pol.gt_eval_count);
+ /* a) check authorization (eventually use specific capabilities) */
+ if (!IS_PRIV(current->domain)) {
+ printk("%s: Grant table management authorization denied ERROR!\n", __func__);
+ return ACM_ACCESS_DENIED;
+ }
+ /* b) check types */
+ subj = current->domain;
+ obj = find_domain_by_id(id);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.gt_denied_count);
+ ret = ACM_ACCESS_DENIED;
+ }
+ if (obj != NULL)
+ put_domain(obj);
+ return ret;
+}
+
+/* now define the hook structure similarly to LSM */
+struct acm_operations acm_simple_type_enforcement_ops = {
+ /* policy management services */
+ .init_domain_ssid = ste_init_domain_ssid,
+ .free_domain_ssid = ste_free_domain_ssid,
+ .dump_binary_policy = ste_dump_policy,
+ .set_binary_policy = ste_set_policy,
+ .dump_statistics = ste_dump_stats,
+ /* domain management control hooks */
+ .pre_domain_create = ste_pre_domain_create,
+ .post_domain_create = NULL,
+ .fail_domain_create = NULL,
+ .post_domain_destroy = ste_post_domain_destroy,
+ /* event channel control hooks */
+ .pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
+ .fail_eventchannel_unbound = NULL,
+ .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
+ .fail_eventchannel_interdomain = NULL,
+ /* grant table control hooks */
+ .pre_grant_map_ref = ste_pre_grant_map_ref,
+ .fail_grant_map_ref = NULL,
+ .pre_grant_setup = ste_pre_grant_setup,
+ .fail_grant_setup = NULL,
+};
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 1241e50921..4b49e17f37 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -193,23 +193,30 @@ static void __init init_amd(struct cpuinfo_x86 *c)
}
display_cacheinfo(c);
- detect_ht(c);
-
-#ifdef CONFIG_X86_HT
- /* AMD dual core looks like HT but isn't really. Hide it from the
- scheduler. This works around problems with the domain scheduler.
- Also probably gives slightly better scheduling and disables
- SMT nice which is harmful on dual core.
- TBD tune the domain scheduler for dual core. */
- if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
- smp_num_siblings = 1;
-#endif
if (cpuid_eax(0x80000000) >= 0x80000008) {
c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
if (c->x86_num_cores & (c->x86_num_cores - 1))
c->x86_num_cores = 1;
}
+
+#ifdef CONFIG_X86_HT
+ /*
+ * On a AMD dual core setup the lower bits of the APIC id
+ * distingush the cores. Assumes number of cores is a power
+ * of two.
+ */
+ if (c->x86_num_cores > 1) {
+ int cpu = smp_processor_id();
+ unsigned bits = 0;
+ while ((1 << bits) < c->x86_num_cores)
+ bits++;
+ cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
+ phys_proc_id[cpu] >>= bits;
+ printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
+ cpu, c->x86_num_cores, cpu_core_id[cpu]);
+ }
+#endif
}
static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index fcb5c16ecb..49661af7d8 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -186,7 +186,7 @@ static inline int flag_is_changeable_p(unsigned long flag)
/* Probe for the CPUID instruction */
-int __init have_cpuid_p(void)
+static int __init have_cpuid_p(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
@@ -194,7 +194,7 @@ int __init have_cpuid_p(void)
/* Do minimum CPU detection early.
Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
The others are not touched to avoid unwanted side effects. */
-void __init early_cpu_detect(void)
+static void __init early_cpu_detect(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -228,6 +228,10 @@ void __init early_cpu_detect(void)
}
early_intel_workaround(c);
+
+#ifdef CONFIG_X86_HT
+ phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+#endif
}
void __init generic_identify(struct cpuinfo_x86 * c)
@@ -416,25 +420,15 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
mcheck_init(c);
#endif
}
-/*
- * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
- */
-
-void __init dodgy_tsc(void)
-{
- if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
- ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC ))
- cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
-}
#ifdef CONFIG_X86_HT
void __init detect_ht(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
- int index_lsb, index_msb, tmp;
+ int index_msb, tmp;
int cpu = smp_processor_id();
- if (!cpu_has(c, X86_FEATURE_HT))
+ if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
return;
cpuid(1, &eax, &ebx, &ecx, &edx);
@@ -443,7 +437,6 @@ void __init detect_ht(struct cpuinfo_x86 *c)
if (smp_num_siblings == 1) {
printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
} else if (smp_num_siblings > 1 ) {
- index_lsb = 0;
index_msb = 31;
if (smp_num_siblings > NR_CPUS) {
@@ -452,21 +445,34 @@ void __init detect_ht(struct cpuinfo_x86 *c)
return;
}
tmp = smp_num_siblings;
- while ((tmp & 1) == 0) {
- tmp >>=1 ;
- index_lsb++;
- }
- tmp = smp_num_siblings;
while ((tmp & 0x80000000 ) == 0) {
tmp <<=1 ;
index_msb--;
}
- if (index_lsb != index_msb )
+ if (smp_num_siblings & (smp_num_siblings - 1))
index_msb++;
phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
phys_proc_id[cpu]);
+
+ smp_num_siblings = smp_num_siblings / c->x86_num_cores;
+
+ tmp = smp_num_siblings;
+ index_msb = 31;
+ while ((tmp & 0x80000000) == 0) {
+ tmp <<=1 ;
+ index_msb--;
+ }
+
+ if (smp_num_siblings & (smp_num_siblings - 1))
+ index_msb++;
+
+ cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+
+ if (c->x86_num_cores > 1)
+ printk(KERN_INFO "CPU: Processor Core ID: %d\n",
+ cpu_core_id[cpu]);
}
}
#endif
@@ -511,7 +517,6 @@ extern int amd_init_cpu(void);
extern int centaur_init_cpu(void);
extern int transmeta_init_cpu(void);
extern int rise_init_cpu(void);
-void early_cpu_detect(void);
void __init early_cpu_init(void)
{
diff --git a/xen/arch/x86/cpu/cpu.h b/xen/arch/x86/cpu/cpu.h
index 9df38d993c..5a1d4f163e 100644
--- a/xen/arch/x86/cpu/cpu.h
+++ b/xen/arch/x86/cpu/cpu.h
@@ -25,7 +25,6 @@ extern int get_model_name(struct cpuinfo_x86 *c);
extern void display_cacheinfo(struct cpuinfo_x86 *c);
extern void generic_identify(struct cpuinfo_x86 * c);
-extern int have_cpuid_p(void);
extern void early_intel_workaround(struct cpuinfo_x86 *c);
diff --git a/xen/arch/x86/cpu/intel.c b/xen/arch/x86/cpu/intel.c
index 861723719b..ef713eb95e 100644
--- a/xen/arch/x86/cpu/intel.c
+++ b/xen/arch/x86/cpu/intel.c
@@ -74,6 +74,27 @@ static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
}
+/*
+ * find out the number of processor cores on the die
+ */
+static int __init num_cpu_cores(struct cpuinfo_x86 *c)
+{
+ unsigned int eax;
+
+ if (c->cpuid_level < 4)
+ return 1;
+
+ __asm__("cpuid"
+ : "=a" (eax)
+ : "0" (4), "c" (0)
+ : "bx", "dx");
+
+ if (eax & 0x1f)
+ return ((eax >> 26) + 1);
+ else
+ return 1;
+}
+
static void __init init_intel(struct cpuinfo_x86 *c)
{
unsigned int l2 = 0;
@@ -136,6 +157,8 @@ static void __init init_intel(struct cpuinfo_x86 *c)
if ( p )
strcpy(c->x86_model_id, p);
+ c->x86_num_cores = num_cpu_cores(c);
+
detect_ht(c);
/* Work around errata */
diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c
index e8979417ec..2a269f11b6 100644
--- a/xen/arch/x86/dom0_ops.c
+++ b/xen/arch/x86/dom0_ops.c
@@ -179,8 +179,8 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
{
dom0_physinfo_t *pi = &op->u.physinfo;
- pi->ht_per_core = ht_per_core;
- pi->cores = num_online_cpus() / ht_per_core;
+ pi->ht_per_core = smp_num_siblings;
+ pi->cores = boot_cpu_data.x86_num_cores;
pi->total_pages = max_page;
pi->free_pages = avail_domheap_pages();
pi->cpu_khz = cpu_khz;
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 9b3d631bc0..0487da6a44 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2793,12 +2793,24 @@ static int ptwr_emulated_cmpxchg(
return ptwr_emulated_update(addr, old, new, bytes, 1);
}
+static int ptwr_emulated_cmpxchg8b(
+ unsigned long addr,
+ unsigned long old,
+ unsigned long old_hi,
+ unsigned long new,
+ unsigned long new_hi)
+{
+ return ptwr_emulated_update(
+ addr, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1);
+}
+
static struct x86_mem_emulator ptwr_mem_emulator = {
- .read_std = x86_emulate_read_std,
- .write_std = x86_emulate_write_std,
- .read_emulated = x86_emulate_read_std,
- .write_emulated = ptwr_emulated_write,
- .cmpxchg_emulated = ptwr_emulated_cmpxchg
+ .read_std = x86_emulate_read_std,
+ .write_std = x86_emulate_write_std,
+ .read_emulated = x86_emulate_read_std,
+ .write_emulated = ptwr_emulated_write,
+ .cmpxchg_emulated = ptwr_emulated_cmpxchg,
+ .cmpxchg8b_emulated = ptwr_emulated_cmpxchg8b
};
/* Write page fault handler: check if guest is trying to modify a PTE. */
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 0903967796..bb0da8c42f 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -20,6 +20,7 @@
#include <asm/desc.h>
#include <asm/shadow.h>
#include <asm/e820.h>
+#include <acm/acm_hooks.h>
extern void dmi_scan_machine(void);
extern void generic_apic_probe(void);
@@ -66,7 +67,6 @@ boolean_param("noapic", skip_ioapic_setup);
int early_boot = 1;
-int ht_per_core = 1;
cpumask_t cpu_present_map;
/* Limits of Xen heap, used to initialise the allocator. */
@@ -188,7 +188,7 @@ static void __init start_of_day(void)
arch_init_memory();
- scheduler_init();
+ scheduler_init();
identify_cpu(&boot_cpu_data);
if ( cpu_has_fxsr )
@@ -383,8 +383,8 @@ void __init __start_xen(multiboot_info_t *mbi)
init_xenheap_pages(xenheap_phys_start, xenheap_phys_end);
printk("Xen heap: %luMB (%lukB)\n",
- (xenheap_phys_end-xenheap_phys_start) >> 20,
- (xenheap_phys_end-xenheap_phys_start) >> 10);
+ (xenheap_phys_end-xenheap_phys_start) >> 20,
+ (xenheap_phys_end-xenheap_phys_start) >> 10);
early_boot = 0;
@@ -394,12 +394,17 @@ void __init __start_xen(multiboot_info_t *mbi)
shadow_mode_init();
+ /* initialize access control security module */
+ acm_init();
+
/* Create initial domain 0. */
dom0 = do_createdomain(0, 0);
if ( dom0 == NULL )
panic("Error creating domain 0\n");
set_bit(_DOMF_privileged, &dom0->domain_flags);
+ /* post-create hooks sets security label */
+ acm_post_domain0_create(dom0->domain_id);
/* Grab the DOM0 command line. */
cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL);
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 80fe8122a4..c9e1ac9151 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -62,6 +62,8 @@ static int __initdata smp_b_stepping;
int smp_num_siblings = 1;
int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
EXPORT_SYMBOL(phys_proc_id);
+int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
+EXPORT_SYMBOL(cpu_core_id);
/* bitmap of online cpus */
cpumask_t cpu_online_map;
@@ -923,6 +925,8 @@ static int boot_cpu_logical_apicid;
void *xquad_portio;
cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_core_map);
static void __init smp_boot_cpus(unsigned int max_cpus)
{
@@ -947,6 +951,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
cpus_clear(cpu_sibling_map[0]);
cpu_set(0, cpu_sibling_map[0]);
+ cpus_clear(cpu_core_map[0]);
+ cpu_set(0, cpu_core_map[0]);
+
/*
* If we couldn't find an SMP configuration at boot time,
* get out of here now!
@@ -959,6 +966,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
printk(KERN_NOTICE "Local APIC not detected."
" Using dummy APIC emulation.\n");
map_cpu_to_logical_apicid();
+ cpu_set(0, cpu_sibling_map[0]);
+ cpu_set(0, cpu_core_map[0]);
return;
}
@@ -1079,10 +1088,13 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
* construct cpu_sibling_map[], so that we can tell sibling CPUs
* efficiently.
*/
- for (cpu = 0; cpu < NR_CPUS; cpu++)
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ }
for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ struct cpuinfo_x86 *c = cpu_data + cpu;
int siblings = 0;
int i;
if (!cpu_isset(cpu, cpu_callout_map))
@@ -1092,7 +1104,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_isset(i, cpu_callout_map))
continue;
- if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ if (cpu_core_id[cpu] == cpu_core_id[i]) {
siblings++;
cpu_set(i, cpu_sibling_map[cpu]);
}
@@ -1102,8 +1114,22 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
cpu_set(cpu, cpu_sibling_map[cpu]);
}
- if (siblings != smp_num_siblings)
+ if (siblings != smp_num_siblings) {
printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
+ smp_num_siblings = siblings;
+ }
+
+ if (c->x86_num_cores > 1) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_isset(i, cpu_callout_map))
+ continue;
+ if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ cpu_set(i, cpu_core_map[cpu]);
+ }
+ }
+ } else {
+ cpu_core_map[cpu] = cpu_sibling_map[cpu];
+ }
}
if (nmi_watchdog == NMI_LOCAL_APIC)
diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S
index 475474b99a..93827336d4 100644
--- a/xen/arch/x86/x86_32/entry.S
+++ b/xen/arch/x86/x86_32/entry.S
@@ -751,6 +751,7 @@ ENTRY(hypercall_table)
.long do_boot_vcpu
.long do_ni_hypercall /* 25 */
.long do_mmuext_op
+ .long do_policy_op /* 27 */
.rept NR_hypercalls-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index 216af3854a..705f27bbb4 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -19,6 +19,7 @@
#include <asm/current.h>
#include <public/dom0_ops.h>
#include <public/sched_ctl.h>
+#include <acm/acm_hooks.h>
extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
extern void arch_getdomaininfo_ctxt(
@@ -91,6 +92,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
{
long ret = 0;
dom0_op_t curop, *op = &curop;
+ void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
if ( !IS_PRIV(current->domain) )
return -EPERM;
@@ -101,6 +103,9 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( op->interface_version != DOM0_INTERFACE_VERSION )
return -EACCES;
+ if ( acm_pre_dom0_op(op, &ssid) )
+ return -EACCES;
+
switch ( op->cmd )
{
@@ -184,8 +189,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
* domains will all share the second HT of each CPU. Since dom0 is on
* CPU 0, we favour high numbered CPUs in the event of a tie.
*/
- pro = ht_per_core - 1;
- for ( i = pro; i < num_online_cpus(); i += ht_per_core )
+ pro = smp_num_siblings - 1;
+ for ( i = pro; i < num_online_cpus(); i += smp_num_siblings )
if ( cnt[i] <= cnt[pro] )
pro = i;
@@ -334,9 +339,14 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
* - domain is marked as paused or blocked only if all its vcpus
* are paused or blocked
* - domain is marked as running if any of its vcpus is running
+ * - only map vcpus that aren't down. Note, at some point we may
+ * wish to demux the -1 value to indicate down vs. not-ever-booted
+ *
*/
for_each_vcpu ( d, v ) {
- op->u.getdomaininfo.vcpu_to_cpu[v->vcpu_id] = v->processor;
+ /* only map vcpus that are up */
+ if ( !(test_bit(_VCPUF_down, &v->vcpu_flags)) )
+ op->u.getdomaininfo.vcpu_to_cpu[v->vcpu_id] = v->processor;
op->u.getdomaininfo.cpumap[v->vcpu_id] = v->cpumap;
if ( !(v->vcpu_flags & VCPUF_ctrl_pause) )
flags &= ~DOMFLAGS_PAUSED;
@@ -357,6 +367,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
+ if (d->ssid != NULL)
+ op->u.getdomaininfo.ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
+ else
+ op->u.getdomaininfo.ssidref = ACM_DEFAULT_SSID;
+
op->u.getdomaininfo.tot_pages = d->tot_pages;
op->u.getdomaininfo.max_pages = d->max_pages;
op->u.getdomaininfo.shared_info_frame =
@@ -374,6 +389,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
struct vcpu_guest_context *c;
struct domain *d;
struct vcpu *v;
+ int i;
d = find_domain_by_id(op->u.getvcpucontext.domain);
if ( d == NULL )
@@ -388,8 +404,16 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
put_domain(d);
break;
}
+
+ /* find first valid vcpu starting from request. */
+ v = NULL;
+ for ( i = op->u.getvcpucontext.vcpu; i < MAX_VIRT_CPUS; i++ )
+ {
+ v = d->vcpu[i];
+ if ( v != NULL && !(test_bit(_VCPUF_down, &v->vcpu_flags)) )
+ break;
+ }
- v = d->vcpu[op->u.getvcpucontext.vcpu];
if ( v == NULL )
{
ret = -ESRCH;
@@ -493,7 +517,10 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
ret = arch_do_dom0_op(op,u_dom0_op);
}
-
+ if (!ret)
+ acm_post_dom0_op(op, ssid);
+ else
+ acm_fail_dom0_op(op, ssid);
return ret;
}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 6f6e707667..29d10ef3d2 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -26,6 +26,7 @@
#include <public/xen.h>
#include <public/event_channel.h>
+#include <acm/acm_hooks.h>
#define bucket_from_port(d,p) \
((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
@@ -587,6 +588,9 @@ long do_event_channel_op(evtchn_op_t *uop)
if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
return -EFAULT;
+ if (acm_pre_event_channel(&op))
+ return -EACCES;
+
switch ( op.cmd )
{
case EVTCHNOP_alloc_unbound:
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 683a051df3..9e7b7223e9 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -30,6 +30,7 @@
#include <xen/sched.h>
#include <xen/shadow.h>
#include <xen/mm.h>
+#include <acm/acm_hooks.h>
#define PIN_FAIL(_lbl, _rc, _f, _a...) \
do { \
@@ -357,6 +358,11 @@ __gnttab_map_grant_ref(
return GNTST_bad_gntref;
}
+ if (acm_pre_grant_map_ref(dom)) {
+ (void)__put_user(GNTST_permission_denied, &uop->handle);
+ return GNTST_permission_denied;
+ }
+
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
unlikely(ld == rd) )
{
diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index 3acaac8e1b..d63c235248 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -1,10 +1,7 @@
/******************************************************************************
* kernel.c
*
- * This file should contain architecture-independent bootstrap and low-level
- * help routines. It's a bit x86/PC specific right now!
- *
- * Copyright (c) 2002-2003 K A Fraser
+ * Copyright (c) 2002-2005 K A Fraser
*/
#include <xen/config.h>
@@ -14,6 +11,7 @@
#include <xen/compile.h>
#include <xen/sched.h>
#include <asm/current.h>
+#include <public/version.h>
void cmdline_parse(char *cmdline)
{
@@ -83,11 +81,38 @@ void cmdline_parse(char *cmdline)
* Simple hypercalls.
*/
-long do_xen_version(int cmd)
+long do_xen_version(int cmd, void *arg)
{
- if ( cmd != 0 )
- return -ENOSYS;
- return (XEN_VERSION<<16) | (XEN_SUBVERSION);
+ switch ( cmd )
+ {
+ case XENVER_version:
+ {
+ return (XEN_VERSION<<16) | (XEN_SUBVERSION);
+ }
+
+ case XENVER_extraversion:
+ {
+ char extraversion[16];
+ safe_strcpy(extraversion, XEN_EXTRAVERSION);
+ if ( copy_to_user(arg, extraversion, sizeof(extraversion)) )
+ return -EFAULT;
+ return 0;
+ }
+
+ case XENVER_compile_info:
+ {
+ struct xen_compile_info info;
+ safe_strcpy(info.compiler, XEN_COMPILER);
+ safe_strcpy(info.compile_by, XEN_COMPILE_BY);
+ safe_strcpy(info.compile_domain, XEN_COMPILE_DOMAIN);
+ safe_strcpy(info.compile_date, XEN_COMPILE_DATE);
+ if ( copy_to_user(arg, &info, sizeof(info)) )
+ return -EFAULT;
+ return 0;
+ }
+ }
+
+ return -ENOSYS;
}
long do_vm_assist(unsigned int cmd, unsigned int type)
diff --git a/xen/common/policy_ops.c b/xen/common/policy_ops.c
new file mode 100644
index 0000000000..11e28d25bc
--- /dev/null
+++ b/xen/common/policy_ops.c
@@ -0,0 +1,137 @@
+/******************************************************************************
+ * policy_ops.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * Process policy command requests from guest OS.
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <public/policy_ops.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/trace.h>
+#include <xen/console.h>
+#include <asm/shadow.h>
+#include <public/sched_ctl.h>
+#include <acm/acm_hooks.h>
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+
+long do_policy_op(policy_op_t *u_policy_op)
+{
+ return -ENOSYS;
+}
+
+#else
+
+/* function prototypes defined in acm/acm_policy.c */
+int acm_set_policy(void *buf, u16 buf_size, u16 policy);
+int acm_get_policy(void *buf, u16 buf_size);
+int acm_dump_statistics(void *buf, u16 buf_size);
+
+typedef enum policyoperation {
+ POLICY, /* access to policy interface (early drop) */
+ GETPOLICY, /* dump policy cache */
+ SETPOLICY, /* set policy cache (controls security) */
+ DUMPSTATS /* dump policy statistics */
+} policyoperation_t;
+
+int
+acm_authorize_policyops(struct domain *d, policyoperation_t pops)
+{
+ /* all policy management functions are restricted to privileged domains,
+ * soon we will introduce finer-grained privileges for policy operations
+ */
+ if (!IS_PRIV(d)) {
+ printk("%s: Policy management authorization denied ERROR!\n",
+ __func__);
+ return ACM_ACCESS_DENIED;
+ }
+ return ACM_ACCESS_PERMITTED;
+}
+
+long do_policy_op(policy_op_t *u_policy_op)
+{
+ long ret = 0;
+ policy_op_t curop, *op = &curop;
+
+ /* check here policy decision for policy commands */
+ /* for now allow DOM0 only, later indepedently */
+ if (acm_authorize_policyops(current->domain, POLICY))
+ return -EACCES;
+
+ if ( copy_from_user(op, u_policy_op, sizeof(*op)) )
+ return -EFAULT;
+
+ if ( op->interface_version != POLICY_INTERFACE_VERSION )
+ return -EACCES;
+
+ switch ( op->cmd )
+ {
+ case POLICY_SETPOLICY:
+ {
+ if (acm_authorize_policyops(current->domain, SETPOLICY))
+ return -EACCES;
+ printkd("%s: setting policy.\n", __func__);
+ ret = acm_set_policy(
+ op->u.setpolicy.pushcache,
+ op->u.setpolicy.pushcache_size,
+ op->u.setpolicy.policy_type);
+ if (ret == ACM_OK)
+ ret = 0;
+ else
+ ret = -ESRCH;
+ }
+ break;
+
+ case POLICY_GETPOLICY:
+ {
+ if (acm_authorize_policyops(current->domain, GETPOLICY))
+ return -EACCES;
+ printkd("%s: getting policy.\n", __func__);
+ ret = acm_get_policy(
+ op->u.getpolicy.pullcache,
+ op->u.getpolicy.pullcache_size);
+ if (ret == ACM_OK)
+ ret = 0;
+ else
+ ret = -ESRCH;
+ }
+ break;
+
+ case POLICY_DUMPSTATS:
+ {
+ if (acm_authorize_policyops(current->domain, DUMPSTATS))
+ return -EACCES;
+ printkd("%s: dumping statistics.\n", __func__);
+ ret = acm_dump_statistics(
+ op->u.dumpstats.pullcache,
+ op->u.dumpstats.pullcache_size);
+ if (ret == ACM_OK)
+ ret = 0;
+ else
+ ret = -ESRCH;
+ }
+ break;
+
+ default:
+ ret = -ESRCH;
+
+ }
+ return ret;
+}
+
+#endif
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index d3273a80e8..c547731302 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -261,6 +261,40 @@ static long do_yield(void)
return 0;
}
+/* Mark target vcpu as non-runnable so it is not scheduled */
+static long do_vcpu_down(int vcpu)
+{
+ struct vcpu *target;
+
+ if ( vcpu > MAX_VIRT_CPUS )
+ return -EINVAL;
+
+ target = current->domain->vcpu[vcpu];
+ if ( target == NULL )
+ return -ESRCH;
+ set_bit(_VCPUF_down, &target->vcpu_flags);
+
+ return 0;
+}
+
+/* Mark target vcpu as runnable and wake it */
+static long do_vcpu_up(int vcpu)
+{
+ struct vcpu *target;
+
+ if (vcpu > MAX_VIRT_CPUS)
+ return -EINVAL;
+
+ target = current->domain->vcpu[vcpu];
+ if ( target == NULL )
+ return -ESRCH;
+ clear_bit(_VCPUF_down, &target->vcpu_flags);
+ /* wake vcpu */
+ domain_wake(target);
+
+ return 0;
+}
+
/*
* Demultiplex scheduler-related hypercalls.
*/
@@ -290,6 +324,16 @@ long do_sched_op(unsigned long op)
domain_shutdown((u8)(op >> SCHEDOP_reasonshift));
break;
}
+ case SCHEDOP_vcpu_down:
+ {
+ ret = do_vcpu_down((int)(op >> SCHEDOP_vcpushift));
+ break;
+ }
+ case SCHEDOP_vcpu_up:
+ {
+ ret = do_vcpu_up((int)(op >> SCHEDOP_vcpushift));
+ break;
+ }
default:
ret = -ENOSYS;
diff --git a/xen/include/acm/acm_core.h b/xen/include/acm/acm_core.h
new file mode 100644
index 0000000000..e404b455ad
--- /dev/null
+++ b/xen/include/acm/acm_core.h
@@ -0,0 +1,117 @@
+/****************************************************************
+ * acm_core.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype header file describing core data types and constants
+ * for the access control module and relevant policies
+ *
+ */
+#ifndef _ACM_CORE_H
+#define _ACM_CORE_H
+
+#include <xen/spinlock.h>
+#include <public/acm.h>
+#include <public/policy_ops.h>
+
+/* Xen-internal representation of the binary policy */
+struct acm_binary_policy {
+ u16 primary_policy_code;
+ u16 secondary_policy_code;
+ void *primary_binary_policy;
+ void *secondary_binary_policy;
+
+};
+
+struct chwall_binary_policy {
+ u16 max_types;
+ u16 max_ssidrefs;
+ u16 max_conflictsets;
+ domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
+ domaintype_t *conflict_aggregate_set; /* [max_types] */
+ domaintype_t *running_types; /* [max_types] */
+ domaintype_t *conflict_sets; /* [max_conflictsets][max_types]*/
+};
+
+struct ste_binary_policy {
+ u16 max_types;
+ u16 max_ssidrefs;
+ domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
+ atomic_t ec_eval_count, gt_eval_count;
+ atomic_t ec_denied_count, gt_denied_count;
+ atomic_t ec_cachehit_count, gt_cachehit_count;
+};
+
+/* global acm policy */
+extern struct acm_binary_policy acm_bin_pol;
+extern struct chwall_binary_policy chwall_bin_pol;
+extern struct ste_binary_policy ste_bin_pol;
+/* use the lock when reading / changing binary policy ! */
+extern rwlock_t acm_bin_pol_rwlock;
+
+/* subject and object type definitions */
+enum acm_datatype { DOMAIN };
+
+/* defines number of access decisions to other domains can be cached
+ * one entry per domain, TE does not distinguish evtchn or grant_table */
+#define ACM_TE_CACHE_SIZE 8
+enum acm_ste_flag { VALID, FREE };
+
+/* cache line:
+ * if cache_line.valid==VALID, then
+ * STE decision is cached as "permitted"
+ * on domain cache_line.id
+ */
+struct acm_ste_cache_line {
+ enum acm_ste_flag valid;
+ domid_t id;
+};
+
+/* general definition of a subject security id */
+struct acm_ssid_domain {
+ enum acm_datatype datatype; /* type of subject (e.g., partition) */
+ ssidref_t ssidref; /* combined security reference */
+ void *primary_ssid; /* primary policy ssid part (e.g. chinese wall) */
+ void *secondary_ssid; /* secondary policy ssid part (e.g. type enforcement) */
+ struct domain *subject; /* backpointer to subject structure */
+ domid_t domainid; /* replicate id */
+};
+
+/* chinese wall ssid type */
+struct chwall_ssid {
+ ssidref_t chwall_ssidref;
+};
+
+/* simple type enforcement ssid type */
+struct ste_ssid {
+ ssidref_t ste_ssidref;
+ struct acm_ste_cache_line ste_cache[ACM_TE_CACHE_SIZE]; /* decision cache */
+};
+
+/* macros to access ssidref for primary / secondary policy
+ * primary ssidref = lower 16 bit
+ * secondary ssidref = higher 16 bit
+ */
+#define GET_SSIDREF(POLICY, ssidref) \
+ ((POLICY) == acm_bin_pol.primary_policy_code) ? \
+ ((ssidref) & 0xffff) : ((ssidref) >> 16)
+
+/* macros to access ssid pointer for primary / secondary policy */
+#define GET_SSIDP(POLICY, ssid) \
+ ((POLICY) == acm_bin_pol.primary_policy_code) ? \
+ ((ssid)->primary_ssid) : ((ssid)->secondary_ssid)
+
+/* protos */
+int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
+int acm_free_domain_ssid(struct acm_ssid_domain *ssid);
+
+#endif
+
diff --git a/xen/include/acm/acm_endian.h b/xen/include/acm/acm_endian.h
new file mode 100644
index 0000000000..fd7229b846
--- /dev/null
+++ b/xen/include/acm/acm_endian.h
@@ -0,0 +1,88 @@
+/****************************************************************
+ * acm_endian.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *
+ * Contributions:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype header file defining endian-dependent functions for the
+ * big-endian policy interface
+ *
+ */
+#ifndef _ACM_ENDIAN_H
+#define _ACM_ENDIAN_H
+
+/* don't use these functions in performance critical sections! */
+
+/* set during initialization by testing */
+extern u8 little_endian;
+
+static inline u32 ntohl(u32 x)
+{
+ if (little_endian)
+ return
+ ( (((x) >> 24) & 0xff )|
+ (((x) >> 8) & 0xff00 )|
+ (((x) << 8) & 0xff0000 )|
+ (((x) << 24) & 0xff000000) );
+ else
+ return x;
+}
+
+static inline u16 ntohs(u16 x)
+{
+ if (little_endian)
+ return
+ ( (((x) >> 8) & 0xff )|
+ (((x) << 8) & 0xff00 ) );
+ else
+ return x;
+}
+
+#define htonl(x) ntohl(x)
+#define htons(x) ntohs(x)
+
+static inline void arrcpy16(u16 *dest, const u16 *src, size_t n)
+{
+ unsigned int i = 0;
+ while (i < n) {
+ dest[i] = htons(src[i]);
+ i++;
+ }
+}
+
+static inline void arrcpy32(u32 *dest, const u32 *src, size_t n)
+{
+ unsigned int i = 0;
+ while (i < n) {
+ dest[i] = htonl(src[i]);
+ i++;
+ }
+}
+
+static inline void arrcpy(void *dest, const void *src, unsigned int elsize, size_t n)
+{
+ switch (elsize) {
+ case sizeof(u16):
+ arrcpy16((u16 *)dest, (u16 *)src, n);
+ break;
+
+ case sizeof(u32):
+ arrcpy32((u32 *)dest, (u32 *)src, n);
+ break;
+
+ default:
+ memcpy(dest, src, elsize*n);
+ }
+}
+
+#endif
diff --git a/xen/include/acm/acm_hooks.h b/xen/include/acm/acm_hooks.h
new file mode 100644
index 0000000000..7c5e3faa9d
--- /dev/null
+++ b/xen/include/acm/acm_hooks.h
@@ -0,0 +1,349 @@
+/****************************************************************
+ * acm_hooks.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * acm header file implementing the global (policy-independent)
+ * sHype hooks that are called throughout Xen.
+ *
+ */
+#ifndef _ACM_HOOKS_H
+#define _ACM_HOOKS_H
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/acm.h>
+#include <acm/acm_core.h>
+#include <public/dom0_ops.h>
+#include <public/event_channel.h>
+#include <asm/current.h>
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+
+static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid)
+{ return 0; }
+static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid)
+{ return; }
+static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid)
+{ return; }
+static inline int acm_pre_event_channel(evtchn_op_t *op)
+{ return 0; }
+static inline int acm_pre_grant_map_ref(domid_t id)
+{ return 0; }
+static inline int acm_pre_grant_setup(domid_t id)
+{ return 0; }
+static inline int acm_init(void)
+{ return 0; }
+static inline void acm_post_domain0_create(domid_t domid)
+{ return; }
+
+#else
+
+/* if ACM_TRACE_MODE defined, all hooks should
+ * print a short trace message */
+/* #define ACM_TRACE_MODE */
+
+#ifdef ACM_TRACE_MODE
+# define traceprintk(fmt, args...) printk(fmt,## args)
+#else
+# define traceprintk(fmt, args...)
+#endif
+
+/* global variables */
+extern struct acm_operations *acm_primary_ops;
+extern struct acm_operations *acm_secondary_ops;
+
+/*********************************************************************
+ * HOOK structure and meaning (justifies a few words about our model):
+ *
+ * General idea: every policy-controlled system operation is reflected in a
+ * transaction in the system's security state
+ *
+ * Keeping the security state consistent requires "atomic" transactions.
+ * The name of the hooks to place around policy-controlled transactions
+ * reflects this. If authorizations do not involve security state changes,
+ * then and only then POST and FAIL hooks remain empty since we don't care
+ * about the eventual outcome of the operation from a security viewpoint.
+ *
+ * PURPOSE of hook types:
+ * ======================
+ * PRE-Hooks
+ * a) general authorization to guard a controlled system operation
+ * b) prepare security state change
+ * (means: fail hook must be able to "undo" this)
+ *
+ * POST-Hooks
+ * a) commit prepared state change
+ *
+ * FAIL-Hooks
+ * a) roll-back prepared security state change from PRE-Hook
+ *
+ *
+ * PLACEMENT of hook types:
+ * ========================
+ * PRE-Hooks must be called:
+ * a) before a guarded/controlled system operation is started
+ * (return is ACM_ACCESS_PERMITTED or ACM_ACCESS_DENIED or error)
+ * --> operation must be aborted if return is != ACM_ACCESS_PERMITTED
+ *
+ * POST-Hooks must be called:
+ * a) after successful transaction (no return value; commit shall never fail)
+ *
+ * FAIL-Hooks must be called:
+ * a) if system transaction (operation) fails somewhen after calling the PRE-hook
+ * (obviously the POST-Hook is not called in this case)
+ * b) if another (secondary) policy denies access in its PRE-Hook
+ * (policy layering is useful but requires additional handling)
+ *
+ *
+ *
+ * Hook model from a security transaction viewpoint:
+ *
+ * start-sys-ops--> prepare ----succeed-----> commit --> sys-ops success
+ * (pre-hook) \ (post-hook)
+ * \
+ * fail
+ * \
+ * \
+ * roll-back
+ * (fail-hook)
+ * \
+ * sys-ops error
+ *
+ ********************************************************************/
+
+struct acm_operations {
+ /* policy management functions (must always be defined!) */
+ int (*init_domain_ssid) (void **ssid, ssidref_t ssidref);
+ void (*free_domain_ssid) (void *ssid);
+ int (*dump_binary_policy) (u8 *buffer, u16 buf_size);
+ int (*set_binary_policy) (u8 *buffer, u16 buf_size);
+ int (*dump_statistics) (u8 *buffer, u16 buf_size);
+ /* domain management control hooks (can be NULL) */
+ int (*pre_domain_create) (void *subject_ssid, ssidref_t ssidref);
+ void (*post_domain_create) (domid_t domid, ssidref_t ssidref);
+ void (*fail_domain_create) (void *subject_ssid, ssidref_t ssidref);
+ void (*post_domain_destroy) (void *object_ssid, domid_t id);
+ /* event channel control hooks (can be NULL) */
+ int (*pre_eventchannel_unbound) (domid_t id);
+ void (*fail_eventchannel_unbound) (domid_t id);
+ int (*pre_eventchannel_interdomain) (domid_t id1, domid_t id2);
+ int (*fail_eventchannel_interdomain) (domid_t id1, domid_t id2);
+ /* grant table control hooks (can be NULL) */
+ int (*pre_grant_map_ref) (domid_t id);
+ void (*fail_grant_map_ref) (domid_t id);
+ int (*pre_grant_setup) (domid_t id);
+ void (*fail_grant_setup) (domid_t id);
+};
+
+static inline int acm_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ if ((acm_primary_ops->pre_domain_create != NULL) &&
+ acm_primary_ops->pre_domain_create(subject_ssid, ssidref))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_domain_create != NULL) &&
+ acm_secondary_ops->pre_domain_create(subject_ssid, ssidref)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_domain_create != NULL)
+ acm_primary_ops->fail_domain_create(subject_ssid, ssidref);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static inline void acm_post_domain_create(domid_t domid, ssidref_t ssidref)
+{
+ if (acm_primary_ops->post_domain_create != NULL)
+ acm_primary_ops->post_domain_create(domid, ssidref);
+ if (acm_secondary_ops->post_domain_create != NULL)
+ acm_secondary_ops->post_domain_create(domid, ssidref);
+}
+
+static inline void acm_fail_domain_create(
+ void *subject_ssid, ssidref_t ssidref)
+{
+ if (acm_primary_ops->fail_domain_create != NULL)
+ acm_primary_ops->fail_domain_create(subject_ssid, ssidref);
+ if (acm_secondary_ops->fail_domain_create != NULL)
+ acm_secondary_ops->fail_domain_create(subject_ssid, ssidref);
+}
+
+static inline void acm_post_domain_destroy(void *object_ssid, domid_t id)
+{
+ if (acm_primary_ops->post_domain_destroy != NULL)
+ acm_primary_ops->post_domain_destroy(object_ssid, id);
+ if (acm_secondary_ops->post_domain_destroy != NULL)
+ acm_secondary_ops->post_domain_destroy(object_ssid, id);
+ return;
+}
+
+static inline int acm_pre_eventchannel_unbound(domid_t id)
+{
+ if ((acm_primary_ops->pre_eventchannel_unbound != NULL) &&
+ acm_primary_ops->pre_eventchannel_unbound(id))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) &&
+ acm_secondary_ops->pre_eventchannel_unbound(id)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_eventchannel_unbound != NULL)
+ acm_primary_ops->fail_eventchannel_unbound(id);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static inline int acm_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
+{
+ if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) &&
+ acm_primary_ops->pre_eventchannel_interdomain(id1, id2))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) &&
+ acm_secondary_ops->pre_eventchannel_interdomain(id1, id2)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_eventchannel_interdomain != NULL)
+ acm_primary_ops->fail_eventchannel_interdomain(id1, id2);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid)
+{
+ int ret = -EACCES;
+ struct domain *d;
+
+ switch(op->cmd) {
+ case DOM0_CREATEDOMAIN:
+ ret = acm_pre_domain_create(
+ current->domain->ssid, op->u.createdomain.ssidref);
+ break;
+ case DOM0_DESTROYDOMAIN:
+ d = find_domain_by_id(op->u.destroydomain.domain);
+ if (d != NULL) {
+ *ssid = d->ssid; /* save for post destroy when d is gone */
+ /* no policy-specific hook */
+ put_domain(d);
+ ret = 0;
+ }
+ break;
+ default:
+ ret = 0; /* ok */
+ }
+ return ret;
+}
+
+static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid)
+{
+ switch(op->cmd) {
+ case DOM0_CREATEDOMAIN:
+ /* initialialize shared sHype security labels for new domain */
+ acm_init_domain_ssid(
+ op->u.createdomain.domain, op->u.createdomain.ssidref);
+ acm_post_domain_create(
+ op->u.createdomain.domain, op->u.createdomain.ssidref);
+ break;
+ case DOM0_DESTROYDOMAIN:
+ acm_post_domain_destroy(ssid, op->u.destroydomain.domain);
+ /* free security ssid for the destroyed domain (also if null policy */
+ acm_free_domain_ssid((struct acm_ssid_domain *)ssid);
+ break;
+ }
+}
+
+static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid)
+{
+ switch(op->cmd) {
+ case DOM0_CREATEDOMAIN:
+ acm_fail_domain_create(
+ current->domain->ssid, op->u.createdomain.ssidref);
+ break;
+ }
+}
+
+static inline int acm_pre_event_channel(evtchn_op_t *op)
+{
+ int ret = -EACCES;
+
+ switch(op->cmd) {
+ case EVTCHNOP_alloc_unbound:
+ ret = acm_pre_eventchannel_unbound(op->u.alloc_unbound.dom);
+ break;
+ case EVTCHNOP_bind_interdomain:
+ ret = acm_pre_eventchannel_interdomain(
+ op->u.bind_interdomain.dom1, op->u.bind_interdomain.dom2);
+ break;
+ default:
+ ret = 0; /* ok */
+ }
+ return ret;
+}
+
+static inline int acm_pre_grant_map_ref(domid_t id)
+{
+ if ( (acm_primary_ops->pre_grant_map_ref != NULL) &&
+ acm_primary_ops->pre_grant_map_ref(id) )
+ {
+ return ACM_ACCESS_DENIED;
+ }
+ else if ( (acm_secondary_ops->pre_grant_map_ref != NULL) &&
+ acm_secondary_ops->pre_grant_map_ref(id) )
+ {
+ /* roll-back primary */
+ if ( acm_primary_ops->fail_grant_map_ref != NULL )
+ acm_primary_ops->fail_grant_map_ref(id);
+ return ACM_ACCESS_DENIED;
+ }
+ else
+ {
+ return ACM_ACCESS_PERMITTED;
+ }
+}
+
+static inline int acm_pre_grant_setup(domid_t id)
+{
+ if ( (acm_primary_ops->pre_grant_setup != NULL) &&
+ acm_primary_ops->pre_grant_setup(id) )
+ {
+ return ACM_ACCESS_DENIED;
+ }
+ else if ( (acm_secondary_ops->pre_grant_setup != NULL) &&
+ acm_secondary_ops->pre_grant_setup(id) )
+ {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_grant_setup != NULL)
+ acm_primary_ops->fail_grant_setup(id);
+ return ACM_ACCESS_DENIED;
+ }
+ else
+ {
+ return ACM_ACCESS_PERMITTED;
+ }
+}
+
+/* predefined ssidref for DOM0 used by xen when creating DOM0 */
+#define ACM_DOM0_SSIDREF 0
+
+static inline void acm_post_domain0_create(domid_t domid)
+{
+ /* initialialize shared sHype security labels for new domain */
+ acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF);
+ acm_post_domain_create(domid, ACM_DOM0_SSIDREF);
+}
+
+extern int acm_init(void);
+
+#endif
+
+#endif
diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
index 87a47f8667..29b9f518a8 100644
--- a/xen/include/asm-x86/page.h
+++ b/xen/include/asm-x86/page.h
@@ -2,13 +2,13 @@
#ifndef __X86_PAGE_H__
#define __X86_PAGE_H__
-#ifndef __ASSEMBLY__
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#else
+/*
+ * It is important that the masks are signed quantities. This ensures that
+ * the compiler sign-extends a 32-bit mask to 64 bits if that is required.
+ */
#define PAGE_SIZE (1 << PAGE_SHIFT)
-#endif
-#define PAGE_MASK (~(intpte_t)(PAGE_SIZE-1))
-#define PAGE_FLAG_MASK (~0U)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+#define PAGE_FLAG_MASK (~0)
#ifndef __ASSEMBLY__
# include <asm/types.h>
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index bec90dbab0..82b8cbce62 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -181,6 +181,7 @@ extern struct cpuinfo_x86 cpu_data[];
#endif
extern int phys_proc_id[NR_CPUS];
+extern int cpu_core_id[NR_CPUS];
extern void identify_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);
diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h
index c70f4d90fc..552b699bc4 100644
--- a/xen/include/asm-x86/smp.h
+++ b/xen/include/asm-x86/smp.h
@@ -8,6 +8,7 @@
#include <xen/config.h>
#include <xen/kernel.h>
#include <xen/cpumask.h>
+#include <asm/current.h>
#endif
#ifdef CONFIG_X86_LOCAL_APIC
@@ -34,6 +35,7 @@ extern void smp_alloc_memory(void);
extern int pic_mode;
extern int smp_num_siblings;
extern cpumask_t cpu_sibling_map[];
+extern cpumask_t cpu_core_map[];
extern void smp_flush_tlb(void);
extern void smp_invalidate_rcv(void); /* Process an NMI */
diff --git a/xen/include/asm-x86/x86_32/page-2level.h b/xen/include/asm-x86/x86_32/page-2level.h
index 34128f24fa..4f11ac49ca 100644
--- a/xen/include/asm-x86/x86_32/page-2level.h
+++ b/xen/include/asm-x86/x86_32/page-2level.h
@@ -46,6 +46,8 @@ typedef l2_pgentry_t root_pgentry_t;
* 12-bit flags = (pte[11:0])
*/
+#define _PAGE_NX 0U
+
/* Extract flags into 12-bit integer, or turn 12-bit flags into a pte mask. */
#define get_pte_flags(x) ((int)(x) & 0xFFF)
#define put_pte_flags(x) ((intpte_t)((x) & 0xFFF))
diff --git a/xen/include/asm-x86/x86_32/page-3level.h b/xen/include/asm-x86/x86_32/page-3level.h
index 1fc423c073..79b14169e9 100644
--- a/xen/include/asm-x86/x86_32/page-3level.h
+++ b/xen/include/asm-x86/x86_32/page-3level.h
@@ -59,6 +59,8 @@ typedef l3_pgentry_t root_pgentry_t;
* 32-bit flags = (pte[63:44],pte[11:0])
*/
+#define _PAGE_NX (cpu_has_nx ? (1<<31) : 0)
+
/* Extract flags into 32-bit integer, or turn 32-bit flags into a pte mask. */
#define get_pte_flags(x) (((int)((x) >> 32) & ~0xFFF) | ((int)(x) & 0xFFF))
#define put_pte_flags(x) (((intpte_t)((x) & ~0xFFF) << 40) | ((x) & 0xFFF))
diff --git a/xen/include/asm-x86/x86_32/page.h b/xen/include/asm-x86/x86_32/page.h
index 9546706876..41396fa6a4 100644
--- a/xen/include/asm-x86/x86_32/page.h
+++ b/xen/include/asm-x86/x86_32/page.h
@@ -7,8 +7,6 @@
#define VADDR_BITS 32
#define VADDR_MASK (~0UL)
-#define _PAGE_NX 0U
-
#include <xen/config.h>
#ifdef CONFIG_X86_PAE
# include <asm/x86_32/page-3level.h>
diff --git a/xen/include/public/acm.h b/xen/include/public/acm.h
new file mode 100644
index 0000000000..31191b7b5a
--- /dev/null
+++ b/xen/include/public/acm.h
@@ -0,0 +1,161 @@
+/****************************************************************
+ * acm.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * added network byte order support for binary policies
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * sHype general access control module header file.
+ * here are all definitions that are shared between
+ * xen-core, guest-kernels, and applications.
+ *
+ * todo: move from static policy choice to compile option.
+ */
+
+#ifndef _XEN_PUBLIC_SHYPE_H
+#define _XEN_PUBLIC_SHYPE_H
+
+#include "xen.h"
+#include "sched_ctl.h"
+
+/* if ACM_DEBUG defined, all hooks should
+ * print a short trace message (comment it out
+ * when not in testing mode )
+ */
+/* #define ACM_DEBUG */
+
+#ifdef ACM_DEBUG
+# define printkd(fmt, args...) printk(fmt,## args)
+#else
+# define printkd(fmt, args...)
+#endif
+
+/* default ssid reference value if not supplied */
+#define ACM_DEFAULT_SSID 0xffffffff
+#define ACM_DEFAULT_LOCAL_SSID 0xffff
+
+/* Internal ACM ERROR types */
+#define ACM_OK 0
+#define ACM_UNDEF -1
+#define ACM_INIT_SSID_ERROR -2
+#define ACM_INIT_SOID_ERROR -3
+#define ACM_ERROR -4
+
+/* External ACCESS DECISIONS */
+#define ACM_ACCESS_PERMITTED 0
+#define ACM_ACCESS_DENIED -111
+#define ACM_NULL_POINTER_ERROR -200
+
+#define ACM_MAX_POLICY 3
+
+#define ACM_NULL_POLICY 0
+#define ACM_CHINESE_WALL_POLICY 1
+#define ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY 2
+#define ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY 3
+
+/* policy: */
+#define ACM_POLICY_NAME(X) \
+ (X == ACM_NULL_POLICY) ? "NULL policy" : \
+ (X == ACM_CHINESE_WALL_POLICY) ? "CHINESE WALL policy" : \
+ (X == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "SIMPLE TYPE ENFORCEMENT policy" : \
+ (X == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "CHINESE WALL AND SIMPLE TYPE ENFORCEMENT policy" : \
+ "UNDEFINED policy"
+
+#ifndef ACM_USE_SECURITY_POLICY
+#define ACM_USE_SECURITY_POLICY ACM_NULL_POLICY
+#endif
+
+/* defines a ssid reference used by xen */
+typedef u32 ssidref_t;
+
+/* -------security policy relevant type definitions-------- */
+
+/* type identifier; compares to "equal" or "not equal" */
+typedef u16 domaintype_t;
+
+/* CHINESE WALL POLICY DATA STRUCTURES
+ *
+ * current accumulated conflict type set:
+ * When a domain is started and has a type that is in
+ * a conflict set, the conflicting types are incremented in
+ * the aggregate set. When a domain is destroyed, the
+ * conflicting types to its type are decremented.
+ * If a domain has multiple types, this procedure works over
+ * all those types.
+ *
+ * conflict_aggregate_set[i] holds the number of
+ * running domains that have a conflict with type i.
+ *
+ * running_types[i] holds the number of running domains
+ * that include type i in their ssidref-referenced type set
+ *
+ * conflict_sets[i][j] is "0" if type j has no conflict
+ * with type i and is "1" otherwise.
+ */
+/* high-16 = version, low-16 = check magic */
+#define ACM_MAGIC 0x0001debc
+
+/* each offset in bytes from start of the struct they
+ * the are part of */
+/* each buffer consists of all policy information for
+ * the respective policy given in the policy code
+ */
+struct acm_policy_buffer {
+ u32 magic;
+ u32 policyversion;
+ u32 len;
+ u16 primary_policy_code;
+ u16 primary_buffer_offset;
+ u16 secondary_policy_code;
+ u16 secondary_buffer_offset;
+};
+
+struct acm_chwall_policy_buffer {
+ u16 policy_code;
+ u16 chwall_max_types;
+ u16 chwall_max_ssidrefs;
+ u16 chwall_max_conflictsets;
+ u16 chwall_ssid_offset;
+ u16 chwall_conflict_sets_offset;
+ u16 chwall_running_types_offset;
+ u16 chwall_conflict_aggregate_offset;
+};
+
+struct acm_ste_policy_buffer {
+ u16 policy_code;
+ u16 ste_max_types;
+ u16 ste_max_ssidrefs;
+ u16 ste_ssid_offset;
+};
+
+struct acm_stats_buffer {
+ u32 magic;
+ u32 policyversion;
+ u32 len;
+ u16 primary_policy_code;
+ u16 primary_stats_offset;
+ u16 secondary_policy_code;
+ u16 secondary_stats_offset;
+};
+
+struct acm_ste_stats_buffer {
+ u32 ec_eval_count;
+ u32 gt_eval_count;
+ u32 ec_denied_count;
+ u32 gt_denied_count;
+ u32 ec_cachehit_count;
+ u32 gt_cachehit_count;
+};
+
+
+#endif
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index 0768b8c6ae..3ff82b43ac 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -43,6 +43,8 @@ typedef struct sched_adjdom_cmd dom0_adjustdom_t;
#define DOM0_CREATEDOMAIN 8
typedef struct {
+ /* IN parameters */
+ u32 ssidref;
/* IN/OUT parameters. */
/* Identifier for new domain (auto-allocate if zero is specified). */
domid_t domain;
@@ -88,6 +90,7 @@ typedef struct {
u32 n_vcpu;
s32 vcpu_to_cpu[MAX_VIRT_CPUS]; /* current mapping */
cpumap_t cpumap[MAX_VIRT_CPUS]; /* allowable mapping */
+ u32 ssidref;
} dom0_getdomaininfo_t;
#define DOM0_SETDOMAININFO 13
diff --git a/xen/include/public/io/domain_controller.h b/xen/include/public/io/domain_controller.h
index 69a8359aa9..140bff4881 100644
--- a/xen/include/public/io/domain_controller.h
+++ b/xen/include/public/io/domain_controller.h
@@ -61,6 +61,7 @@ typedef struct {
#define CMSG_MEM_REQUEST 7 /* Memory reservation reqs */
#define CMSG_USBIF_BE 8 /* USB controller backend */
#define CMSG_USBIF_FE 9 /* USB controller frontend */
+#define CMSG_VCPU_HOTPLUG 10 /* Hotplug VCPU messages */
/******************************************************************************
* CONSOLE DEFINITIONS
@@ -758,6 +759,25 @@ typedef struct {
} PACKED shutdown_sysrq_t; /* 4 bytes */
/******************************************************************************
+ * VCPU HOTPLUG CONTROLS
+ */
+
+/*
+ * Subtypes for shutdown messages.
+ */
+#define CMSG_VCPU_HOTPLUG_OFF 0 /* turn vcpu off */
+#define CMSG_VCPU_HOTPLUG_ON 1 /* turn vcpu on */
+
+/*
+ * CMSG_VCPU_HOTPLUG:
+ * Indicate which vcpu's state should change
+ */
+typedef struct {
+ u32 vcpu; /* 0: VCPU's whose state will change */
+ u32 status; /* 4: Return code indicates success or failure. */
+} PACKED vcpu_hotplug_t;
+
+/******************************************************************************
* MEMORY CONTROLS
*/
diff --git a/xen/include/public/policy_ops.h b/xen/include/public/policy_ops.h
new file mode 100644
index 0000000000..6b55f764b1
--- /dev/null
+++ b/xen/include/public/policy_ops.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * policy_ops.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * Process policy command requests from guest OS.
+ * access checked by policy; not restricted to DOM0
+ *
+ */
+
+
+#ifndef __XEN_PUBLIC_POLICY_OPS_H__
+#define __XEN_PUBLIC_POLICY_OPS_H__
+
+#include "xen.h"
+#include "sched_ctl.h"
+
+/*
+ * Make sure you increment the interface version whenever you modify this file!
+ * This makes sure that old versions of policy tools will stop working in a
+ * well-defined way (rather than crashing the machine, for instance).
+ */
+#define POLICY_INTERFACE_VERSION 0xAAAA0001
+
+/************************************************************************/
+
+#define POLICY_SETPOLICY 4
+typedef struct {
+ /* IN variables. */
+ u16 policy_type;
+ u16 padding1;
+ /* OUT variables */
+ void *pushcache;
+ u16 pushcache_size;
+} PACKED policy_setpolicy_t;
+
+
+#define POLICY_GETPOLICY 5
+typedef struct {
+ /* IN variables. */
+ u16 policy_type;
+ u16 padding1;
+ /* OUT variables */
+ void *pullcache;
+ u16 pullcache_size;
+} PACKED policy_getpolicy_t;
+
+#define POLICY_DUMPSTATS 6
+typedef struct {
+ void *pullcache;
+ u16 pullcache_size;
+} PACKED policy_dumpstats_t;
+
+
+typedef struct {
+ u32 cmd; /* 0 */
+ u32 interface_version; /* 4 */ /* POLICY_INTERFACE_VERSION */
+ union { /* 8 */
+ u32 dummy[14]; /* 72bytes */
+ policy_setpolicy_t setpolicy;
+ policy_getpolicy_t getpolicy;
+ policy_dumpstats_t dumpstats;
+ } PACKED u;
+} PACKED policy_op_t; /* 80 bytes */
+
+#endif /* __XEN_PUBLIC_POLICY_OPS_H__ */
diff --git a/xen/include/public/version.h b/xen/include/public/version.h
new file mode 100644
index 0000000000..1860d061da
--- /dev/null
+++ b/xen/include/public/version.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * version.h
+ *
+ * Xen version, type, and compile information.
+ *
+ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VERSION_H__
+#define __XEN_PUBLIC_VERSION_H__
+
+/* NB. All ops return zero on success, except XENVER_version. */
+
+/* arg == NULL; returns major:minor (16:16). */
+#define XENVER_version 0
+
+/* arg == 16-char string buffer. */
+#define XENVER_extraversion 1
+
+/* arg == xenversion_compile_info_t. */
+#define XENVER_compile_info 2
+typedef struct xen_compile_info {
+ char compiler[64];
+ char compile_by[16];
+ char compile_domain[32];
+ char compile_date[32];
+} xen_compile_info_t;
+
+#endif /* __XEN_PUBLIC_VERSION_H__ */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 2fdd400e92..cef89b837e 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -58,6 +58,7 @@
#define __HYPERVISOR_boot_vcpu 24
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
#define __HYPERVISOR_mmuext_op 26
+#define __HYPERVISOR_policy_op 27
/*
* VIRTUAL INTERRUPTS
@@ -200,8 +201,11 @@ struct mmuext_op {
#define SCHEDOP_yield 0 /* Give up the CPU voluntarily. */
#define SCHEDOP_block 1 /* Block until an event is received. */
#define SCHEDOP_shutdown 2 /* Stop executing this domain. */
+#define SCHEDOP_vcpu_down 3 /* make target VCPU not-runnable. */
+#define SCHEDOP_vcpu_up 4 /* make target VCPU runnable. */
#define SCHEDOP_cmdmask 255 /* 8-bit command. */
#define SCHEDOP_reasonshift 8 /* 8-bit reason code. (SCHEDOP_shutdown) */
+#define SCHEDOP_vcpushift 8 /* 8-bit VCPU target. (SCHEDOP_up|down) */
/*
* Reason codes for SCHEDOP_shutdown. These may be interpreted by control
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 35a3c36cab..ca21c5eee8 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -137,6 +137,8 @@ struct domain
cpumask_t cpumask;
struct arch_domain arch;
+
+ void *ssid; /* sHype security subject identifier */
};
struct domain_setup_info
@@ -346,6 +348,9 @@ extern struct domain *domain_list;
/* Initialization completed. */
#define _VCPUF_initialised 8
#define VCPUF_initialised (1UL<<_VCPUF_initialised)
+ /* VCPU is not-runnable */
+#define _VCPUF_down 9
+#define VCPUF_down (1UL<<_VCPUF_down)
/*
* Per-domain flags (domain_flags).
@@ -375,7 +380,7 @@ extern struct domain *domain_list;
static inline int domain_runnable(struct vcpu *v)
{
return ( (atomic_read(&v->pausecnt) == 0) &&
- !(v->vcpu_flags & (VCPUF_blocked|VCPUF_ctrl_pause)) &&
+ !(v->vcpu_flags & (VCPUF_blocked|VCPUF_ctrl_pause|VCPUF_down)) &&
!(v->domain->domain_flags & (DOMF_shutdown|DOMF_shuttingdown)) );
}
diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h
index 2004211589..57f7580ade 100644
--- a/xen/include/xen/smp.h
+++ b/xen/include/xen/smp.h
@@ -58,8 +58,6 @@ static inline int on_each_cpu(void (*func) (void *info), void *info,
return ret;
}
-extern int ht_per_core;
-
extern volatile unsigned long smp_msg_data;
extern volatile int smp_src_cpu;
extern volatile int smp_msg_id;
diff --git a/xen/include/xen/string.h b/xen/include/xen/string.h
index 384ee2cfce..0c6dd612ad 100644
--- a/xen/include/xen/string.h
+++ b/xen/include/xen/string.h
@@ -81,4 +81,9 @@ extern void * memchr(const void *,int,__kernel_size_t);
}
#endif
+#define safe_strcpy(d,s) \
+do { strncpy((d),(s),sizeof((d))); \
+ (d)[sizeof((d))-1] = '\0'; \
+} while (0)
+
#endif /* _LINUX_STRING_H_ */