diff options
121 files changed, 8904 insertions, 615 deletions
@@ -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 @@ -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_ */ |