[prev in list] [next in list] [prev in thread] [next in thread]
List: xense-devel
Subject: [Xen-devel] [Xense-devel] [PATCH] [4/4] ACM XSM Module
From: "George S. Coker, II" <gscoker () alpha ! ncsc ! mil>
Date: 2006-12-20 14:09:08
Message-ID: 1166623748.4824.267.camel () moss-walleye ! epoch ! ncsc ! mil
[Download RAW message or body]
This patch performs a minor refactoring of the existing ACM code to
create an ACM module for XSM. This patch does not effect the existing
ACM support for powerpc.
Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
["acm-xsm-121906-xen-unstable.diff" (acm-xsm-121906-xen-unstable.diff)]
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/Rules.mk
--- a/xen/Rules.mk Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/Rules.mk Tue Dec 19 20:18:02 2006 -0500
@@ -52,7 +52,7 @@ CFLAGS-$(FLASK_DEVELOP) += -DFLASK_DEV
CFLAGS-$(FLASK_DEVELOP) += -DFLASK_DEVELOP
CFLAGS-$(FLASK_BOOTPARAM) += -DFLASK_BOOTPARAM
CFLAGS-$(FLASK_AVC_STATS) += -DFLASK_AVC_STATS
-CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
+CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY -DXSM_MAGIC=0x0100bcde
CFLAGS-$(verbose) += -DVERBOSE
CFLAGS-$(crash_debug) += -DCRASH_DEBUG
CFLAGS-$(perfc) += -DPERF_COUNTERS
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/acm/Makefile
--- a/xen/acm/Makefile Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/acm/Makefile Tue Dec 19 20:18:02 2006 -0500
@@ -3,3 +3,4 @@ obj-y += acm_simple_type_enforcement_hoo
obj-y += acm_simple_type_enforcement_hooks.o
obj-y += acm_chinesewall_hooks.o
obj-y += acm_null_hooks.o
+obj-y += acm_xsm_hooks.o
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/acm/acm_core.c
--- a/xen/acm/acm_core.c Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/acm/acm_core.c Tue Dec 19 20:18:02 2006 -0500
@@ -31,6 +31,7 @@
#include <xen/multiboot.h>
#include <acm/acm_hooks.h>
#include <acm/acm_endian.h>
+#include <xsm/xsm.h>
/* debug:
* include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE;
@@ -48,6 +49,8 @@ void acm_init_ste_policy(void);
extern struct acm_operations acm_chinesewall_ops,
acm_simple_type_enforcement_ops, acm_null_ops;
+
+extern struct xsm_operations acm_xsm_ops;
/* global ACM policy (now dynamically determined at boot time) */
u16 acm_active_security_policy = ACM_POLICY_UNDEFINED;
@@ -201,46 +204,16 @@ acm_is_policy(char *buf, unsigned long l
return ntohl(pol->magic) == ACM_MAGIC;
}
-
-static int
-acm_setup(char *policy_start,
- unsigned long policy_len)
-{
- int rc = ACM_OK;
- struct acm_policy_buffer *pol;
-
- if (policy_start == NULL || policy_len < sizeof(struct acm_policy_buffer))
- return rc;
-
- pol = (struct acm_policy_buffer *)policy_start;
- if (ntohl(pol->magic) != ACM_MAGIC)
- return rc;
-
- rc = do_acm_set_policy((void *)policy_start, (u32)policy_len);
- if (rc == ACM_OK)
- {
- printkd("Policy len 0x%lx, start at %p.\n",policy_len,policy_start);
- }
- else
- {
- printk("Invalid policy.\n");
- /* load default policy later */
- acm_active_security_policy = ACM_POLICY_UNDEFINED;
- }
- return rc;
-}
-
-
-int
-acm_init(char *policy_start,
- unsigned long policy_len)
+static __init int acm_init(void)
{
int ret = ACM_OK;
+ printk("ACM-XSM: Initializing.\n");
+
acm_set_endian();
/* first try to load the boot policy (uses its own locks) */
- acm_setup(policy_start, policy_len);
+ do_acm_set_policy(policy_buffer, policy_size);
if (acm_active_security_policy != ACM_POLICY_UNDEFINED)
{
@@ -269,8 +242,14 @@ acm_init(char *policy_start,
/* here one could imagine a clean panic */
return -EINVAL;
}
+
+ if (register_xsm(&acm_xsm_ops))
+ panic("ACM-XSM: Unable to register with XSM.\n");
+
return ret;
}
+
+xsm_initcall(acm_init);
int
acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/arch/x86/setup.c Tue Dec 19 20:18:02 2006 -0500
@@ -26,7 +26,6 @@
#include <asm/desc.h>
#include <asm/shadow.h>
#include <asm/e820.h>
-#include <acm/acm_hooks.h>
#include <xen/kexec.h>
#include <xsm/xsm.h>
@@ -204,44 +203,6 @@ static void __init percpu_free_unused_ar
init_xenheap_pages(__pa(__per_cpu_start) + (first_unused << PERCPU_SHIFT),
__pa(__per_cpu_end));
#endif
-}
-
-/* Fetch acm policy module from multiboot modules. */
-static void extract_acm_policy(
- multiboot_info_t *mbi,
- unsigned int *initrdidx,
- char **_policy_start,
- unsigned long *_policy_len)
-{
- int i;
- module_t *mod = (module_t *)__va(mbi->mods_addr);
- unsigned long start, policy_len;
- char *policy_start;
-
- /*
- * Try all modules and see whichever could be the binary policy.
- * Adjust the initrdidx if module[1] is the binary policy.
- */
- for ( i = mbi->mods_count-1; i >= 1; i-- )
- {
- start = initial_images_start + (mod[i].mod_start-mod[0].mod_start);
-#if defined(__i386__)
- policy_start = (char *)start;
-#elif defined(__x86_64__)
- policy_start = __va(start);
-#endif
- policy_len = mod[i].mod_end - mod[i].mod_start;
- if ( acm_is_policy(policy_start, policy_len) )
- {
- printk("Policy len 0x%lx, start at %p - module %d.\n",
- policy_len, policy_start, i);
- *_policy_start = policy_start;
- *_policy_len = policy_len;
- if ( i == 1 )
- *initrdidx = (mbi->mods_count > 2) ? 2 : 0;
- break;
- }
- }
}
static void __init init_idle_domain(void)
@@ -294,8 +255,6 @@ void __init __start_xen(multiboot_info_t
char __cmdline[] = "", *cmdline = __cmdline;
unsigned long _initrd_start = 0, _initrd_len = 0;
unsigned int initrdidx = 1;
- char *_policy_start = NULL;
- unsigned long _policy_len = 0;
module_t *mod = (module_t *)__va(mbi->mods_addr);
unsigned long nr_pages, modules_length;
paddr_t s, e;
@@ -691,21 +650,12 @@ void __init __start_xen(multiboot_info_t
if ( opt_watchdog )
watchdog_enable();
- /* Extract policy from multiboot. */
- extract_acm_policy(mbi, &initrdidx, &_policy_start, &_policy_len);
-
- /* initialize access control security module */
- acm_init(_policy_start, _policy_len);
-
/* Create initial domain 0. */
dom0 = domain_create(0, 0);
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
panic("Error creating domain 0\n");
dom0->is_privileged = 1;
-
- /* Post-create hook sets security label. */
- acm_post_domain0_create(dom0->domain_id);
xsm_complete_init(dom0);
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/arch/x86/x86_32/entry.S Tue Dec 19 20:18:02 2006 -0500
@@ -657,7 +657,7 @@ ENTRY(hypercall_table)
.long do_vcpu_op
.long do_ni_hypercall /* 25 */
.long do_mmuext_op
- .long do_acm_op
+ .long do_xsm_op
.long do_nmi_op
.long do_sched_op
.long do_callback_op /* 30 */
@@ -668,7 +668,6 @@ ENTRY(hypercall_table)
.long do_sysctl /* 35 */
.long do_domctl
.long do_kexec_op
- .long do_xsm_op
.rept NR_hypercalls-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
@@ -701,7 +700,7 @@ ENTRY(hypercall_args_table)
.byte 3 /* do_vcpu_op */
.byte 0 /* do_ni_hypercall */ /* 25 */
.byte 4 /* do_mmuext_op */
- .byte 1 /* do_acm_op */
+ .byte 1 /* do_xsm_op */
.byte 2 /* do_nmi_op */
.byte 2 /* do_sched_op */
.byte 2 /* do_callback_op */ /* 30 */
@@ -712,7 +711,6 @@ ENTRY(hypercall_args_table)
.byte 1 /* do_sysctl */ /* 35 */
.byte 1 /* do_domctl */
.byte 2 /* do_kexec_op */
- .byte 1 /* do_xsm_op */
.rept NR_hypercalls-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/common/domctl.c
--- a/xen/common/domctl.c Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/common/domctl.c Tue Dec 19 20:18:02 2006 -0500
@@ -20,7 +20,6 @@
#include <xen/guest_access.h>
#include <asm/current.h>
#include <public/domctl.h>
-#include <acm/acm_hooks.h>
#include <xsm/xsm.h>
extern long arch_do_domctl(
@@ -120,11 +119,6 @@ void getdomaininfo(struct domain *d, str
if ( is_hvm_domain(d) )
info->flags |= XEN_DOMINF_hvm_guest;
- if ( d->ssid != NULL )
- info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
- else
- info->ssidref = ACM_DEFAULT_SSID;
-
xsm_security_domaininfo(d, info);
info->tot_pages = d->tot_pages;
@@ -176,7 +170,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
{
long ret = 0;
struct xen_domctl curop, *op = &curop;
- void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
static DEFINE_SPINLOCK(domctl_lock);
if ( !IS_PRIV(current->domain) )
@@ -187,9 +180,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION )
return -EACCES;
-
- if ( acm_pre_domctl(op, &ssid) )
- return -EPERM;
spin_lock(&domctl_lock);
@@ -747,11 +737,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
}
spin_unlock(&domctl_lock);
-
- if ( ret == 0 )
- acm_post_domctl(op, &ssid);
- else
- acm_fail_domctl(op, &ssid);
return ret;
}
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/common/event_channel.c
--- a/xen/common/event_channel.c Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/common/event_channel.c Tue Dec 19 20:18:02 2006 -0500
@@ -28,7 +28,6 @@
#include <public/xen.h>
#include <public/event_channel.h>
-#include <acm/acm_hooks.h>
#include <xsm/xsm.h>
#define bucket_from_port(d,p) \
@@ -110,9 +109,6 @@ static long evtchn_alloc_unbound(evtchn_
domid_t dom = alloc->dom;
long rc;
- if ( (rc = acm_pre_eventchannel_unbound(dom, alloc->remote_dom)) != 0 )
- return rc;
-
if ( dom == DOMID_SELF )
dom = current->domain->domain_id;
else if ( !IS_PRIV(current->domain) )
@@ -153,9 +149,6 @@ static long evtchn_bind_interdomain(evtc
int lport, rport = bind->remote_port;
domid_t rdom = bind->remote_dom;
long rc;
-
- if ( (rc = acm_pre_eventchannel_interdomain(rdom)) != 0 )
- return rc;
if ( rdom == DOMID_SELF )
rdom = current->domain->domain_id;
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/common/grant_table.c
--- a/xen/common/grant_table.c Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/common/grant_table.c Tue Dec 19 20:18:02 2006 -0500
@@ -33,7 +33,6 @@
#include <xen/trace.h>
#include <xen/guest_access.h>
#include <xen/domain_page.h>
-#include <acm/acm_hooks.h>
#include <xsm/xsm.h>
/*
@@ -115,12 +114,6 @@ __gnttab_map_grant_ref(
gdprintk(XENLOG_INFO, "Bad ref (%d) or flags (%x).\n",
op->ref, op->flags);
op->status = GNTST_bad_gntref;
- return;
- }
-
- if ( acm_pre_grant_map_ref(op->dom) )
- {
- op->status = GNTST_permission_denied;
return;
}
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/include/acm/acm_hooks.h
--- a/xen/include/acm/acm_hooks.h Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/include/acm/acm_hooks.h Tue Dec 19 20:18:02 2006 -0500
@@ -370,8 +370,6 @@ static inline int acm_sharing(ssidref_t
}
-extern int acm_init(char *policy_start, unsigned long policy_len);
-
/* Return true iff buffer has an acm policy magic number. */
extern int acm_is_policy(char *buf, unsigned long len);
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/include/public/xen.h
--- a/xen/include/public/xen.h Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/include/public/xen.h Tue Dec 19 20:18:02 2006 -0500
@@ -71,7 +71,7 @@
#define __HYPERVISOR_vcpu_op 24
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
#define __HYPERVISOR_mmuext_op 26
-#define __HYPERVISOR_acm_op 27
+#define __HYPERVISOR_xsm_op 27
#define __HYPERVISOR_nmi_op 28
#define __HYPERVISOR_sched_op 29
#define __HYPERVISOR_callback_op 30
@@ -82,7 +82,6 @@
#define __HYPERVISOR_sysctl 35
#define __HYPERVISOR_domctl 36
#define __HYPERVISOR_kexec_op 37
-#define __HYPERVISOR_xsm_op 38
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/include/xen/hypercall.h
--- a/xen/include/xen/hypercall.h Sat Dec 16 11:53:48 2006 -0500
+++ b/xen/include/xen/hypercall.h Tue Dec 19 20:18:02 2006 -0500
@@ -12,7 +12,6 @@
#include <public/domctl.h>
#include <public/sysctl.h>
#include <public/platform.h>
-#include <public/acm_ops.h>
#include <public/event_channel.h>
#include <asm/hypercall.h>
#include <xsm/xsm.h>
@@ -90,8 +89,9 @@ do_vcpu_op(
XEN_GUEST_HANDLE(void) arg);
extern long
-do_acm_op(
- int cmd, XEN_GUEST_HANDLE(void) arg);
+do_xsm_op(
+ int cmd,
+ XEN_GUEST_HANDLE(xsm_op_t) u_xsm_op);
extern long
do_nmi_op(
@@ -109,9 +109,4 @@ do_kexec_op(
int arg1,
XEN_GUEST_HANDLE(void) arg);
-extern long
-do_xsm_op(
- int cmd,
- XEN_GUEST_HANDLE(xsm_op_t) u_xsm_op);
-
#endif /* __XEN_HYPERCALL_H__ */
diff -r 65bfdf932c7e -r 2fc5e8f646c7 xen/acm/acm_xsm_hooks.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/xen/acm/acm_xsm_hooks.c Tue Dec 19 20:18:02 2006 -0500
@@ -0,0 +1,195 @@
+/****************************************************************
+ * acm_xsm_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * sHype hooks for XSM based on the original ACM hooks.
+ *
+ * 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 <xsm/xsm.h>
+#include <acm/acm_hooks.h>
+#include <public/acm.h>
+
+static int acm_createdomain (struct xen_domctl *op)
+{
+ void *subject_ssid = current->domain->ssid;
+ ssidref_t ssidref = op->u.createdomain.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 void acm_createdomain_post (struct domain *d, struct xen_domctl *op)
+{
+ ssidref_t ssidref = op->u.createdomain.ssidref;
+
+ /* initialialize shared sHype security labels for new domain */
+ acm_init_domain_ssid(d->domain_id, ssidref);
+
+ if (acm_primary_ops->post_domain_create != NULL)
+ acm_primary_ops->post_domain_create(d->domain_id, ssidref);
+ if (acm_secondary_ops->post_domain_create != NULL)
+ acm_secondary_ops->post_domain_create(d->domain_id, ssidref);
+}
+
+static int acm_destroydomain (struct domain *d)
+{
+ int ret = -EACCES;
+ void *ssid = NULL;
+
+ if (d != NULL) {
+ ssid = d->ssid;
+
+ if (ssid == NULL) {
+ printk("%s: Warning. Destroying domain without ssid pointer.\n", __func__);
+ return -EACCES;
+ }
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void acm_destroydomain_post (struct domain *d)
+{
+ domid_t id = d->domain_id;
+
+ if (acm_primary_ops->post_domain_destroy != NULL)
+ acm_primary_ops->post_domain_destroy(d->ssid, id);
+ if (acm_secondary_ops->post_domain_destroy != NULL)
+ acm_secondary_ops->post_domain_destroy(d->ssid, id);
+
+ /* free security ssid for the destroyed domain (also if null policy */
+ acm_free_domain_ssid((struct acm_ssid_domain *)(d->ssid));
+ d->ssid = NULL;
+}
+
+static void acm_createdomain_fail (struct xen_domctl *op)
+{
+ acm_fail_domain_create(
+ current->domain->ssid, op->u.createdomain.ssidref);
+}
+
+static int acm_grant_mapref (struct domain *ld, struct domain *rd,
+ uint32_t flags)
+{
+ domid_t id = rd->domain_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 int acm_evtchn_unbound (struct domain *d1, struct evtchn *chn1, domid_t id2)
+{
+ domid_t id1 = d1->domain_id;
+
+ if ((acm_primary_ops->pre_eventchannel_unbound != NULL) &&
+ acm_primary_ops->pre_eventchannel_unbound(id1, id2))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) &&
+ acm_secondary_ops->pre_eventchannel_unbound(id1, id2)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_eventchannel_unbound != NULL)
+ acm_primary_ops->fail_eventchannel_unbound(id1, id2);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static int acm_evtchn_interdomain (struct domain *d1, struct evtchn *chn1,
+ struct domain *d2, struct evtchn *chn2)
+{
+ domid_t id2 = d2->domain_id;
+
+ if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) &&
+ acm_primary_ops->pre_eventchannel_interdomain(id2))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) &&
+ acm_secondary_ops->pre_eventchannel_interdomain(id2)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_eventchannel_interdomain != NULL)
+ acm_primary_ops->fail_eventchannel_interdomain(id2);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static void acm_complete_init (struct domain *dom0)
+{
+ domid_t domid = dom0->domain_id;
+
+ acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF);
+
+ if (acm_primary_ops->post_domain_create != NULL)
+ acm_primary_ops->post_domain_create(domid, ACM_DOM0_SSIDREF);
+ if (acm_secondary_ops->post_domain_create != NULL)
+ acm_secondary_ops->post_domain_create(domid, ACM_DOM0_SSIDREF);
+
+}
+
+static void acm_security_domaininfo (struct domain *d,
+ struct xen_domctl_getdomaininfo *info)
+{
+ if (d->ssid != NULL)
+ info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
+ else
+ info->ssidref = ACM_DEFAULT_SSID;
+}
+
+extern long do_acm_op(int cmd, XEN_GUEST_HANDLE(xsm_op_t) arg);
+
+struct xsm_operations acm_xsm_ops = {
+ .createdomain = acm_createdomain,
+ .createdomain_post = acm_createdomain_post,
+ .createdomain_fail = acm_createdomain_fail,
+ .destroydomain = acm_destroydomain,
+ .free_security_domain = acm_destroydomain_post,
+
+ .grant_mapref = acm_grant_mapref,
+
+ .evtchn_unbound = acm_evtchn_unbound,
+ .evtchn_interdomain = acm_evtchn_interdomain,
+ .complete_init = acm_complete_init,
+
+ .security_domaininfo = acm_security_domaininfo,
+
+ .__do_xsm_op = do_acm_op,
+};
_______________________________________________
Xense-devel mailing list
Xense-devel@lists.xensource.com
http://lists.xensource.com/xense-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic