From 0b86412f9dad3c5cd990e51b0501f8551353e111 Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Wed, 17 Aug 2005 14:37:22 +0000 Subject: [PATCH 01/36] Make xm save/restore work for SMP guest domains. Signed-off-by: Steven Smith, sos22@cam.ac.uk --- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index 445daf01e6..eb4d712ec7 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #define SHUTDOWN_INVALID -1 #define SHUTDOWN_POWEROFF 0 @@ -58,7 +60,12 @@ EXPORT_SYMBOL(machine_power_off); /* Ignore multiple shutdown requests. */ static int shutting_down = SHUTDOWN_INVALID; -static void __do_suspend(void) +#ifndef CONFIG_HOTPLUG_CPU +#define cpu_down(x) (-EOPNOTSUPP) +#define cpu_up(x) (-EOPNOTSUPP) +#endif + +static int __do_suspend(void *ignore) { int i, j; suspend_record_t *suspend_record; @@ -104,10 +111,49 @@ static void __do_suspend(void) extern unsigned long max_pfn; extern unsigned int *pfn_to_mfn_frame_list; + cpumask_t feasible_cpus; + int err = 0; + + BUG_ON(smp_processor_id() != 0); + BUG_ON(in_interrupt()); + +#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU) + if (num_online_cpus() > 1) { + printk(KERN_WARNING "Can't suspend SMP guests without CONFIG_HOTPLUG_CPU\n"); + return -EOPNOTSUPP; + } +#endif + suspend_record = (suspend_record_t *)__get_free_page(GFP_KERNEL); if ( suspend_record == NULL ) goto out; + /* Take all of the other cpus offline. We need to be careful not + to get preempted between the final test for num_online_cpus() + == 1 and disabling interrupts, since otherwise userspace could + bring another cpu online, and then we'd be stuffed. At the + same time, cpu_down can reschedule, so we need to enable + preemption while doing that. This kind of sucks, but should be + correct. */ + /* (We don't need to worry about other cpus bringing stuff up, + since by the time num_online_cpus() == 1, there aren't any + other cpus) */ + cpus_clear(feasible_cpus); + preempt_disable(); + while (num_online_cpus() > 1) { + preempt_enable(); + for_each_online_cpu(i) { + if (i == 0) + continue; + err = cpu_down(i); + if (err != 0) { + printk(KERN_CRIT "Failed to take all CPUs down: %d.\n", err); + goto out_reenable_cpus; + } + cpu_set(i, feasible_cpus); + } + } + suspend_record->nr_pfns = max_pfn; /* final number of pfns */ __cli(); @@ -141,8 +187,11 @@ static void __do_suspend(void) memcpy(&suspend_record->resume_info, &xen_start_info, sizeof(xen_start_info)); + /* We'll stop somewhere inside this hypercall. When it returns, + we'll start resuming after the restore. */ HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT); + shutting_down = SHUTDOWN_INVALID; memcpy(&xen_start_info, &suspend_record->resume_info, @@ -182,11 +231,26 @@ static void __do_suspend(void) usbif_resume(); + preempt_enable(); + __sti(); + out_reenable_cpus: + while (!cpus_empty(feasible_cpus)) { + i = first_cpu(feasible_cpus); + j = cpu_up(i); + if (j != 0) { + printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n", + i, j); + err = j; + } + cpu_clear(i, feasible_cpus); + } + out: if ( suspend_record != NULL ) free_page((unsigned long)suspend_record); + return err; } static int shutdown_process(void *__unused) @@ -233,6 +297,18 @@ static int shutdown_process(void *__unused) return 0; } +static struct task_struct *kthread_create_on_cpu(int (*f)(void *arg), + void *arg, + const char *name, + int cpu) +{ + struct task_struct *p; + p = kthread_create(f, arg, name); + kthread_bind(p, cpu); + wake_up_process(p); + return p; +} + static void __shutdown_handler(void *unused) { int err; @@ -245,7 +321,7 @@ static void __shutdown_handler(void *unused) } else { - __do_suspend(); + kthread_create_on_cpu(__do_suspend, NULL, "suspender", 0); } } From fd148643e4c2fe687334539077df3b526aae7a0b Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 15:27:55 +0000 Subject: [PATCH 02/36] Actually make suspending SMP domUs work: the previous commit didn't bring the other vcpus up correctly. Signed-off-by: Steven Smith, sos22@cam.ac.uk --- .../arch/xen/i386/kernel/process.c | 21 ++--- .../arch/xen/i386/kernel/smp.c | 11 ++- .../arch/xen/i386/kernel/smpboot.c | 16 ++++ .../arch/xen/i386/kernel/time.c | 2 +- linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c | 1 + linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c | 77 ++++++++++++++++++- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 70 ++++++++++++++++- .../include/asm-xen/asm-i386/hypercall.h | 32 ++++++-- xen/arch/x86/domain.c | 25 +++++- xen/arch/x86/mm.c | 17 +++- xen/arch/x86/time.c | 2 +- xen/common/domain.c | 12 ++- xen/common/event_channel.c | 17 ++++ xen/common/schedule.c | 40 +++++++++- xen/include/public/xen.h | 1 + 15 files changed, 310 insertions(+), 34 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c index 76e5d04801..39cf60d6e4 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c @@ -115,20 +115,12 @@ void xen_idle(void) /* We don't actually take CPU down, just spin without interrupts. */ static inline void play_dead(void) { - /* Ack it */ - __get_cpu_var(cpu_state) = CPU_DEAD; - - /* We shouldn't have to disable interrupts while dead, but - * some interrupts just don't seem to go away, and this makes - * it "work" for testing purposes. */ /* Death loop */ while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) HYPERVISOR_yield(); - local_irq_disable(); __flush_tlb_all(); cpu_set(smp_processor_id(), cpu_online_map); - local_irq_enable(); } #else static inline void play_dead(void) @@ -156,12 +148,23 @@ void cpu_idle (void) rmb(); if (cpu_is_offline(cpu)) { + printk("<0>Cpu %d going offline.\n", + cpu); + local_irq_disable(); + /* Ack it. From this point on until + we get woken up, we're not allowed + to take any locks. In particular, + don't printk. */ + __get_cpu_var(cpu_state) = CPU_DEAD; #if defined(CONFIG_XEN) && defined(CONFIG_HOTPLUG_CPU) /* Tell hypervisor to take vcpu down. */ HYPERVISOR_vcpu_down(cpu); #endif play_dead(); - } + local_irq_enable(); + printk("<0>Cpu %d back online.\n", + cpu); + } __get_cpu_var(irq_stat).idle_timestamp = jiffies; xen_idle(); diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c index 56729ce885..38c2dfd883 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c @@ -129,9 +129,12 @@ static inline int __prepare_ICR2 (unsigned int mask) DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); +unsigned uber_debug; + static inline void __send_IPI_one(unsigned int cpu, int vector) { unsigned int evtchn; + int r; evtchn = per_cpu(ipi_to_evtchn, cpu)[vector]; // printk("send_IPI_mask_bitmask cpu %d vector %d evtchn %d\n", cpu, vector, evtchn); @@ -142,7 +145,11 @@ static inline void __send_IPI_one(unsigned int cpu, int vector) synch_test_bit(evtchn, &s->evtchn_mask[0])) ; #endif - notify_via_evtchn(evtchn); + if (uber_debug) + printk("<0>Notifying on evtchn %d.\n", evtchn); + if ((r = notify_via_evtchn(evtchn)) != 0) + printk("<0>Hypervisor stopped us sending an IPI: %d.\n", + r); } else printk("send_IPI to unbound port %d/%d", cpu, vector); @@ -161,6 +168,8 @@ void __send_IPI_shortcut(unsigned int shortcut, int vector) if (cpu == smp_processor_id()) continue; if (cpu_isset(cpu, cpu_online_map)) { + if (uber_debug) + printk("<0>Sending ipi to %d.\n", cpu); __send_IPI_one(cpu, vector); } } diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index ea82103e06..1fa524b0e8 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1616,3 +1616,19 @@ void smp_resume(void) smp_intr_init(); local_setup_timer_irq(); } + +DECLARE_PER_CPU(int, timer_irq); + +void _restore_vcpu(void) +{ + int cpu = smp_processor_id(); + /* We are the first thing the vcpu runs when it comes back, + and we are supposed to restore the IPIs and timer + interrupts etc. When we return, the vcpu's idle loop will + start up again. */ + printk("<0>_restore_vcpu %d.\n", cpu); + _bind_virq_to_irq(VIRQ_TIMER, cpu, per_cpu(timer_irq, cpu)); + _bind_virq_to_irq(VIRQ_DEBUG, cpu, per_cpu(ldebug_irq, cpu)); + _bind_ipi_to_irq(RESCHEDULE_VECTOR, cpu, per_cpu(resched_irq, cpu) ); + _bind_ipi_to_irq(CALL_FUNCTION_VECTOR, cpu, per_cpu(callfunc_irq, cpu) ); +} diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c index 9a9e160550..3b85e34798 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c @@ -745,7 +745,7 @@ static void __init hpet_time_init(void) #endif /* Dynamically-mapped IRQ. */ -static DEFINE_PER_CPU(int, timer_irq); +DEFINE_PER_CPU(int, timer_irq); static struct irqaction irq_timer = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer0", diff --git a/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c b/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c index a826b7e38f..e66a186487 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c @@ -512,6 +512,7 @@ no_context: printk("%08lx\n", regs->eip); dump_fault_path(address); die("Oops", regs, error_code); + while(1); bust_spinlocks(0); do_exit(SIGKILL); diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c index 2abfd67c4b..99d1c76ef0 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c @@ -134,6 +134,8 @@ void force_evtchn_callback(void) (void)HYPERVISOR_xen_version(0); } +extern unsigned uber_debug; + /* NB. Interrupts are disabled on entry. */ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) { @@ -145,6 +147,8 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) vcpu_info->evtchn_upcall_pending = 0; + if (uber_debug && cpu != 0) + printk("<0>evtchn_do_upcall on %d.\n", cpu); /* NB. No need for a barrier here -- XCHG is a barrier on x86. */ l1 = xchg(&vcpu_info->evtchn_pending_sel, 0); while ( l1 != 0 ) @@ -158,9 +162,13 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) l2 &= ~(1 << l2i); port = (l1i << 5) + l2i; - if ( (irq = evtchn_to_irq[port]) != -1 ) + if (uber_debug && cpu != 0) + printk("<0>Port %d.\n", port); + if ( (irq = evtchn_to_irq[port]) != -1 ) { + if (uber_debug && cpu != 0) + printk("<0>irq %d.\n", irq); do_IRQ(irq, regs); - else + } else evtchn_device_upcall(port); } } @@ -245,6 +253,71 @@ void unbind_virq_from_irq(int virq) spin_unlock(&irq_mapping_update_lock); } +/* This is only used when a vcpu from an xm save. The ipi is expected + to have been bound before we suspended, and so all of the xenolinux + state is set up; we only need to restore the Xen side of things. + The irq number has to be the same, but the evtchn number can + change. */ +void _bind_ipi_to_irq(int ipi, int vcpu, int irq) +{ + evtchn_op_t op; + int evtchn; + + spin_lock(&irq_mapping_update_lock); + + op.cmd = EVTCHNOP_bind_ipi; + if ( HYPERVISOR_event_channel_op(&op) != 0 ) + panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, vcpu); + evtchn = op.u.bind_ipi.port; + + printk("<0>IPI %d, old evtchn %d, evtchn %d.\n", + ipi, per_cpu(ipi_to_evtchn, vcpu)[ipi], + evtchn); + + evtchn_to_irq[irq_to_evtchn[irq]] = -1; + irq_to_evtchn[irq] = -1; + + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; + + per_cpu(ipi_to_evtchn, vcpu)[ipi] = evtchn; + + bind_evtchn_to_cpu(evtchn, vcpu); + + spin_unlock(&irq_mapping_update_lock); + + clear_bit(evtchn, HYPERVISOR_shared_info->evtchn_mask); +} + +void _bind_virq_to_irq(int virq, int cpu, int irq) +{ + evtchn_op_t op; + int evtchn; + + spin_lock(&irq_mapping_update_lock); + + op.cmd = EVTCHNOP_bind_virq; + op.u.bind_virq.virq = virq; + if ( HYPERVISOR_event_channel_op(&op) != 0 ) + panic("Failed to bind virtual IRQ %d\n", virq); + evtchn = op.u.bind_virq.port; + + + evtchn_to_irq[irq_to_evtchn[irq]] = -1; + irq_to_evtchn[irq] = -1; + + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; + + per_cpu(virq_to_irq, cpu)[virq] = irq; + + bind_evtchn_to_cpu(evtchn, cpu); + + spin_unlock(&irq_mapping_update_lock); + + return irq; +} + int bind_ipi_to_irq(int ipi) { evtchn_op_t op; diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index eb4d712ec7..b1e4e697d6 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -65,10 +65,56 @@ static int shutting_down = SHUTDOWN_INVALID; #define cpu_up(x) (-EOPNOTSUPP) #endif +static void save_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt) +{ + int r; + int gdt_pages; + r = HYPERVISOR_vcpu_pickle(vcpu, ctxt); + BUG_ON(r != 0); + gdt_pages = (ctxt->gdt_ents + 511) / 512; + ctxt->ctrlreg[3] = machine_to_phys(ctxt->ctrlreg[3]); + for (r = 0; r < gdt_pages; r++) { + ctxt->gdt_frames[r] = mfn_to_pfn(ctxt->gdt_frames[r]); + } +} + +void _restore_vcpu(int cpu); + +static void restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt) +{ + int r; + int gdt_pages = (ctxt->gdt_ents + 511) / 512; + + /* This is kind of a hack, and implicitly relies on the fact that + the vcpu stops in a place where all of the call clobbered + registers are already dead. */ + printk("<0>regs.esp %x.\n", ctxt->user_regs.esp); + ctxt->user_regs.esp -= 4; + ((unsigned long *)ctxt->user_regs.esp)[0] = ctxt->user_regs.eip; + ctxt->user_regs.eip = (unsigned long)_restore_vcpu; + + ctxt->ctrlreg[3] = phys_to_machine(ctxt->ctrlreg[3]); + for (r = 0; r < gdt_pages; r++) { + ctxt->gdt_frames[r] = pfn_to_mfn(ctxt->gdt_frames[r]); + } + r = HYPERVISOR_boot_vcpu(vcpu, ctxt); + if (r != 0) { + printk(KERN_EMERG "Failed to reboot vcpu %d (%d)\n", vcpu, r); + return; + } +} + +/* Whoever decided that printk should call into the scheduler needs to + be taken out and shot */ +#define msg(x) HYPERVISOR_console_io(CONSOLEIO_write, sizeof(x), x) + +extern unsigned uber_debug; + static int __do_suspend(void *ignore) { int i, j; suspend_record_t *suspend_record; + static vcpu_guest_context_t suspended_cpu_records[NR_CPUS]; /* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */ /* XXX SMH: yes it would :-( */ @@ -158,6 +204,10 @@ static int __do_suspend(void *ignore) __cli(); + for (i = 0; i < NR_CPUS; i++) + if (cpu_isset(i, feasible_cpus)) + save_vcpu_context(i, &suspended_cpu_records[i]); + #ifdef __i386__ mm_pin_all(); kmem_cache_shrink(pgd_cache); @@ -173,7 +223,9 @@ static int __do_suspend(void *ignore) smp_suspend(); #endif + msg("xenbus going down.\n"); xenbus_suspend(); + msg("xenbus gone down.\n"); ctrl_if_suspend(); @@ -187,10 +239,11 @@ static int __do_suspend(void *ignore) memcpy(&suspend_record->resume_info, &xen_start_info, sizeof(xen_start_info)); + msg("Suspending...\n"); /* We'll stop somewhere inside this hypercall. When it returns, we'll start resuming after the restore. */ HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT); - + msg("Back from suspension\n"); shutting_down = SHUTDOWN_INVALID; @@ -217,7 +270,9 @@ static int __do_suspend(void *ignore) ctrl_if_resume(); + msg("Here comes the xenbus...\n"); xenbus_resume(); + msg("xenbus resumed.\n"); #ifdef CONFIG_SMP smp_resume(); @@ -231,21 +286,32 @@ static int __do_suspend(void *ignore) usbif_resume(); - preempt_enable(); + msg("Restoring cpu contexts...\n"); + for (i = 0; i < NR_CPUS; i++) + if (cpu_isset(i, feasible_cpus)) + restore_vcpu_context(i, &suspended_cpu_records[i]); + msg("All vcpus rebooted.\n"); __sti(); out_reenable_cpus: + msg("Reenabling cpus.\n"); while (!cpus_empty(feasible_cpus)) { i = first_cpu(feasible_cpus); + printk("<0>Bring up %d/%d.\n", i, num_online_cpus()); + printk("<0>17 preempt_count %x.\n", preempt_count()); j = cpu_up(i); + printk("<0>18 preempt_count %x.\n", preempt_count()); if (j != 0) { printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n", i, j); err = j; } + printk("<0>%d up.\n", i); cpu_clear(i, feasible_cpus); } + msg("Reenabled cpus.\n"); + uber_debug = 0; out: if ( suspend_record != NULL ) diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h index e4b7f781e8..3491eef3c1 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h @@ -163,7 +163,7 @@ HYPERVISOR_yield( TRAP_INSTR : "=a" (ret), "=b" (ign) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_yield) - : "memory" ); + : "memory", "ecx" ); return ret; } @@ -178,7 +178,7 @@ HYPERVISOR_block( TRAP_INSTR : "=a" (ret), "=b" (ign1) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_block) - : "memory" ); + : "memory", "ecx" ); return ret; } @@ -194,7 +194,7 @@ HYPERVISOR_shutdown( : "=a" (ret), "=b" (ign1) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift)) - : "memory" ); + : "memory", "ecx" ); return ret; } @@ -210,7 +210,7 @@ HYPERVISOR_reboot( : "=a" (ret), "=b" (ign1) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift)) - : "memory" ); + : "memory", "ecx" ); return ret; } @@ -228,7 +228,7 @@ HYPERVISOR_suspend( : "=a" (ret), "=b" (ign1), "=S" (ign2) : "0" (__HYPERVISOR_sched_op), "b" (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)), - "S" (srec) : "memory"); + "S" (srec) : "memory", "ecx"); return ret; } @@ -244,7 +244,7 @@ HYPERVISOR_crash( : "=a" (ret), "=b" (ign1) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_shutdown | (SHUTDOWN_crash << SCHEDOP_reasonshift)) - : "memory" ); + : "memory", "ecx" ); return ret; } @@ -534,7 +534,7 @@ HYPERVISOR_vcpu_down( : "=a" (ret), "=b" (ign1) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift)) - : "memory" ); + : "memory", "ecx", "edx" ); return ret; } @@ -550,8 +550,26 @@ HYPERVISOR_vcpu_up( : "=a" (ret), "=b" (ign1) : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift)) + : "memory", "ecx" ); + + return ret; +} + +static inline int +HYPERVISOR_vcpu_pickle( + int vcpu, vcpu_guest_context_t *ctxt) +{ + int ret; + unsigned long ign1, ign2; + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret), "=b" (ign1), "=c" (ign2) + : "0" (__HYPERVISOR_sched_op), + "1" (SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)), + "2" (ctxt) : "memory" ); return ret; } + #endif /* __HYPERCALL_H__ */ diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index ad8716aac6..f52c9c5e5f 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -217,8 +217,16 @@ struct vcpu *arch_alloc_vcpu_struct(void) return xmalloc(struct vcpu); } +/* We assume that vcpu 0 is always the last one to be freed in a + domain i.e. if v->vcpu_id == 0, the domain should be + single-processor. */ void arch_free_vcpu_struct(struct vcpu *v) { + struct vcpu *p; + for_each_vcpu(v->domain, p) { + if (p->next_in_list == v) + p->next_in_list = v->next_in_list; + } xfree(v); } @@ -402,8 +410,10 @@ int arch_set_info_guest( if ( !(c->flags & VGCF_VMX_GUEST) ) { if ( ((c->user_regs.cs & 3) == 0) || - ((c->user_regs.ss & 3) == 0) ) - return -EINVAL; + ((c->user_regs.ss & 3) == 0) ) { + printf("User regs.cs %x, ss %x.\n", c->user_regs.cs, c->user_regs.ss); + return -EINVAL; + } } clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags); @@ -448,8 +458,10 @@ int arch_set_info_guest( if ( shadow_mode_refcounts(d) ) { - if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) + if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) { + printf("Bad phys_basetab %lx.\n", phys_basetab); return -EINVAL; + } } else { @@ -457,13 +469,16 @@ int arch_set_info_guest( if ( !(c->flags & VGCF_VMX_GUEST) ) #endif if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d, - PGT_base_page_table) ) + PGT_base_page_table) ) { + printf("Bad phys_basetab2 %lx.\n", phys_basetab); return -EINVAL; + } } if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 ) { put_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT]); + printf("Failed to set gdt, %d.\n", rc); return rc; } @@ -485,6 +500,8 @@ int arch_set_info_guest( /* Don't redo final setup */ set_bit(_VCPUF_initialised, &v->vcpu_flags); + printf("Arch set_info_guest succeeded.\n"); + return 0; } diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 78270ee57c..a920fadce9 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2631,16 +2631,25 @@ long set_gdt(struct vcpu *v, int i, nr_pages = (entries + 511) / 512; unsigned long pfn; - if ( entries > FIRST_RESERVED_GDT_ENTRY ) + if ( entries > FIRST_RESERVED_GDT_ENTRY ) { + printf("Too many entries in gdt (%d).\n", entries); return -EINVAL; + } shadow_sync_all(d); /* Check the pages in the new GDT. */ - for ( i = 0; i < nr_pages; i++ ) - if ( ((pfn = frames[i]) >= max_page) || - !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) ) + for ( i = 0; i < nr_pages; i++ ) { + pfn = frames[i]; + if (pfn >= max_page) { + printf("GDT bad as %ld >= %ld.\n", pfn, max_page); goto fail; + } + if (!get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) ) { + printf("Frame %ld looks bad.\n", pfn); + goto fail; + } + } /* Tear down the old GDT. */ destroy_gdt(v); diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 81100e7a1c..657231a86b 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -831,7 +831,7 @@ static void local_time_calibration(void *unused) tsc_elapsed32 = (u32)tsc_elapsed64; /* tsc_elapsed > stime_elapsed */ - ASSERT(tsc_elapsed32 != 0); + // ASSERT(tsc_elapsed32 != 0); while ( tsc_elapsed32 <= stime_elapsed32 ) { tsc_elapsed32 <<= 1; diff --git a/xen/common/domain.c b/xen/common/domain.c index b939d90f77..aee0b90140 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -178,6 +178,7 @@ void domain_shutdown(u8 reason) { struct domain *d = current->domain; struct vcpu *v; + int cntr; if ( d->domain_id == 0 ) { @@ -208,8 +209,17 @@ void domain_shutdown(u8 reason) } /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */ - for_each_vcpu ( d, v ) + cntr = 0; + printf("Putting %d to sleep.\n", d->domain_id); + for_each_vcpu ( d, v ) { + if (test_bit(_VCPUF_down, &v->vcpu_flags)) { + printf("vcpu %d is down.\n", v->vcpu_id); + } else { + printf("vcpu %d is up.\n", v->vcpu_id); + } domain_sleep_nosync(v); + } + printf("Put %d vcpus to sleep for domain shutdown.\n", cntr); } diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 21e11a69e4..8abb035479 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -292,6 +292,8 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind) chn = evtchn_from_port(d, port); chn->state = ECS_IPI; chn->notify_vcpu_id = current->vcpu_id; + printf("Bound ipi on vcpu %d to port %d.\n", current->vcpu_id, + port); } spin_unlock(&d->evtchn_lock); @@ -497,9 +499,24 @@ long evtchn_send(int lport) evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport); break; case ECS_IPI: + if (current->domain->domain_id != 0) { + printf("Set %d pending on %d.\n", lport, + lchn->notify_vcpu_id); + if (lport == 7) { + struct vcpu *v = ld->vcpu[lchn->notify_vcpu_id]; + struct domain *d = v->domain; + shared_info_t *s = d->shared_info; + printf("pending %x, mask %x, pending_sel %x, upcall_pending %x.\n", + s->evtchn_pending[0], + s->evtchn_mask[0], + v->vcpu_info->evtchn_pending_sel, + v->vcpu_info->evtchn_upcall_pending); + } + } evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); break; default: + printf("Failed to set %d pending: state %d.\n", lport, lchn->state); ret = -EINVAL; } diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 6cf1b7858d..d3d222b35b 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -38,6 +38,8 @@ #include #include +extern void arch_getdomaininfo_ctxt(struct vcpu *, + struct vcpu_guest_context *); /* opt_sched: scheduler - default to SEDF */ static char opt_sched[10] = "sedf"; string_param("sched", opt_sched); @@ -82,7 +84,8 @@ void free_domain_struct(struct domain *d) int i; SCHED_OP(free_task, d); - for (i = 0; i < MAX_VIRT_CPUS; i++) + /* vcpu 0 has to be the last one destructed. */ + for (i = MAX_VIRT_CPUS-1; i >= 0; i--) if ( d->vcpu[i] ) arch_free_vcpu_struct(d->vcpu[i]); @@ -295,10 +298,37 @@ static long do_vcpu_up(int vcpu) return 0; } +static long do_vcpu_pickle(int vcpu, unsigned long arg) +{ + struct vcpu *v; + vcpu_guest_context_t *c; + int ret = 0; + + if (vcpu >= MAX_VIRT_CPUS) + return -EINVAL; + v = current->domain->vcpu[vcpu]; + if (!v) + return -ESRCH; + /* Don't pickle vcpus which are currently running */ + if (!test_bit(_VCPUF_down, &v->vcpu_flags)) { + printf("Pickling a live vcpu?\n"); + return -EBUSY; + } + c = xmalloc(vcpu_guest_context_t); + if (!c) + return -ENOMEM; + arch_getdomaininfo_ctxt(v, c); + if (copy_to_user((vcpu_guest_context_t *)arg, + (const vcpu_guest_context_t *)c, sizeof(*c))) + ret = -EFAULT; + xfree(c); + return ret; +} + /* * Demultiplex scheduler-related hypercalls. */ -long do_sched_op(unsigned long op) +long do_sched_op(unsigned long op, unsigned long arg) { long ret = 0; @@ -334,6 +364,12 @@ long do_sched_op(unsigned long op) ret = do_vcpu_up((int)(op >> SCHEDOP_vcpushift)); break; } + case SCHEDOP_vcpu_pickle: + { + ret = do_vcpu_pickle((int)(op >> SCHEDOP_vcpushift), arg); + printf("Pickle result %ld.\n", ret); + break; + } default: ret = -ENOSYS; diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index ca156ca4f5..82b5023a31 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -203,6 +203,7 @@ struct mmuext_op { #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_vcpu_pickle 5 /* save a vcpu's context to memory. */ #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) */ From 1be1e1ccd3d263dd6998788d4f70f01c3b201329 Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 16:28:41 +0000 Subject: [PATCH 03/36] A really nasty workaround for a race. Signed-off-by: Steven Smith, sos22@cam.ac.uk --- .../arch/xen/i386/kernel/process.c | 4 -- .../arch/xen/i386/kernel/smp.c | 10 +---- .../arch/xen/i386/kernel/smpboot.c | 4 +- linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c | 1 - linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c | 16 ++------ linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 38 +++++++------------ .../include/asm-xen/asm-i386/hypercall.h | 3 ++ xen/arch/x86/domain.c | 15 ++------ xen/arch/x86/mm.c | 15 ++------ xen/arch/x86/time.c | 2 +- xen/common/domain.c | 12 +----- xen/common/event_channel.c | 17 --------- 12 files changed, 33 insertions(+), 104 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c index 39cf60d6e4..12a47fb4e3 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c @@ -148,8 +148,6 @@ void cpu_idle (void) rmb(); if (cpu_is_offline(cpu)) { - printk("<0>Cpu %d going offline.\n", - cpu); local_irq_disable(); /* Ack it. From this point on until we get woken up, we're not allowed @@ -162,8 +160,6 @@ void cpu_idle (void) #endif play_dead(); local_irq_enable(); - printk("<0>Cpu %d back online.\n", - cpu); } __get_cpu_var(irq_stat).idle_timestamp = jiffies; diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c index 38c2dfd883..4bb1453592 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c @@ -129,8 +129,6 @@ static inline int __prepare_ICR2 (unsigned int mask) DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); -unsigned uber_debug; - static inline void __send_IPI_one(unsigned int cpu, int vector) { unsigned int evtchn; @@ -145,11 +143,7 @@ static inline void __send_IPI_one(unsigned int cpu, int vector) synch_test_bit(evtchn, &s->evtchn_mask[0])) ; #endif - if (uber_debug) - printk("<0>Notifying on evtchn %d.\n", evtchn); - if ((r = notify_via_evtchn(evtchn)) != 0) - printk("<0>Hypervisor stopped us sending an IPI: %d.\n", - r); + notify_via_evtchn(evtchn); } else printk("send_IPI to unbound port %d/%d", cpu, vector); @@ -168,8 +162,6 @@ void __send_IPI_shortcut(unsigned int shortcut, int vector) if (cpu == smp_processor_id()) continue; if (cpu_isset(cpu, cpu_online_map)) { - if (uber_debug) - printk("<0>Sending ipi to %d.\n", cpu); __send_IPI_one(cpu, vector); } } diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index 1fa524b0e8..f47e809e60 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1622,13 +1622,15 @@ DECLARE_PER_CPU(int, timer_irq); void _restore_vcpu(void) { int cpu = smp_processor_id(); + extern atomic_t vcpus_rebooting; + /* We are the first thing the vcpu runs when it comes back, and we are supposed to restore the IPIs and timer interrupts etc. When we return, the vcpu's idle loop will start up again. */ - printk("<0>_restore_vcpu %d.\n", cpu); _bind_virq_to_irq(VIRQ_TIMER, cpu, per_cpu(timer_irq, cpu)); _bind_virq_to_irq(VIRQ_DEBUG, cpu, per_cpu(ldebug_irq, cpu)); _bind_ipi_to_irq(RESCHEDULE_VECTOR, cpu, per_cpu(resched_irq, cpu) ); _bind_ipi_to_irq(CALL_FUNCTION_VECTOR, cpu, per_cpu(callfunc_irq, cpu) ); + atomic_dec(&vcpus_rebooting); } diff --git a/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c b/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c index e66a186487..a826b7e38f 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c @@ -512,7 +512,6 @@ no_context: printk("%08lx\n", regs->eip); dump_fault_path(address); die("Oops", regs, error_code); - while(1); bust_spinlocks(0); do_exit(SIGKILL); diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c index 99d1c76ef0..6e3f3357be 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c @@ -134,8 +134,6 @@ void force_evtchn_callback(void) (void)HYPERVISOR_xen_version(0); } -extern unsigned uber_debug; - /* NB. Interrupts are disabled on entry. */ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) { @@ -147,8 +145,6 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) vcpu_info->evtchn_upcall_pending = 0; - if (uber_debug && cpu != 0) - printk("<0>evtchn_do_upcall on %d.\n", cpu); /* NB. No need for a barrier here -- XCHG is a barrier on x86. */ l1 = xchg(&vcpu_info->evtchn_pending_sel, 0); while ( l1 != 0 ) @@ -162,13 +158,9 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) l2 &= ~(1 << l2i); port = (l1i << 5) + l2i; - if (uber_debug && cpu != 0) - printk("<0>Port %d.\n", port); - if ( (irq = evtchn_to_irq[port]) != -1 ) { - if (uber_debug && cpu != 0) - printk("<0>irq %d.\n", irq); + if ( (irq = evtchn_to_irq[port]) != -1 ) do_IRQ(irq, regs); - } else + else evtchn_device_upcall(port); } } @@ -286,7 +278,7 @@ void _bind_ipi_to_irq(int ipi, int vcpu, int irq) spin_unlock(&irq_mapping_update_lock); - clear_bit(evtchn, HYPERVISOR_shared_info->evtchn_mask); + clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_mask); } void _bind_virq_to_irq(int virq, int cpu, int irq) @@ -314,8 +306,6 @@ void _bind_virq_to_irq(int virq, int cpu, int irq) bind_evtchn_to_cpu(evtchn, cpu); spin_unlock(&irq_mapping_update_lock); - - return irq; } int bind_ipi_to_irq(int ipi) diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index b1e4e697d6..ad6935ea73 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -73,13 +73,14 @@ static void save_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt) BUG_ON(r != 0); gdt_pages = (ctxt->gdt_ents + 511) / 512; ctxt->ctrlreg[3] = machine_to_phys(ctxt->ctrlreg[3]); - for (r = 0; r < gdt_pages; r++) { + for (r = 0; r < gdt_pages; r++) ctxt->gdt_frames[r] = mfn_to_pfn(ctxt->gdt_frames[r]); - } } void _restore_vcpu(int cpu); +atomic_t vcpus_rebooting; + static void restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt) { int r; @@ -88,26 +89,27 @@ static void restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt) /* This is kind of a hack, and implicitly relies on the fact that the vcpu stops in a place where all of the call clobbered registers are already dead. */ - printk("<0>regs.esp %x.\n", ctxt->user_regs.esp); ctxt->user_regs.esp -= 4; ((unsigned long *)ctxt->user_regs.esp)[0] = ctxt->user_regs.eip; ctxt->user_regs.eip = (unsigned long)_restore_vcpu; ctxt->ctrlreg[3] = phys_to_machine(ctxt->ctrlreg[3]); - for (r = 0; r < gdt_pages; r++) { + for (r = 0; r < gdt_pages; r++) ctxt->gdt_frames[r] = pfn_to_mfn(ctxt->gdt_frames[r]); - } + atomic_set(&vcpus_rebooting, 1); r = HYPERVISOR_boot_vcpu(vcpu, ctxt); if (r != 0) { printk(KERN_EMERG "Failed to reboot vcpu %d (%d)\n", vcpu, r); return; } + /* Hmm... slight hack: make sure the cpus come up in order, + because that way they get the same evtchn numbers this time as + they did last time, which works around a few bugs. */ + /* XXX */ + while (atomic_read(&vcpus_rebooting)) + barrier(); } -/* Whoever decided that printk should call into the scheduler needs to - be taken out and shot */ -#define msg(x) HYPERVISOR_console_io(CONSOLEIO_write, sizeof(x), x) - extern unsigned uber_debug; static int __do_suspend(void *ignore) @@ -223,9 +225,7 @@ static int __do_suspend(void *ignore) smp_suspend(); #endif - msg("xenbus going down.\n"); xenbus_suspend(); - msg("xenbus gone down.\n"); ctrl_if_suspend(); @@ -239,11 +239,9 @@ static int __do_suspend(void *ignore) memcpy(&suspend_record->resume_info, &xen_start_info, sizeof(xen_start_info)); - msg("Suspending...\n"); /* We'll stop somewhere inside this hypercall. When it returns, we'll start resuming after the restore. */ HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT); - msg("Back from suspension\n"); shutting_down = SHUTDOWN_INVALID; @@ -270,9 +268,7 @@ static int __do_suspend(void *ignore) ctrl_if_resume(); - msg("Here comes the xenbus...\n"); xenbus_resume(); - msg("xenbus resumed.\n"); #ifdef CONFIG_SMP smp_resume(); @@ -286,32 +282,26 @@ static int __do_suspend(void *ignore) usbif_resume(); - msg("Restoring cpu contexts...\n"); for (i = 0; i < NR_CPUS; i++) if (cpu_isset(i, feasible_cpus)) restore_vcpu_context(i, &suspended_cpu_records[i]); - msg("All vcpus rebooted.\n"); + printk("<0>All cpus rebooted...\n"); __sti(); out_reenable_cpus: - msg("Reenabling cpus.\n"); while (!cpus_empty(feasible_cpus)) { i = first_cpu(feasible_cpus); - printk("<0>Bring up %d/%d.\n", i, num_online_cpus()); - printk("<0>17 preempt_count %x.\n", preempt_count()); + printk("<0>Bring %d up.\n", i); j = cpu_up(i); - printk("<0>18 preempt_count %x.\n", preempt_count()); + printk("<0>cpu_up(%d) -> %d.\n", i, j); if (j != 0) { printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n", i, j); err = j; } - printk("<0>%d up.\n", i); cpu_clear(i, feasible_cpus); } - msg("Reenabled cpus.\n"); - uber_debug = 0; out: if ( suspend_record != NULL ) diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h index 3491eef3c1..cec6e2b9b2 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h @@ -529,6 +529,9 @@ HYPERVISOR_vcpu_down( { int ret; unsigned long ign1; + /* Yes, I really do want to clobber edx here: when we resume a + vcpu after unpickling a multi-processor domain, it returns + here, but clobbers all of the call clobbered registers. */ __asm__ __volatile__ ( TRAP_INSTR : "=a" (ret), "=b" (ign1) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index f52c9c5e5f..4f4187dda7 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -410,10 +410,8 @@ int arch_set_info_guest( if ( !(c->flags & VGCF_VMX_GUEST) ) { if ( ((c->user_regs.cs & 3) == 0) || - ((c->user_regs.ss & 3) == 0) ) { - printf("User regs.cs %x, ss %x.\n", c->user_regs.cs, c->user_regs.ss); + ((c->user_regs.ss & 3) == 0) ) return -EINVAL; - } } clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags); @@ -458,10 +456,8 @@ int arch_set_info_guest( if ( shadow_mode_refcounts(d) ) { - if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) { - printf("Bad phys_basetab %lx.\n", phys_basetab); + if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) return -EINVAL; - } } else { @@ -469,16 +465,13 @@ int arch_set_info_guest( if ( !(c->flags & VGCF_VMX_GUEST) ) #endif if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d, - PGT_base_page_table) ) { - printf("Bad phys_basetab2 %lx.\n", phys_basetab); + PGT_base_page_table) ) return -EINVAL; - } } if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 ) { put_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT]); - printf("Failed to set gdt, %d.\n", rc); return rc; } @@ -500,8 +493,6 @@ int arch_set_info_guest( /* Don't redo final setup */ set_bit(_VCPUF_initialised, &v->vcpu_flags); - printf("Arch set_info_guest succeeded.\n"); - return 0; } diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index a920fadce9..afb9dc482d 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2631,24 +2631,17 @@ long set_gdt(struct vcpu *v, int i, nr_pages = (entries + 511) / 512; unsigned long pfn; - if ( entries > FIRST_RESERVED_GDT_ENTRY ) { - printf("Too many entries in gdt (%d).\n", entries); + if ( entries > FIRST_RESERVED_GDT_ENTRY ) return -EINVAL; - } - + shadow_sync_all(d); /* Check the pages in the new GDT. */ for ( i = 0; i < nr_pages; i++ ) { pfn = frames[i]; - if (pfn >= max_page) { - printf("GDT bad as %ld >= %ld.\n", pfn, max_page); + if ((pfn >= max_page) || + !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) ) goto fail; - } - if (!get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) ) { - printf("Frame %ld looks bad.\n", pfn); - goto fail; - } } /* Tear down the old GDT. */ diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 657231a86b..81100e7a1c 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -831,7 +831,7 @@ static void local_time_calibration(void *unused) tsc_elapsed32 = (u32)tsc_elapsed64; /* tsc_elapsed > stime_elapsed */ - // ASSERT(tsc_elapsed32 != 0); + ASSERT(tsc_elapsed32 != 0); while ( tsc_elapsed32 <= stime_elapsed32 ) { tsc_elapsed32 <<= 1; diff --git a/xen/common/domain.c b/xen/common/domain.c index aee0b90140..b939d90f77 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -178,7 +178,6 @@ void domain_shutdown(u8 reason) { struct domain *d = current->domain; struct vcpu *v; - int cntr; if ( d->domain_id == 0 ) { @@ -209,17 +208,8 @@ void domain_shutdown(u8 reason) } /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */ - cntr = 0; - printf("Putting %d to sleep.\n", d->domain_id); - for_each_vcpu ( d, v ) { - if (test_bit(_VCPUF_down, &v->vcpu_flags)) { - printf("vcpu %d is down.\n", v->vcpu_id); - } else { - printf("vcpu %d is up.\n", v->vcpu_id); - } + for_each_vcpu ( d, v ) domain_sleep_nosync(v); - } - printf("Put %d vcpus to sleep for domain shutdown.\n", cntr); } diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 8abb035479..21e11a69e4 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -292,8 +292,6 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind) chn = evtchn_from_port(d, port); chn->state = ECS_IPI; chn->notify_vcpu_id = current->vcpu_id; - printf("Bound ipi on vcpu %d to port %d.\n", current->vcpu_id, - port); } spin_unlock(&d->evtchn_lock); @@ -499,24 +497,9 @@ long evtchn_send(int lport) evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport); break; case ECS_IPI: - if (current->domain->domain_id != 0) { - printf("Set %d pending on %d.\n", lport, - lchn->notify_vcpu_id); - if (lport == 7) { - struct vcpu *v = ld->vcpu[lchn->notify_vcpu_id]; - struct domain *d = v->domain; - shared_info_t *s = d->shared_info; - printf("pending %x, mask %x, pending_sel %x, upcall_pending %x.\n", - s->evtchn_pending[0], - s->evtchn_mask[0], - v->vcpu_info->evtchn_pending_sel, - v->vcpu_info->evtchn_upcall_pending); - } - } evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); break; default: - printf("Failed to set %d pending: state %d.\n", lport, lchn->state); ret = -EINVAL; } From 7f434cccbf339245034ee7022be26d15ae529c31 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 18:54:38 +0000 Subject: [PATCH 04/36] Update probe code for backend layout. Backend directories are of form backend///. This extra level makes an asymmetry with front ends (device/type/id) and are too long to make nice bus-ids under Linux, but the code isn't too horrible, and an OS which only wants to be a guest doesn't need to implement it. It allows backends to calculate the front-end path directly, which is a nice benefit. Also: subtype matching is tightened: they must match exactly. That way a future variant which requires a specific driver will not match current drivers. Signed-off-by: Rusty Russell Signed-off-by: Christian Limpach --- .../drivers/xen/xenbus/xenbus_probe.c | 382 ++++++++++++++---- linux-2.6-xen-sparse/include/asm-xen/xenbus.h | 14 +- 2 files changed, 308 insertions(+), 88 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 63923361a1..1af6f1d63e 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -48,15 +48,8 @@ static const struct xenbus_device_id * match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) { for (; !streq(arr->devicetype, ""); arr++) { - if (!streq(arr->devicetype, dev->devicetype)) - continue; - - /* If they don't care what subtype, it's a match. */ - if (streq(arr->subtype, "")) - return arr; - - /* If they care, device must have (same) subtype. */ - if (dev->subtype && streq(arr->subtype, dev->subtype)) + if (streq(arr->devicetype, dev->devicetype) && + streq(arr->subtype, dev->subtype ?: "")) return arr; } return NULL; @@ -72,10 +65,101 @@ static int xenbus_match(struct device *_dev, struct device_driver *_drv) return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; } +struct xen_bus_type +{ + char *root; + unsigned int levels; + int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); + int (*probe)(const char *type, const char *dir); + struct bus_type bus; +}; + +/* device// => - */ +static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) +{ + nodename = strchr(nodename, '/'); + if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) { + printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); + return -EINVAL; + } + + strlcpy(bus_id, nodename + 1, BUS_ID_SIZE); + if (!strchr(bus_id, '/')) { + printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); + return -EINVAL; + } + *strchr(bus_id, '/') = '-'; + return 0; +} + /* Bus type for frontend drivers. */ -static struct bus_type xenbus_type = { - .name = "xenbus", - .match = xenbus_match, +static int xenbus_probe_frontend(const char *type, const char *name); +static struct xen_bus_type xenbus_frontend = { + .root = "device", + .levels = 2, /* device/type/ */ + .get_bus_id = frontend_bus_id, + .probe = xenbus_probe_frontend, + .bus = { + .name = "xenbus", + .match = xenbus_match, + }, +}; + +/* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ +int xenbus_uuid_to_domid(const char *uuid) +{ + int err, domid, len; + char path[strlen("/domain/") + 50]; + + len = strcspn(uuid, "/"); + if (snprintf(path, sizeof(path), "/domain/%.*s", len, uuid) + >= sizeof(path)) + return -ENOSPC; + err = xenbus_scanf(path, "id", "%i", &domid); + if (err != 1) + return err; + return domid; +} + +/* backend/// => -- */ +static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) +{ + unsigned int typelen, uuidlen; + int domid; + const char *p; + + nodename = strchr(nodename, '/'); + if (!nodename) + return -EINVAL; + nodename++; + typelen = strcspn(nodename, "/"); + if (!typelen || nodename[typelen] != '/') + return -EINVAL; + p = nodename + typelen + 1; + uuidlen = strcspn(p, "/"); + if (!uuidlen || p[uuidlen] != '/') + return -EINVAL; + domid = xenbus_uuid_to_domid(p); + if (domid < 0) + return domid; + p += uuidlen + 1; + + if (snprintf(bus_id, BUS_ID_SIZE, + "%.*s-%i-%s", typelen, nodename, domid, p) >= BUS_ID_SIZE) + return -ENOSPC; + return 0; +} + +static int xenbus_probe_backend(const char *type, const char *uuid); +static struct xen_bus_type xenbus_backend = { + .root = "backend", + .levels = 3, /* backend/type// */ + .get_bus_id = backend_bus_id, + .probe = xenbus_probe_backend, + .bus = { + .name = "xenbus-backend", + .match = xenbus_match, + }, }; static int xenbus_dev_probe(struct device *_dev) @@ -104,12 +188,13 @@ static int xenbus_dev_remove(struct device *_dev) return drv->remove(dev); } -int xenbus_register_driver(struct xenbus_driver *drv) +static int xenbus_register_driver(struct xenbus_driver *drv, + struct xen_bus_type *bus) { int err; drv->driver.name = drv->name; - drv->driver.bus = &xenbus_type; + drv->driver.bus = &bus->bus; drv->driver.owner = drv->owner; drv->driver.probe = xenbus_dev_probe; drv->driver.remove = xenbus_dev_remove; @@ -120,6 +205,16 @@ int xenbus_register_driver(struct xenbus_driver *drv) return err; } +int xenbus_register_device(struct xenbus_driver *drv) +{ + return xenbus_register_driver(drv, &xenbus_frontend); +} + +int xenbus_register_backend(struct xenbus_driver *drv) +{ + return xenbus_register_driver(drv, &xenbus_backend); +} + void xenbus_unregister_driver(struct xenbus_driver *drv) { down(&xenbus_lock); @@ -130,31 +225,30 @@ void xenbus_unregister_driver(struct xenbus_driver *drv) struct xb_find_info { struct xenbus_device *dev; - const char *busid; + const char *nodename; }; static int cmp_dev(struct device *dev, void *data) { + struct xenbus_device *xendev = to_xenbus_device(dev); struct xb_find_info *info = data; - if (streq(dev->bus_id, info->busid)) { - info->dev = container_of(get_device(dev), - struct xenbus_device, dev); + if (streq(xendev->nodename, info->nodename)) { + info->dev = xendev; return 1; } return 0; } -/* FIXME: device_find is fixed in 2.6.13-rc2 according to Greg KH --RR */ -struct xenbus_device *xenbus_device_find(const char *busid) +struct xenbus_device *xenbus_device_find(const char *nodename, + struct bus_type *bus) { - struct xb_find_info info = { .dev = NULL, .busid = busid }; + struct xb_find_info info = { .dev = NULL, .nodename = nodename }; - bus_for_each_dev(&xenbus_type, NULL, &info, cmp_dev); + bus_for_each_dev(bus, NULL, &info, cmp_dev); return info.dev; } - static void xenbus_release_device(struct device *dev) { if (dev) { @@ -164,18 +258,37 @@ static void xenbus_release_device(struct device *dev) kfree(xendev); } } -/* devices// */ -static int xenbus_probe_device(const char *dirpath, const char *devicetype, - const char *name) + +/* Simplified asprintf. */ +static char *kasprintf(const char *fmt, ...) +{ + va_list ap; + unsigned int len; + char *p, dummy[1]; + + va_start(ap, fmt); + /* FIXME: vsnprintf has a bug, NULL should work */ + len = vsnprintf(dummy, 0, fmt, ap); + va_end(ap); + + p = kmalloc(len + 1, GFP_KERNEL); + if (!p) + return NULL; + va_start(ap, fmt); + vsprintf(p, fmt, ap); + va_end(ap); + return p; +} + +static int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, + const char *nodename) { int err; struct xenbus_device *xendev; unsigned int stringlen; - /* Nodename: /device/// */ - stringlen = strlen(dirpath) + strlen(devicetype) + strlen(name) + 3; - /* Typename */ - stringlen += strlen(devicetype) + 1; + stringlen = strlen(nodename) + 1 + strlen(type) + 1; xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL); if (!xendev) return -ENOMEM; @@ -183,38 +296,108 @@ static int xenbus_probe_device(const char *dirpath, const char *devicetype, /* Copy the strings into the extra space. */ xendev->nodename = (char *)(xendev + 1); - sprintf(xendev->nodename, "%s/%s/%s", dirpath, devicetype, name); + strcpy(xendev->nodename, nodename); xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1; - strcpy(xendev->devicetype, devicetype); + strcpy(xendev->devicetype, type); - /* FIXME: look for "subtype" field. */ - snprintf(xendev->dev.bus_id, BUS_ID_SIZE, "%s-%s", devicetype, name); - xendev->dev.bus = &xenbus_type; + /* This might not exist, but that's OK. */ + xendev->subtype = xenbus_read(xendev->nodename, "subtype", NULL); + if (IS_ERR(xendev->subtype)) + xendev->subtype = NULL; + + err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); + if (err) { + printk("XENBUS: Failed to get bus id for %s: error %i\n", + xendev->nodename, err); + kfree(xendev); + return err; + } + + xendev->dev.bus = &bus->bus; xendev->dev.release = xenbus_release_device; /* Register with generic device framework. */ err = device_register(&xendev->dev); if (err) { - printk("XENBUS: Registering device %s: error %i\n", - xendev->dev.bus_id, err); + printk("XENBUS: Registering %s device %s: error %i\n", + bus->bus.name, xendev->dev.bus_id, err); kfree(xendev); } return err; } -static int xenbus_probe_device_type(const char *dirpath, const char *typename) +/* device// */ +static int xenbus_probe_frontend(const char *type, const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name); + if (!nodename) + return -ENOMEM; + + err = xenbus_probe_node(&xenbus_frontend, type, nodename); + kfree(nodename); + return err; +} + +/* backend/// */ +static int xenbus_probe_backend_unit(const char *dir, + const char *type, + const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf("%s/%s", dir, name); + if (!nodename) + return -ENOMEM; + + err = xenbus_probe_node(&xenbus_backend, type, nodename); + kfree(nodename); + return err; +} + +/* backend// */ +static int xenbus_probe_backend(const char *type, const char *uuid) +{ + char *nodename; + int err = 0; + char **dir; + unsigned int i, dir_n = 0; + + nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, uuid); + if (!nodename) + return -ENOMEM; + + dir = xenbus_directory(nodename, "", &dir_n); + if (IS_ERR(dir)) { + kfree(nodename); + return PTR_ERR(dir); + } + + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_backend_unit(nodename, type, dir[i]); + if (err) + break; + } + kfree(nodename); + return err; +} + +static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) { int err = 0; char **dir; unsigned int dir_n = 0; int i; - dir = xenbus_directory(dirpath, typename, &dir_n); + dir = xenbus_directory(bus->root, type, &dir_n); if (IS_ERR(dir)) return PTR_ERR(dir); for (i = 0; i < dir_n; i++) { - err = xenbus_probe_device(dirpath, typename, dir[i]); + err = bus->probe(type, dir[i]); if (err) break; } @@ -222,18 +405,18 @@ static int xenbus_probe_device_type(const char *dirpath, const char *typename) return err; } -static int xenbus_probe_devices(const char *path) +static int xenbus_probe_devices(struct xen_bus_type *bus) { int err = 0; char **dir; unsigned int i, dir_n; - dir = xenbus_directory(path, "", &dir_n); + dir = xenbus_directory(bus->root, "", &dir_n); if (IS_ERR(dir)) return PTR_ERR(dir); for (i = 0; i < dir_n; i++) { - err = xenbus_probe_device_type(path, dir[i]); + err = xenbus_probe_device_type(bus, dir[i]); if (err) break; } @@ -251,58 +434,96 @@ static unsigned int char_count(const char *str, char c) return ret; } -static void dev_changed(struct xenbus_watch *watch, const char *node) +static void dev_changed(const char *node, struct xen_bus_type *bus) { - char busid[BUS_ID_SIZE]; int exists; struct xenbus_device *dev; - char *p; + char type[BUS_ID_SIZE]; + const char *p; - /* Node is of form device//[/...] */ - if (char_count(node, '/') != 2) + /* FIXME: wouldn't need this if we could limit watch depth. */ + if (char_count(node, '/') != bus->levels) return; + /* backend//... or device//... */ + p = strchr(node, '/') + 1; + snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p); + type[BUS_ID_SIZE-1] = '\0'; + /* Created or deleted? */ exists = xenbus_exists(node, ""); + dev = xenbus_device_find(node, &bus->bus); - p = strchr(node, '/') + 1; - if (strlen(p) + 1 > BUS_ID_SIZE) { - printk("Device for node %s is too big!\n", node); - return; - } - /* Bus ID is name with / changed to - */ - strcpy(busid, p); - *strchr(busid, '/') = '-'; - - dev = xenbus_device_find(busid); - printk("xenbus: device %s %s\n", busid, dev ? "exists" : "new"); + printk("xenbus: device %s %s\n", node, dev ? "exists" : "new"); if (dev && !exists) { - printk("xenbus: Unregistering device %s\n", busid); - /* FIXME: free? */ + printk("xenbus: Unregistering device %s\n", node); device_unregister(&dev->dev); } else if (!dev && exists) { - printk("xenbus: Adding device %s\n", busid); - /* Hack bus id back into two strings. */ - *strrchr(busid, '-') = '\0'; - xenbus_probe_device("device", busid, busid+strlen(busid)+1); + printk("xenbus: Adding device %s\n", node); + xenbus_probe_node(bus, type, node); } else - printk("xenbus: strange, %s already %s\n", busid, + printk("xenbus: strange, %s already %s\n", node, exists ? "exists" : "gone"); if (dev) put_device(&dev->dev); } +static void frontend_changed(struct xenbus_watch *watch, const char *node) +{ + dev_changed(node, &xenbus_frontend); +} + +static void backend_changed(struct xenbus_watch *watch, const char *node) +{ + dev_changed(node, &xenbus_backend); +} + /* We watch for devices appearing and vanishing. */ -static struct xenbus_watch dev_watch = { +static struct xenbus_watch fe_watch = { /* FIXME: Ideally we'd only watch for changes 2 levels deep... */ .node = "device", - .callback = dev_changed, + .callback = frontend_changed, }; +static struct xenbus_watch be_watch = { + .node = "backend", + .callback = backend_changed, +}; + +static int suspend_dev(struct device *dev, void *data) +{ + int err = 0; + struct xenbus_driver *drv = to_xenbus_driver(dev->driver); + struct xenbus_device *xdev + = container_of(dev, struct xenbus_device, dev); + + if (drv->suspend) + err = drv->suspend(xdev); + if (err) + printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err); + return 0; +} + +static int resume_dev(struct device *dev, void *data) +{ + int err = 0; + struct xenbus_driver *drv = to_xenbus_driver(dev->driver); + struct xenbus_device *xdev + = container_of(dev, struct xenbus_device, dev); + + if (drv->resume) + err = drv->resume(xdev); + if (err) + printk("xenbus: resume %s failed: %i\n", dev->bus_id, err); + return 0; +} + void xenbus_suspend(void) { /* We keep lock, so no comms can happen as page moves. */ down(&xenbus_lock); + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); + bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev); xb_suspend_comms(); } @@ -310,6 +531,8 @@ void xenbus_resume(void) { xb_init_comms(); reregister_xenbus_watches(); + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); + bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); up(&xenbus_lock); } @@ -353,31 +576,22 @@ int do_xenbus_probe(void *unused) return err; } - down(&xenbus_lock); - err = notifier_call_chain(&xenstore_chain, 0, 0); - up(&xenbus_lock); - - if (err == NOTIFY_BAD) { - printk("%s: calling xenstore notify chain failed\n", - __FUNCTION__); - return -EINVAL; - } - - err = 0; - down(&xenbus_lock); /* Enumerate devices in xenstore. */ - xenbus_probe_devices("device"); + xenbus_probe_devices(&xenbus_frontend); + xenbus_probe_devices(&xenbus_backend); /* Watch for changes. */ - register_xenbus_watch(&dev_watch); + register_xenbus_watch(&fe_watch); + register_xenbus_watch(&be_watch); up(&xenbus_lock); return 0; } static int __init xenbus_probe_init(void) { - bus_register(&xenbus_type); - + bus_register(&xenbus_frontend.bus); + bus_register(&xenbus_backend.bus); + if (!xen_start_info.store_evtchn) return 0; diff --git a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h index 8ffbcb75ef..25b2d1ce80 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h @@ -61,9 +61,11 @@ struct xenbus_driver { char *name; struct module *owner; const struct xenbus_device_id *ids; - int (*probe) (struct xenbus_device * dev, - const struct xenbus_device_id * id); - int (*remove) (struct xenbus_device * dev); + int (*probe)(struct xenbus_device *dev, + const struct xenbus_device_id *id); + int (*remove)(struct xenbus_device *dev); + int (*suspend)(struct xenbus_device *dev); + int (*resume)(struct xenbus_device *dev); struct device_driver driver; }; @@ -72,7 +74,8 @@ static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) return container_of(drv, struct xenbus_driver, driver); } -int xenbus_register_driver(struct xenbus_driver *drv); +int xenbus_register_device(struct xenbus_driver *drv); +int xenbus_register_backend(struct xenbus_driver *drv); void xenbus_unregister_driver(struct xenbus_driver *drv); /* Caller must hold this lock to call these functions: it's also held @@ -123,6 +126,9 @@ int register_xenbus_watch(struct xenbus_watch *watch); void unregister_xenbus_watch(struct xenbus_watch *watch); void reregister_xenbus_watches(void); +/* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ +int xenbus_uuid_to_domid(const char *uuid); + /* Called from xen core code. */ void xenbus_suspend(void); void xenbus_resume(void); From c2425f692738e4bd8e3dbcc12d105b21cfb0ab47 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 18:56:47 +0000 Subject: [PATCH 05/36] Make probe less chatty. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 1af6f1d63e..008aac4ba0 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -307,8 +307,6 @@ static int xenbus_probe_node(struct xen_bus_type *bus, err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); if (err) { - printk("XENBUS: Failed to get bus id for %s: error %i\n", - xendev->nodename, err); kfree(xendev); return err; } @@ -454,16 +452,11 @@ static void dev_changed(const char *node, struct xen_bus_type *bus) exists = xenbus_exists(node, ""); dev = xenbus_device_find(node, &bus->bus); - printk("xenbus: device %s %s\n", node, dev ? "exists" : "new"); if (dev && !exists) { - printk("xenbus: Unregistering device %s\n", node); device_unregister(&dev->dev); } else if (!dev && exists) { - printk("xenbus: Adding device %s\n", node); xenbus_probe_node(bus, type, node); - } else - printk("xenbus: strange, %s already %s\n", node, - exists ? "exists" : "gone"); + } if (dev) put_device(&dev->dev); } From 17c6a6517eb9fcfae52250e86726e6fc49ca6d39 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:01:09 +0000 Subject: [PATCH 06/36] Rename bus names from xenbus* to xen*. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 008aac4ba0..331ef7f150 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -100,7 +100,7 @@ static struct xen_bus_type xenbus_frontend = { .get_bus_id = frontend_bus_id, .probe = xenbus_probe_frontend, .bus = { - .name = "xenbus", + .name = "xen", .match = xenbus_match, }, }; @@ -157,7 +157,7 @@ static struct xen_bus_type xenbus_backend = { .get_bus_id = backend_bus_id, .probe = xenbus_probe_backend, .bus = { - .name = "xenbus-backend", + .name = "xen-backend", .match = xenbus_match, }, }; From 8442e529f5504a7e80a5aa02a3b57a2f584f7a42 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:04:47 +0000 Subject: [PATCH 07/36] Create devices for the xenbus-bus's. Signed-off-by: Christian Limpach --- .../drivers/xen/xenbus/xenbus_probe.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 331ef7f150..3a37014c0b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -72,6 +72,7 @@ struct xen_bus_type int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); int (*probe)(const char *type, const char *dir); struct bus_type bus; + struct device dev; }; /* device// => - */ @@ -103,6 +104,9 @@ static struct xen_bus_type xenbus_frontend = { .name = "xen", .match = xenbus_match, }, + .dev = { + .bus_id = "xen", + }, }; /* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ @@ -160,6 +164,9 @@ static struct xen_bus_type xenbus_backend = { .name = "xen-backend", .match = xenbus_match, }, + .dev = { + .bus_id = "xen-backend", + }, }; static int xenbus_dev_probe(struct device *_dev) @@ -304,16 +311,17 @@ static int xenbus_probe_node(struct xen_bus_type *bus, xendev->subtype = xenbus_read(xendev->nodename, "subtype", NULL); if (IS_ERR(xendev->subtype)) xendev->subtype = NULL; - + + xendev->dev.parent = &bus->dev; + xendev->dev.bus = &bus->bus; + xendev->dev.release = xenbus_release_device; + err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); if (err) { kfree(xendev); return err; } - xendev->dev.bus = &bus->bus; - xendev->dev.release = xenbus_release_device; - /* Register with generic device framework. */ err = device_register(&xendev->dev); if (err) { @@ -584,6 +592,8 @@ static int __init xenbus_probe_init(void) { bus_register(&xenbus_frontend.bus); bus_register(&xenbus_backend.bus); + device_register(&xenbus_frontend.dev); + device_register(&xenbus_backend.dev); if (!xen_start_info.store_evtchn) return 0; From 345c934993ff86221062c997730450869a25a316 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:06:51 +0000 Subject: [PATCH 08/36] Get device when we find it - fixes refcount leak and is correct. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 3a37014c0b..cd4d3d97ef 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -242,6 +242,7 @@ static int cmp_dev(struct device *dev, void *data) if (streq(xendev->nodename, info->nodename)) { info->dev = xendev; + get_device(dev); return 1; } return 0; From 2a101123795334f50d8b6706d12c0a65c65cdfc4 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:07:29 +0000 Subject: [PATCH 09/36] Don't free subtype field unconditionally. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index cd4d3d97ef..d8edd387f7 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -262,7 +262,8 @@ static void xenbus_release_device(struct device *dev) if (dev) { struct xenbus_device *xendev = to_xenbus_device(dev); - kfree(xendev->subtype); + if (xendev->subtype) + kfree(xendev->subtype); kfree(xendev); } } From 805274f7680741fde85da5bd2fd7408ab0f85f0e Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:08:09 +0000 Subject: [PATCH 10/36] Free memory returned from xenbus_directory call. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index d8edd387f7..dcf8d2de31 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -389,6 +389,7 @@ static int xenbus_probe_backend(const char *type, const char *uuid) if (err) break; } + kfree(dir); kfree(nodename); return err; } From b3aeb9b7bfa241a5b43f6854d6b77af2e819909c Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:15:22 +0000 Subject: [PATCH 11/36] Let dev_changed detect devices when a watch fires with a longer node name. Also improve device cleanup when the dir for a while frontend domain is removed. Signed-off-by: Christian Limpach --- .../drivers/xen/xenbus/xenbus_probe.c | 76 +++++++++++++++---- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index dcf8d2de31..06b33fd645 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -257,6 +257,34 @@ struct xenbus_device *xenbus_device_find(const char *nodename, return info.dev; } +static int cleanup_dev(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct xb_find_info *info = data; + int len = strlen(info->nodename); + + if (!strncmp(xendev->nodename, info->nodename, len)) { + info->dev = xendev; + get_device(dev); + return 1; + } + return 0; +} + +static void xenbus_cleanup_devices(const char *path, struct bus_type *bus) +{ + struct xb_find_info info = { .nodename = path }; + + do { + info.dev = NULL; + bus_for_each_dev(bus, NULL, &info, cleanup_dev); + if (info.dev) { + device_unregister(&info.dev->dev); + put_device(&info.dev->dev); + } + } while (info.dev); +} + static void xenbus_release_device(struct device *dev) { if (dev) { @@ -443,33 +471,54 @@ static unsigned int char_count(const char *str, char c) return ret; } +static int strsep_len(const char *str, char c, unsigned int len) +{ + unsigned int i; + + for (i = 0; str[i]; i++) + if (str[i] == c) { + if (len == 0) + return i; + len--; + } + return (len == 0) ? i : -ERANGE; +} + static void dev_changed(const char *node, struct xen_bus_type *bus) { - int exists; + int exists, rootlen; struct xenbus_device *dev; char type[BUS_ID_SIZE]; - const char *p; + const char *p, *root; - /* FIXME: wouldn't need this if we could limit watch depth. */ - if (char_count(node, '/') != bus->levels) + if (char_count(node, '/') < 2) + return; + + exists = xenbus_exists(node, ""); + if (!exists) { + xenbus_cleanup_devices(node, &bus->bus); return; + } /* backend//... or device//... */ p = strchr(node, '/') + 1; snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p); type[BUS_ID_SIZE-1] = '\0'; - /* Created or deleted? */ - exists = xenbus_exists(node, ""); - dev = xenbus_device_find(node, &bus->bus); + rootlen = strsep_len(node, '/', bus->levels); + if (rootlen < 0) + return; + root = kasprintf("%.*s", rootlen, node); + if (!root) + return; - if (dev && !exists) { - device_unregister(&dev->dev); - } else if (!dev && exists) { - xenbus_probe_node(bus, type, node); - } - if (dev) + dev = xenbus_device_find(root, &bus->bus); + if (!dev) + xenbus_probe_node(bus, type, root); + else put_device(&dev->dev); + + kfree(root); } static void frontend_changed(struct xenbus_watch *watch, const char *node) @@ -484,7 +533,6 @@ static void backend_changed(struct xenbus_watch *watch, const char *node) /* We watch for devices appearing and vanishing. */ static struct xenbus_watch fe_watch = { - /* FIXME: Ideally we'd only watch for changes 2 levels deep... */ .node = "device", .callback = frontend_changed, }; From 90562ffd561be71d472fa293ae74612d55d2016a Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:21:09 +0000 Subject: [PATCH 12/36] Get rid of xenbus_uuid_to_domid - get the frontend id from the node. We don't want to parse paths we read out of the store to _construct_ other paths and tie down the store layout for no good reason. Also require the frontend path to exist and be valid before creating the device. Signed-off-by: Christian Limpach --- .../drivers/xen/xenbus/xenbus_probe.c | 60 +++++++++---------- linux-2.6-xen-sparse/include/asm-xen/xenbus.h | 3 - 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 06b33fd645..cfdd92fcdd 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -109,47 +109,41 @@ static struct xen_bus_type xenbus_frontend = { }, }; -/* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ -int xenbus_uuid_to_domid(const char *uuid) -{ - int err, domid, len; - char path[strlen("/domain/") + 50]; - - len = strcspn(uuid, "/"); - if (snprintf(path, sizeof(path), "/domain/%.*s", len, uuid) - >= sizeof(path)) - return -ENOSPC; - err = xenbus_scanf(path, "id", "%i", &domid); - if (err != 1) - return err; - return domid; -} - /* backend/// => -- */ static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) { - unsigned int typelen, uuidlen; - int domid; - const char *p; + int domid, err; + const char *devid, *type, *frontend; + unsigned int typelen; - nodename = strchr(nodename, '/'); - if (!nodename) + type = strchr(nodename, '/'); + if (!type) return -EINVAL; - nodename++; - typelen = strcspn(nodename, "/"); - if (!typelen || nodename[typelen] != '/') + type++; + typelen = strcspn(type, "/"); + if (!typelen || type[typelen] != '/') return -EINVAL; - p = nodename + typelen + 1; - uuidlen = strcspn(p, "/"); - if (!uuidlen || p[uuidlen] != '/') - return -EINVAL; - domid = xenbus_uuid_to_domid(p); - if (domid < 0) - return domid; - p += uuidlen + 1; + + devid = strrchr(nodename, '/') + 1; + + err = xenbus_gather(nodename, "frontend-id", "%i", &domid, + "frontend", NULL, &frontend, + NULL); + if (err) + return err; + if (strlen(frontend) == 0) + err = -ERANGE; + + if (!err && !xenbus_exists(frontend, "")) + err = -ENOENT; + + if (err) { + kfree(frontend); + return err; + } if (snprintf(bus_id, BUS_ID_SIZE, - "%.*s-%i-%s", typelen, nodename, domid, p) >= BUS_ID_SIZE) + "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE) return -ENOSPC; return 0; } diff --git a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h index 25b2d1ce80..685b5d7a3e 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h @@ -126,9 +126,6 @@ int register_xenbus_watch(struct xenbus_watch *watch); void unregister_xenbus_watch(struct xenbus_watch *watch); void reregister_xenbus_watches(void); -/* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ -int xenbus_uuid_to_domid(const char *uuid); - /* Called from xen core code. */ void xenbus_suspend(void); void xenbus_resume(void); From c4d04f6326d8a08df38732eeea43409063341e8b Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:24:42 +0000 Subject: [PATCH 13/36] Add support to xenbus_gather to scan for strings and return them in allocated memory. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index 2e9c79361d..2cfa3106d9 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -187,6 +187,7 @@ static char *join(const char *dir, const char *name) static char buffer[4096]; BUG_ON(down_trylock(&xenbus_lock) == 0); + /* XXX FIXME: might not be correct if name == "" */ BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer)); strcpy(buffer, dir); @@ -399,9 +400,12 @@ int xenbus_gather(const char *dir, ...) ret = PTR_ERR(p); break; } - if (sscanf(p, fmt, result) == 0) - ret = -EINVAL; - kfree(p); + if (fmt) { + if (sscanf(p, fmt, result) == 0) + ret = -EINVAL; + kfree(p); + } else + *(char **)result = p; } va_end(ap); return ret; From e9eaa6bafb0e2d1257efe2d2ea811cb4f4b5c625 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 18 Aug 2005 19:51:46 +0000 Subject: [PATCH 14/36] Remove support for xenbus driver subtypes since with the subtype field there's no fallback. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 10 +--------- linux-2.6-xen-sparse/include/asm-xen/xenbus.h | 2 -- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index cfdd92fcdd..b346b9dddc 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -48,8 +48,7 @@ static const struct xenbus_device_id * match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) { for (; !streq(arr->devicetype, ""); arr++) { - if (streq(arr->devicetype, dev->devicetype) && - streq(arr->subtype, dev->subtype ?: "")) + if (streq(arr->devicetype, dev->devicetype)) return arr; } return NULL; @@ -284,8 +283,6 @@ static void xenbus_release_device(struct device *dev) if (dev) { struct xenbus_device *xendev = to_xenbus_device(dev); - if (xendev->subtype) - kfree(xendev->subtype); kfree(xendev); } } @@ -331,11 +328,6 @@ static int xenbus_probe_node(struct xen_bus_type *bus, xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1; strcpy(xendev->devicetype, type); - /* This might not exist, but that's OK. */ - xendev->subtype = xenbus_read(xendev->nodename, "subtype", NULL); - if (IS_ERR(xendev->subtype)) - xendev->subtype = NULL; - xendev->dev.parent = &bus->dev; xendev->dev.bus = &bus->bus; xendev->dev.release = xenbus_release_device; diff --git a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h index 685b5d7a3e..d119b78ad4 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h @@ -37,7 +37,6 @@ /* A xenbus device. */ struct xenbus_device { char *devicetype; - char *subtype; char *nodename; struct device dev; int has_error; @@ -53,7 +52,6 @@ struct xenbus_device_id { /* .../device// */ char devicetype[32]; /* General class of device. */ - char subtype[32]; /* Contents of "subtype" for this device */ }; /* A xenbus driver. */ From d41f35ae27ff988098d930a552f9c069c2aab4c6 Mon Sep 17 00:00:00 2001 From: "smh22@firebug.cl.cam.ac.uk" Date: Fri, 19 Aug 2005 02:41:16 +0000 Subject: [PATCH 15/36] Proleptic xend bug fix for multi-sxp messages; stricly more robust than before. Signed-off-by: Steven Hand --- tools/python/xen/xend/server/event.py | 2 +- tools/python/xen/xend/server/relocate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/server/event.py b/tools/python/xen/xend/server/event.py index a34393800e..360cd47a9b 100644 --- a/tools/python/xen/xend/server/event.py +++ b/tools/python/xen/xend/server/event.py @@ -50,7 +50,7 @@ class EventProtocol(protocol.Protocol): def dataReceived(self, data): try: self.parser.input(data) - if self.parser.ready(): + while(self.parser.ready()): val = self.parser.get_val() res = self.dispatch(val) self.send_result(res) diff --git a/tools/python/xen/xend/server/relocate.py b/tools/python/xen/xend/server/relocate.py index 01995193c9..b8959baa06 100644 --- a/tools/python/xen/xend/server/relocate.py +++ b/tools/python/xen/xend/server/relocate.py @@ -42,7 +42,7 @@ class RelocationProtocol(protocol.Protocol): def dataReceived(self, data): try: self.parser.input(data) - if self.parser.ready(): + while(self.parser.ready()): val = self.parser.get_val() res = self.dispatch(val) self.send_result(res) From f5b9cd087fa4774a162d27071d81a3ffad71190e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 19 Aug 2005 08:55:03 +0000 Subject: [PATCH 16/36] This patch provides a workaround for bugzilla #90 which shows up far too often when creating and then destroying lots of domUs and dom0 is SMP. Details are in the [1]bug. With this patch, I now can create/destroy domains in a tight loop for hours where previously every 3 to 10 cycles would blow up. 1. http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=90 Signed-off-by: Ryan Harper --- .../linux-2.6.12/workaround_double_br_del_if.patch | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 patches/linux-2.6.12/workaround_double_br_del_if.patch diff --git a/patches/linux-2.6.12/workaround_double_br_del_if.patch b/patches/linux-2.6.12/workaround_double_br_del_if.patch new file mode 100644 index 0000000000..8c43e19628 --- /dev/null +++ b/patches/linux-2.6.12/workaround_double_br_del_if.patch @@ -0,0 +1,11 @@ +--- linux-2.6.12/net/bridge/br_if.c 2005-06-17 14:48:29.000000000 -0500 ++++ linux-2.6.12-xen0-smp/net/bridge/br_if.c 2005-08-18 15:17:27.302615846 -0500 +@@ -382,7 +382,7 @@ + { + struct net_bridge_port *p = dev->br_port; + +- if (!p || p->br != br) ++ if (!p || p->br != br || p->state == BR_STATE_DISABLED) + return -EINVAL; + + br_sysfs_removeif(p); From 39ec3e6c6ac6362f6245292701da08e7a055e686 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 19 Aug 2005 09:03:17 +0000 Subject: [PATCH 17/36] This patch: * adds a C-based security policy translation tool to Xen (secpol_xml2bin) and removes the current Java security policy translator (Java dependencies). The C-based tool integrates into the Xen source tree build and install (using gnome libxml2 for XML parsing). See install.txt. * introduces security labels and related tools. Users can now use semantic-rich label names to put security-tags on domains. See example.txt, policy.txt. * moves the security configuration (currently ACM_USE_SECURITY_POLICY) from xen/Rules.mk into a separate top-level Security.mk file (it is needed by the tools/security and xen/acm). Both xen/acm and tools/security are built during the Xen build process only if ACM_USE_SECURITY_POLICY is not ACM_NULL_POLICY (which is the default setting). Signed-off-by Reiner Sailer Signed-off by Stefan Berger Signed-off by Ray Valdez --- Config.mk | 8 + docs/misc/shype4xen_readme.txt | 588 ------ tools/misc/policyprocessor/Makefile | 42 - tools/misc/policyprocessor/SecurityLabel.java | 34 - .../policyprocessor/SecurityPolicySpec.xsd | 115 -- tools/misc/policyprocessor/SsidsEntry.java | 29 - tools/misc/policyprocessor/XmlToBin.java | 1570 ----------------- .../policyprocessor/XmlToBinInterface.java | 138 -- tools/misc/policyprocessor/c2j_include.c | 57 - tools/misc/policyprocessor/myHandler.java | 47 - tools/misc/policyprocessor/readme.install | 33 - tools/misc/policyprocessor/readme.xen | 65 - tools/misc/policyprocessor/xen_sample_def.xml | 46 - .../policyprocessor/xen_sample_policy.xml | 58 - tools/security/Makefile | 62 +- tools/security/example.txt | 269 +++ tools/security/install.txt | 67 + .../chwall/chwall-security_label_template.xml | 76 + .../chwall/chwall-security_policy.xml | 36 + .../chwall_ste-security_label_template.xml | 167 ++ .../chwall_ste/chwall_ste-security_policy.xml | 49 + .../null/null-security_label_template.xml | 24 + .../policies/null/null-security_policy.xml | 14 + tools/security/policies/security_policy.xsd | 138 ++ .../ste/ste-security_label_template.xml | 143 ++ .../policies/ste/ste-security_policy.xml | 27 + tools/security/policy.txt | 405 +++++ tools/security/readme.txt | 29 + tools/security/secpol_compat.h | 14 + tools/security/secpol_tool.c | 185 +- tools/security/secpol_xml2bin.c | 1396 +++++++++++++++ tools/security/secpol_xml2bin.h | 139 ++ tools/security/setlabel.sh | 345 ++++ tools/security/updategrub.sh | 171 ++ xen/Rules.mk | 8 - 35 files changed, 3572 insertions(+), 3022 deletions(-) delete mode 100644 docs/misc/shype4xen_readme.txt delete mode 100644 tools/misc/policyprocessor/Makefile delete mode 100644 tools/misc/policyprocessor/SecurityLabel.java delete mode 100644 tools/misc/policyprocessor/SecurityPolicySpec.xsd delete mode 100644 tools/misc/policyprocessor/SsidsEntry.java delete mode 100644 tools/misc/policyprocessor/XmlToBin.java delete mode 100644 tools/misc/policyprocessor/XmlToBinInterface.java delete mode 100644 tools/misc/policyprocessor/c2j_include.c delete mode 100644 tools/misc/policyprocessor/myHandler.java delete mode 100644 tools/misc/policyprocessor/readme.install delete mode 100644 tools/misc/policyprocessor/readme.xen delete mode 100644 tools/misc/policyprocessor/xen_sample_def.xml delete mode 100644 tools/misc/policyprocessor/xen_sample_policy.xml create mode 100644 tools/security/example.txt create mode 100644 tools/security/install.txt create mode 100644 tools/security/policies/chwall/chwall-security_label_template.xml create mode 100644 tools/security/policies/chwall/chwall-security_policy.xml create mode 100644 tools/security/policies/chwall_ste/chwall_ste-security_label_template.xml create mode 100644 tools/security/policies/chwall_ste/chwall_ste-security_policy.xml create mode 100644 tools/security/policies/null/null-security_label_template.xml create mode 100644 tools/security/policies/null/null-security_policy.xml create mode 100644 tools/security/policies/security_policy.xsd create mode 100644 tools/security/policies/ste/ste-security_label_template.xml create mode 100644 tools/security/policies/ste/ste-security_policy.xml create mode 100644 tools/security/policy.txt create mode 100644 tools/security/readme.txt create mode 100644 tools/security/secpol_compat.h create mode 100644 tools/security/secpol_xml2bin.c create mode 100644 tools/security/secpol_xml2bin.h create mode 100644 tools/security/setlabel.sh create mode 100644 tools/security/updategrub.sh diff --git a/Config.mk b/Config.mk index 2eb5eae86f..76180e6b26 100644 --- a/Config.mk +++ b/Config.mk @@ -35,3 +35,11 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES), -I$(i)) # Choose the best mirror to download linux kernel KERNEL_REPO = http://www.kernel.org + +# ACM_USE_SECURITY_POLICY is set to security policy of Xen +# Supported models are: +# ACM_NULL_POLICY (ACM will not be built with this policy) +# ACM_CHINESE_WALL_POLICY +# ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY +# ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY +ACM_USE_SECURITY_POLICY ?= ACM_NULL_POLICY diff --git a/docs/misc/shype4xen_readme.txt b/docs/misc/shype4xen_readme.txt deleted file mode 100644 index 8c3e78788a..0000000000 --- a/docs/misc/shype4xen_readme.txt +++ /dev/null @@ -1,588 +0,0 @@ -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 - sets the policy defined in the - 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. - -5. Booting with a binary policy: -******************************** -The grub configuration file can be adapted to boot the hypervisor with an -already active policy. To do this, a binary policy file - this can be -the same file as used by the policy_tool - should be placed into the boot -partition. The following entry from the grub configuration file shows how -a binary policy can be added to the system during boot time. Note that the -binary policy must be of the same type that the hypervisor was compiled -for. The policy module line should also only be added as the last module -line if XEN was compiled with the access control module (ACM). - -title XEN0 3.0 Devel - kernel /xen.gz dom0_mem=400000 - module /vmlinuz-2.6.12-xen0 root=/dev/hda2 ro console=tty0 - module /initrd-2.6.12-xen0.img - module /xen_sample_policy.bin - - -====================end-of file======================================= diff --git a/tools/misc/policyprocessor/Makefile b/tools/misc/policyprocessor/Makefile deleted file mode 100644 index f1e34bc842..0000000000 --- a/tools/misc/policyprocessor/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -XEN_ROOT = ../../.. -include $(XEN_ROOT)/tools/Rules.mk - -CFLAGS += -static -CFLAGS += -Wall -CFLAGS += -Werror -CFLAGS += -O3 -CFLAGS += -fno-strict-aliasing -CFLAGS += -I. - -all: build - -build: mk-symlinks - $(MAKE) xml_to_bin - -default: all - -install: all - -xml_to_bin : make_include XmlToBin.java XmlToBinInterface.java SsidsEntry.java SecurityLabel.java myHandler.java - javac XmlToBin.java - -make_include : c2j_include - ./c2j_include - -c2j_include: c2j_include.c - $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< - -clean: - rm -rf *.class xen c2j_include policy_version.java *.bin - - -LINUX_ROOT := $(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/misc/policyprocessor/SecurityLabel.java b/tools/misc/policyprocessor/SecurityLabel.java deleted file mode 100644 index c7ffbcaaeb..0000000000 --- a/tools/misc/policyprocessor/SecurityLabel.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * (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. - * - *

- * - * Keeps track of types. - * - *

- * - * - */ -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 deleted file mode 100644 index bb7265e6b0..0000000000 --- a/tools/misc/policyprocessor/SecurityPolicySpec.xsd +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/misc/policyprocessor/SsidsEntry.java b/tools/misc/policyprocessor/SsidsEntry.java deleted file mode 100644 index e178d9e6a3..0000000000 --- a/tools/misc/policyprocessor/SsidsEntry.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * (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. - *

- * - * Holds ssid information. - * - *

- * - * - */ -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 deleted file mode 100644 index fe04516672..0000000000 --- a/tools/misc/policyprocessor/XmlToBin.java +++ /dev/null @@ -1,1570 +0,0 @@ -/** - * (C) Copyright IBM Corp. 2005 - * - * $Id: XmlToBin.java,v 1.3 2005/06/20 21:07:37 rvaldez Exp $ - * - * Author: Ray Valdez - * - * Contributors: - * Reiner Sailer - adjust type-lengths - * - * 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. - *

- * - * 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 - * - *

- * - * - */ -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 { - index = 0; - /* fill in General Policy Version */ - writeIntToStream(binBuffer, ACM_POLICY_VERSION, index); - index += u32Size; - - /* Write magic */ - writeIntToStream(binBuffer, ACM_MAGIC, index); - index += u32Size; - - /* write len */ - writeIntToStream(binBuffer, binBuffer.length, 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 { - int skip = 0; - - /* init with NULL policy setting */ - writeIntToStream(binBuffer, ACM_NULL_POLICY, index); - writeIntToStream(binBuffer, 0, index + u32Size); - writeIntToStream(binBuffer, ACM_NULL_POLICY, index + 2*u32Size); - writeIntToStream(binBuffer, 0, index + 3*u32Size); - - index = address; - if (null != chwPolicy) { - - /* Write policy name */ - writeIntToStream(binBuffer, ACM_CHINESE_WALL_POLICY, index); - index += u32Size; - - /* Write offset */ - writeIntToStream(binBuffer, offset, index); - index += u32Size; - - /* Write payload. No need increment index */ - address = offset; - System.arraycopy(chwPolicy, 0, binBuffer,address, chwPolicy.length); - address = address + chwPolicy.length; - } else - skip += 2*u32Size; - - if (null != stePolicy) - { - /* Write policy name */ - writeIntToStream(binBuffer, ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, index); - index += u32Size; - - /* Write offset */ - writeIntToStream(binBuffer, address, index); - index += u32Size; - - /* Copy array */ - System.arraycopy(stePolicy, 0, binBuffer,address, stePolicy.length); - /* Update address */ - address = address + stePolicy.length; - } else - skip += 2*u32Size; - - /* Skip writing policy name and offset for each null policy*/ - index += skip; - - int size; - /* Assumes that you will always have a partition defined in policy */ - if ( 0 < partMap.length) { - writeIntToStream(binBuffer, 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 */ - int maxTypes = ColorTypes.size(); - - /* Get number of SSids entry */ - int maxSsids = Ssids.size(); - - /* Get number of conflict sets */ - int maxConflict = ConflictSsids.size(); - - - if (maxTypes * maxSsids == 0) - return null; - /* - data structure acm_chwall_policy_buffer - se XmlToBinInterface.java - */ - 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; - /* fill in General Policy Version */ - writeIntToStream(chwBuffer, ACM_CHWALL_VERSION, index); - index += u32Size; - - writeIntToStream(chwBuffer, ACM_CHINESE_WALL_POLICY, index); - index += u32Size; - - writeIntToStream(chwBuffer, maxTypes, index); - index += u32Size; - - writeIntToStream(chwBuffer, maxSsids, index); - index += u32Size; - - writeIntToStream(chwBuffer, maxConflict, index); - index += u32Size; - - /* Write chwall_ssid_offset */ - writeIntToStream(chwBuffer, chwHeaderSize, index); - index += u32Size; - - /* Write chwall_conflict_sets_offset */ - writeIntToStream(chwBuffer, address, index); - index += u32Size; - - /* Write chwall_running_types_offset */ - writeIntToStream(chwBuffer, 0, index); - index += u32Size; - - /* Write chwall_conflict_aggregate_offset */ - writeIntToStream(chwBuffer, 0, index); - index += u32Size; - - } 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 -

- @param Ssids Vector - @param ColorTypes Vector -

- @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 */ - int numColorTypes = ColorTypes.size(); - - /* Get number of SSids entry */ - int numSsids = Ssids.size(); - - if (numColorTypes * numSsids == 0) - return null; - - /* data structure: acm_ste_policy_buffer - * see XmlToBinInterface.java - * total bytes: steHeaderSize * 2B + colorTypes(size) * Ssids(size) - * - */ - steBuffer = new byte[ steHeaderSize + (numColorTypes * numSsids) * 2]; - - try { - - index = 0; - writeIntToStream(steBuffer, ACM_STE_VERSION, index); - index += u32Size; - - writeIntToStream(steBuffer, ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, index); - index += u32Size; - - writeIntToStream(steBuffer, numColorTypes, index); - index += u32Size; - - writeIntToStream(steBuffer, numSsids, index); - index += u32Size; - - writeIntToStream(steBuffer, steHeaderSize, index); - index += u32Size; - - - } 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()); - /* Add default Ssid to Ste and Chw bags */ - SecurityLabel defEntry = new SecurityLabel(); - - defEntry.chwTypes = new Vector(); - defEntry.steTypes = new Vector(); - defEntry.chwIDs = new Vector(); - defEntry.ids = new Vector(); - - defEntry.steSsidPosition =0; - defEntry.chwSsidPosition =0; - bagOfChwSsids.add(defEntry); - bagOfSsids.add(defEntry); - - 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(); - - policy_version active_policy = new policy_version(); - - if ((active_policy.ACM_POLICY_VERSION != ACM_POLICY_VERSION) || - (active_policy.ACM_CHWALL_VERSION != ACM_CHWALL_VERSION) || - (active_policy.ACM_STE_VERSION != ACM_STE_VERSION)) { - System.out.println("ACM policy versions differ."); - System.out.println("Please verify that data structures are correct"); - System.out.println("and then adjust the version numbers in XmlToBinInterface.java."); - return; - } - - - 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 deleted file mode 100644 index bcbdd15e02..0000000000 --- a/tools/misc/policyprocessor/XmlToBinInterface.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * (C) Copyright IBM Corp. 2005 - * - * $Id: XmlToBinInterface.java,v 1.3 2005/06/20 21:07:37 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. - *

- * - * Defines constants used by XmToBin. - * - *

- * - * policy binary structures - * - * struct acm_policy_buffer { - * u32 policy_version; * ACM_POLICY_VERSION * - * u32 magic; - * u32 len; - * u32 primary_policy_code; - * u32 primary_buffer_offset; - * u32 secondary_policy_code; - * u32 secondary_buffer_offset; - * +u32 resource offset (not used yet in Xen) - * }; - * - * - * struct acm_ste_policy_buffer { - * u32 policy_version; * ACM_STE_VERSION * - * u32 policy_code; - * u32 ste_max_types; - * u32 ste_max_ssidrefs; - * u32 ste_ssid_offset; - * }; - * - * struct acm_chwall_policy_buffer { - * u32 policy_version; * ACM_CHWALL_VERSION * - * u32 policy_code; - * u32 chwall_max_types; - * u32 chwall_max_ssidrefs; - * u32 chwall_max_conflictsets; - * u32 chwall_ssid_offset; - * u32 chwall_conflict_sets_offset; - * u32 chwall_running_types_offset; - * u32 chwall_conflict_aggregate_offset; - * }; - * - * 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 int steHeaderSize = (5 * u32Size); - - /* byte for acm_chinese_wall_policy_buffer_t */ - final int chwHeaderSize = (9 * u32Size); - - final int primaryPolicyCodeSize = u32Size; - final int primaryBufferOffsetSize = u32Size ; - - final int secondaryPolicyCodeSz = u32Size; - final int secondaryBufferOffsetSz = u32Size; - final int resourceOffsetSz = u32Size; - - 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 int binaryBufferHeaderSz = (8 * u32Size); /* 8th not used in Xen */ - - /* copied directly from acm.h */ - final int ACM_MAGIC = 0x0001debc; - final int ACM_NULL_POLICY = 0; - final int ACM_CHINESE_WALL_POLICY = 1; - final int ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY = 2; - final int ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY = 3; - final int ACM_EMPTY_POLICY = 4; - - /* version for compatibility check */ - final int ACM_POLICY_VERSION = 1; - final int ACM_STE_VERSION = 1; - final int ACM_CHWALL_VERSION = 1; -} diff --git a/tools/misc/policyprocessor/c2j_include.c b/tools/misc/policyprocessor/c2j_include.c deleted file mode 100644 index cef70509ae..0000000000 --- a/tools/misc/policyprocessor/c2j_include.c +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************** - * c2j_include.c - * - * Copyright (C) 2005 IBM Corporation - * - * Authors: - * Reiner Sailer - * - * 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. - * - * This tool makes some constants from acm.h available to the - * java policyprocessor for version checking. - */ -#include -#include -#include -#include - -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 - -char *filename = "policy_version.java"; - -int main(int argc, char **argv) -{ - - FILE *fd; - if ((fd = fopen(filename, "w")) <= 0) - { - printf("File %s not found.\n", filename); - exit(-ENOENT); - } - - fprintf(fd, "/*\n * This file was automatically generated\n"); - fprintf(fd, " * Do not change it manually!\n */\n"); - fprintf(fd, "public class policy_version {\n"); - fprintf(fd, " final int ACM_POLICY_VERSION = %x;\n", - ACM_POLICY_VERSION); - fprintf(fd, " final int ACM_CHWALL_VERSION = %x;\n", - ACM_CHWALL_VERSION); - fprintf(fd, " final int ACM_STE_VERSION = %x;\n", - ACM_STE_VERSION); - fprintf(fd, "}\n"); - fclose(fd); - return 0; -} diff --git a/tools/misc/policyprocessor/myHandler.java b/tools/misc/policyprocessor/myHandler.java deleted file mode 100644 index b972c20605..0000000000 --- a/tools/misc/policyprocessor/myHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * (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. - * - *

- * - * A dummy class used for detecting XML validating/parsing errors. - * - *

- * - * - */ -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 deleted file mode 100644 index 058ab8212a..0000000000 --- a/tools/misc/policyprocessor/readme.install +++ /dev/null @@ -1,33 +0,0 @@ -# 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 deleted file mode 100644 index e7f9fa4c9a..0000000000 --- a/tools/misc/policyprocessor/readme.xen +++ /dev/null @@ -1,65 +0,0 @@ -# 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 -xssid -xssidconf - - 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., xen_sample_def.xml). -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 deleted file mode 100644 index b578a183d8..0000000000 --- a/tools/misc/policyprocessor/xen_sample_def.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - LOCAL-management - R-Company-development - S-Company-order - T-Company-advertising - U-Company-computing - - - - - - Q-Company - R-Company - S-Company - T-Company - U-Company - V-Company - W-Company - X-Company - Y-Company - Z-Company - - - - T-Company - S-Company - - - - R-Company - V-Company - W-Company - - - - diff --git a/tools/misc/policyprocessor/xen_sample_policy.xml b/tools/misc/policyprocessor/xen_sample_policy.xml deleted file mode 100644 index cebb303c4f..0000000000 --- a/tools/misc/policyprocessor/xen_sample_policy.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - xen sample policy - 2005-05-20T16:56:00 - foobar - - xen_sample_def.xml - abcdef123456abcdef - - - - - 0 - LOCAL-management - R-Company-development - S-Company-order - T-Company-advertising - U-Company-computing - Q-Company - - - - 1 - R-Company-development - R-Company - - - - 2 - S-Company-order - S-Company - - - - - 3 - T-Company-advertising - T-Company - - - - - 4 - U-Company-computing - U-Company - - - - - diff --git a/tools/security/Makefile b/tools/security/Makefile index bd2b6d87e7..f6654d486c 100644 --- a/tools/security/Makefile +++ b/tools/security/Makefile @@ -2,27 +2,71 @@ XEN_ROOT = ../.. include $(XEN_ROOT)/tools/Rules.mk SRCS = secpol_tool.c -CFLAGS += -static CFLAGS += -Wall CFLAGS += -Werror CFLAGS += -O3 CFLAGS += -fno-strict-aliasing -CFLAGS += -I. +CFLAGS += -I. -I/usr/include/libxml2 +CFLAGS_XML2BIN += $(shell xml2-config --cflags --libs ) +#if above does not work, try -L/usr/lib -lxml2 -lz -lpthread -lm +XML2VERSION = $(shell xml2-config --version ) +VALIDATE_SCHEMA=$(shell if [[ $(XML2VERSION) < 2.6.20 ]]; then echo ""; else echo "-DVALIDATE_SCHEMA"; fi; ) +ifeq ($(ACM_USE_SECURITY_POLICY),ACM_NULL_POLICY) +POLICY=null +endif +ifeq ($(ACM_USE_SECURITY_POLICY),ACM_CHINESE_WALL_POLICY) +POLICY=chwall +endif +ifeq ($(ACM_USE_SECURITY_POLICY),ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) +POLICY=ste +endif +ifeq ($(ACM_USE_SECURITY_POLICY),ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) +POLICY=chwall_ste +endif +POLICYFILE=./policies/$(POLICY)/$(POLICY).bin + +ifneq ($(ACM_USE_SECURITY_POLICY), ACM_NULL_POLICY) all: build + +install:all + +default:all +else +all: + +install: + +default: +endif + build: mk-symlinks $(MAKE) secpol_tool + $(MAKE) secpol_xml2bin + chmod 700 ./setlabel.sh + chmod 700 ./updategrub.sh -default: all - -install: all - -secpol_tool : secpol_tool.c +secpol_tool : secpol_tool.c secpol_compat.h $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -clean: - rm -rf secpol_tool xen +secpol_xml2bin : secpol_xml2bin.c secpol_xml2bin.h secpol_compat.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_XML2BIN) $(VALIDATE_SCHEMA) -o $@ $< +clean: + rm -rf secpol_tool secpol_xml2bin xen + +policy_clean: + rm -rf policies/*/*.bin policies/*/*.map + +mrproper: clean policy_clean + + +$(POLICYFILE) : build + @./secpol_xml2bin $(POLICY) > /dev/null + +boot_install: $(POLICYFILE) + @cp $(POLICYFILE) /boot + @./updategrub.sh $(POLICY) $(PWD)/$(XEN_ROOT) LINUX_ROOT := $(XEN_ROOT)/linux-2.6-xen-sparse mk-symlinks: diff --git a/tools/security/example.txt b/tools/security/example.txt new file mode 100644 index 0000000000..5df6ef5a9f --- /dev/null +++ b/tools/security/example.txt @@ -0,0 +1,269 @@ +## +# example.txt +# +# Author: +# Reiner Sailer 08/15/2005 +# +# +# This file introduces into the tools to manage policies +# and to label domains and resources. +## + +We will show how to install and use the chwall_ste policy. +Other policies work similarly. Feedback welcome! + + + +1. Using secpol_xml2bin to translate the chwall_ste policy: +=========================================================== + +#tools/security/secpol_xml2bin chwall_ste + +Successful execution should print: + + [root@laptopxn security]# ./secpol_xml2bin chwall_ste + Validating label file policies/chwall_ste/chwall_ste-security_label_template.xml... + XML Schema policies/security_policy.xsd valid. + Validating policy file policies/chwall_ste/chwall_ste-security_policy.xml... + XML Schema policies/security_policy.xsd valid. + Creating ssid mappings ... + Creating label mappings ... + Max chwall labels: 7 + Max chwall-types: 4 + Max chwall-ssids: 5 + Max ste labels: 14 + Max ste-types: 6 + Max ste-ssids: 10 + +The tool looks in directory policies/chwall_ste for +the label and policy files. + +The default policy directory structure under tools/security looks like: + +policies +|-- security_policy.xsd +|-- chwall +| |-- chwall-security_label_template.xml +| `-- chwall-security_policy.xml +|-- chwall_ste +| |-- chwall_ste-security_label_template.xml +| `-- chwall_ste-security_policy.xml +|-- null +| |-- null-security_label_template.xml +| `-- null-security_policy.xml +`-- ste + |-- ste-security_label_template.xml + `-- ste-security_policy.xml + +policies/security_policy.xsd contains the schema against which both the +label-template and the policy files must validate during translation. + +policies/chwall_ste/chwall_ste-security_policy.xml defines the +policies and the types known to the policies. + +policies/chwall_ste/chwall_ste-security_label_template.xml contains +label definitions that group chwall and ste types together and make +them easier to use for users + +After executing the above secpol_xml2bin command, you will find 2 new +files in the policies/chwall_ste sub-directory: + +policies/chwall_ste/chwall_ste.map ... this file includes the mapping +of names from the xml files into their binary code representation. + +policies/chwall_ste/chwall_ste.bin ... this is the binary policy file, +the result of parsing the xml files and using the mapping to extract a +binary version that can be loaded into the hypervisor. + + + +2. Loading and activating the policy: +===================================== + +We assume that xen is already configured to use the chwall_ste policy; +please refer to install.txt for instructions. + +To activate the policy from the command line (assuming that the +currently established policy is the minimal boot-policy that is +hard-coded into the hypervisor: + +# ./secpol_tool loadpolicy policies/chwall_ste/chwall_ste.bin + +To activate the policy at next reboot: + +# cp policies/chwall_ste/chwall_ste.bin /boot + +Add a module line to your /boot/grub/grub.conf Xen entry. +My boot entry with chwall_ste enabled looks like this: + + title Xen (2.6.12) + root (hd0,5) + kernel /boot/xen.gz dom0_mem=1200000 console=vga + module /boot/vmlinuz-2.6.12-xen0 ro root=/dev/hda6 rhgb + module /boot/initrd-2.6.12-xen0.img + module /boot/chwall_ste.bin + +This tells the grub boot-loader to load the binary policy, which +the hypervisor will recognize. The hypervisor will then establish +this binary policy during boot instead of the minimal policy that +is hardcoded as default. + +If you have any trouble here, maks sure you have the access control +framework enabled (see: install.txt). + + + +3. Labeling domains: +==================== + +a) Labeling Domain0: + +The chwall_ste-security_label_template.xml file includes an attribute +"bootstrap", which is set to the label name that will be assigned to +Dom0 (this label will be mapped to ssidref 1/1, the default for Dom0). + +b) Labeling User Domains: + +Use the script tools/security/setlabel.sh to choose a label and to +assign labels to user domains. + +To show available labels for the chwall_ste policy: + +#tools/security/setlabel.sh -l + +lists all available labels. For the default chwall_ste it should print +the following: + + [root@laptopxn security]# ./setlabel.sh -l chwall_ste + The following labels are available: + dom_SystemManagement + dom_HomeBanking + dom_Fun + dom_BoincClient + dom_StorageDomain + dom_NetworkDomain + +You need to have compiled the policy beforehand so that a .map file +exists. Setlabel.sh uses the mapping file created throughout the +policy translation to translate a user-friendly label string into a +ssidref-number that is eventually used by the Xen hypervisor. + +We distinguish two kinds of labels: a) VM labels (for domains) and RES +Labels (for resources). We are currently working on support for +resource labeling but will focus here on VM labels. + +Setlabel.sh only prints VM labels (which we have prefixed with "dom_") +since only those are used at this time. + +If you would like to assign the dom_HomeBanking label to one of your +user domains (which you hopefully keep clean), look at an example +domain configuration homebanking.xm: + + #------HOMEBANKING--------- + kernel = "/boot/vmlinuz-2.6.12-xenU" + ramdisk="/boot/U1_ramdisk.img" + memory = 65 + name = "test34" + cpu = -1 # leave to Xen to pick + # Number of network interfaces. Default is 1. + nics=1 + dhcp="dhcp" + #------------------------- + +Now we label this domain + +[root@laptopxn security]# ./setlabel.sh homebanking.xm dom_HomeBanking chwall_ste +Mapped label 'dom_HomeBanking' to ssidref '0x00020002'. + +The domain configuration my look now like: + + [root@laptopxn security]# cat homebanking.xm + #------HOMEBANKING--------- + kernel = "/boot/vmlinuz-2.6.12-xenU" + ramdisk="/boot/U1_ramdisk.img" + memory = 65 + name = "test34" + cpu = -1 # leave to Xen to pick + # Number of network interfaces. Default is 1. + nics=1 + dhcp="dhcp" + #------------------------- + #ACM_POLICY=chwall_ste-security_policy.xml + #ACM_LABEL=dom_HomeBanking + ssidref = 0x00020002 + +You can see 3 new entries, two of which are comments. The only value +that the hypervisor cares about is the ssidref that will reference +those types assigned to this label. You can look them up in the +xml label-template file for the chwall_ste policy. + +This script will eventually move into the domain management and will +be called when the domain is instantiated. For now, the setlabel +script must be run on domains whenever the policy files change since +the mapping between label names and ssidrefs can change in this case. + + +4. Starting a labeled domain +============================ + +Now, start the domain: + #xm create -c homebanking.xm + + +If you label another domain configuration as dom_Fun and try to start +it afterwards, its start will fail. Why? + +Because the running homebanking domain has the chinese wall type +"cw_Sensitive". The new domain dom_Fun has the chinese wall label +"cw_Distrusted". This domain is not allowed to run simultaneously +because of the defined conflict set + + + cw_Sensitive + cw_Distrusted + + +(in policies/chwall_ste/chwall_ste-security_policy.xml), which says +that only one of the types cw_sensitive and cw_Distrusted can run at a +time. + +If you save or shutdown the HomeBanking domain, you will be able to +start the "Fun" domain. You can look into the Xen log to see if a +domain was denied to start because of the access control framework +with the command 'xm dmesg'. + +It is important (and usually non-trivial) to define the labels in a +way that the semantics of the labels are enforced and supported by the +types and the conflict sets. + +Note: While the chinese wall policy enforcement is complete, the type +enforcement is currently enforced in the Xen hypervisor +only. Therefore, only point-to-point sharing with regard to the type +enforcement is currently controlled. We are working on enhancements to +Dom0 that enforce types also for network traffic that is routed +through Dom0 and on the enforcement of resource labeling when binding +resources to domains (e.g., enforcing types between domains and +hardware resources, such as disk partitions). + + +4. Adding your own policies +=========================== + +Writing your own policy (e.g. "mypolicy") requires the following: + +a) the policy definition (types etc.) file +b) the label template definition (labels etc.) file + +If your policy name is "mypolicy", you need to create a +subdirectory mypolicy in tools/security/policies. + +Then you create +tools/security/policies/mypolicy/mypolicy-security_policy.xml and +tools/security/policies/mypolicy/mypolicy-security_label_template.xml. + +You need to keep to the schema as defined in +tools/security/security_policy.xsd since the translation tool +secpol_xml2bin is written against this schema. + +If you keep to the security policy schema, then you can use all the +tools described above. Refer to install.txt to install it. diff --git a/tools/security/install.txt b/tools/security/install.txt new file mode 100644 index 0000000000..e915617155 --- /dev/null +++ b/tools/security/install.txt @@ -0,0 +1,67 @@ +## +# install.txt +# +# Author: +# Reiner Sailer 08/15/2005 +# +# +# This file shows how to activate and install the access control +# framework. +## + + +INSTALLING A SECURITY POLICY IN XEN +=================================== + +By default, the access control architecture is disabled in Xen. To +enable the access control architecture in Xen follow the steps below. +This description assumes that you want to install the Chinese Wall and +Simple Type Enforcement policy. Some file names need to be replaced +below to activate the Chinese Wall OR the Type Enforcement policy +exclusively (chwall_ste --> {chwall, ste}). + +1. enable access control in Xen + # cd "xen_root" + # edit/xemacs/vi Config.mk + + change the line: + ACM_USE_SECURITY_POLICY ?= ACM_NULL_POLICY + + to: + ACM_USE_SECURITY_POLICY ?= ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY + + # make all + # ./install.sh + +2. compile the policy from xml to a binary format that can be loaded + into the hypervisor for enforcement + # cd tools/security + # make + + manual steps (alternative to make boot_install): + #./secpol_xml2bin chwall_ste + #cp policies/chwall_ste/chwall_ste.bin /boot + #edit /boot/grub/grub.conf + add the follwoing line to your xen boot entry: + "module chwall_ste.bin" + + alternatively, you can try our automatic translation and + installation of the policy: + # make boot_install + + [we try hard to do the right thing to the right boot entry but + please verify boot entry in /boot/grub/grub.conf afterwards; + your xen boot entry should have an additional module line + specifying a chwall_ste.bin file with the correct directory + (e.g. "/" or "/boot").] + + +3. reboot into the newly compiled hypervisor + + after boot + #xm dmesg should show an entry about the policy being loaded + during the boot process + + #tools/security/secpol_tool getpolicy + should print the new chwall_ste binary policy representation + diff --git a/tools/security/policies/chwall/chwall-security_label_template.xml b/tools/security/policies/chwall/chwall-security_label_template.xml new file mode 100644 index 0000000000..3a286f7fc6 --- /dev/null +++ b/tools/security/policies/chwall/chwall-security_label_template.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + chwall-security_label_template + 2005-08-10 + + chwall-security_policy.xml + abcdef123456abcdef + + + + + + + + + + + dom_HomeBanking + + cw_Sensitive + + + + + dom_Fun + + cw_Distrusted + + + + + + dom_BoincClient + + cw_Isolated + + + + + + + dom_SystemManagement + + cw_SystemManagement + + + + + + dom_StorageDomain + + cw_SystemManagement + + + + + + dom_NetworkDomain + + cw_SystemManagement + + + + + diff --git a/tools/security/policies/chwall/chwall-security_policy.xml b/tools/security/policies/chwall/chwall-security_policy.xml new file mode 100644 index 0000000000..fabe1ae161 --- /dev/null +++ b/tools/security/policies/chwall/chwall-security_policy.xml @@ -0,0 +1,36 @@ + + + + + + + + chwall-security_policy + 2005-08-10 + + + + + + + + + + + cw_SystemManagement + cw_Sensitive + cw_Isolated + cw_Distrusted + + + + + cw_Sensitive + cw_Distrusted + + + + + diff --git a/tools/security/policies/chwall_ste/chwall_ste-security_label_template.xml b/tools/security/policies/chwall_ste/chwall_ste-security_label_template.xml new file mode 100644 index 0000000000..1a311fbb4a --- /dev/null +++ b/tools/security/policies/chwall_ste/chwall_ste-security_label_template.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + chwall_ste-security_label_template + 2005-08-10 + + chwall_ste-security_policy.xml + abcdef123456abcdef + + + + + + + + + + + dom_HomeBanking + + ste_PersonalFinances + + + + cw_Sensitive + + + + + dom_Fun + + ste_InternetInsecure + + + + cw_Distrusted + + + + + + dom_BoincClient + + ste_DonatedCycles + + + + cw_Isolated + + + + + + + dom_SystemManagement + + + + ste_SystemManagement + ste_PersonalFinances + ste_InternetInsecure + ste_DonatedCycles + ste_PersistentStorageA + ste_NetworkAdapter0 + + + + cw_SystemManagement + + + + + + dom_StorageDomain + + + ste_PersistentStorageA + + ste_PersonalFinances + ste_InternetInsecure + + + + cw_SystemManagement + + + + + + dom_NetworkDomain + + + ste_NetworkAdapter0 + + ste_PersonalFinances + ste_InternetInsecure + ste_DonatedCycles + + + + cw_SystemManagement + + + + + + + res_ManagementResource + + ste_SystemManagement + + + + + res_HardDrive (hda) + + ste_PersistentStorageA + + + + + res_LogicalDiskPartition1 (hda1) + + ste_PersonalFinances + + + + + res_LogicalDiskPartition2 (hda2) + + ste_InternetInsecure + + + + + res_EthernetCard + + ste_NetworkAdapter0 + + + + + res_SecurityToken + + ste_PersonalFinances + + + + + res_GraphicsAdapter + + ste_SystemManagement + + + + + diff --git a/tools/security/policies/chwall_ste/chwall_ste-security_policy.xml b/tools/security/policies/chwall_ste/chwall_ste-security_policy.xml new file mode 100644 index 0000000000..bbbad3b3f0 --- /dev/null +++ b/tools/security/policies/chwall_ste/chwall_ste-security_policy.xml @@ -0,0 +1,49 @@ + + + + + + + + chwall_ste-security_policy + 2005-08-10 + + + + + + + ste_SystemManagement + ste_PersonalFinances + ste_InternetInsecure + ste_DonatedCycles + ste_PersistentStorageA + ste_NetworkAdapter0 + + + + + + + + + + + + cw_SystemManagement + cw_Sensitive + cw_Isolated + cw_Distrusted + + + + + cw_Sensitive + cw_Distrusted + + + + + diff --git a/tools/security/policies/null/null-security_label_template.xml b/tools/security/policies/null/null-security_label_template.xml new file mode 100644 index 0000000000..858d919fe9 --- /dev/null +++ b/tools/security/policies/null/null-security_label_template.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + null-security_label_template + + 2005-08-10 + + null-security_policy.xml + + abcdef123456abcdef + + + + diff --git a/tools/security/policies/null/null-security_policy.xml b/tools/security/policies/null/null-security_policy.xml new file mode 100644 index 0000000000..4d68b20d4c --- /dev/null +++ b/tools/security/policies/null/null-security_policy.xml @@ -0,0 +1,14 @@ + + + + + + + + null-security_policy + 2005-08-10 + + + diff --git a/tools/security/policies/security_policy.xsd b/tools/security/policies/security_policy.xsd new file mode 100644 index 0000000000..ce512e9ce0 --- /dev/null +++ b/tools/security/policies/security_policy.xsd @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/security/policies/ste/ste-security_label_template.xml b/tools/security/policies/ste/ste-security_label_template.xml new file mode 100644 index 0000000000..66af16229a --- /dev/null +++ b/tools/security/policies/ste/ste-security_label_template.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + ste-security_label_template + 2005-08-10 + + ste-security_policy.xml + abcdef123456abcdef + + + + + + + + + + + dom_HomeBanking + + ste_PersonalFinances + + + + + dom_Fun + + ste_InternetInsecure + + + + + + dom_BoincClient + + ste_DonatedCycles + + + + + + + dom_SystemManagement + + + + ste_SystemManagement + ste_PersonalFinances + ste_InternetInsecure + ste_DonatedCycles + ste_PersistentStorageA + ste_NetworkAdapter0 + + + + + + dom_StorageDomain + + + ste_PersistentStorageA + + ste_PersonalFinances + ste_InternetInsecure + + + + + + dom_NetworkDomain + + + ste_NetworkAdapter0 + + ste_PersonalFinances + ste_InternetInsecure + ste_DonatedCycles + + + + + + + res_ManagementResource + + ste_SystemManagement + + + + + res_HardDrive (hda) + + ste_PersistentStorageA + + + + + res_LogicalDiskPartition1 (hda1) + + ste_PersonalFinances + + + + + res_LogicalDiskPartition2 (hda2) + + ste_InternetInsecure + + + + + res_EthernetCard + + ste_NetworkAdapter0 + + + + + res_SecurityToken + + ste_PersonalFinances + + + + + res_GraphicsAdapter + + ste_SystemManagement + + + + + diff --git a/tools/security/policies/ste/ste-security_policy.xml b/tools/security/policies/ste/ste-security_policy.xml new file mode 100644 index 0000000000..16b83223d5 --- /dev/null +++ b/tools/security/policies/ste/ste-security_policy.xml @@ -0,0 +1,27 @@ + + + + + + + + ste-security_policy + 2005-08-10 + + + + + + + ste_SystemManagement + ste_PersonalFinances + ste_InternetInsecure + ste_DonatedCycles + ste_PersistentStorageA + ste_NetworkAdapter0 + + + + diff --git a/tools/security/policy.txt b/tools/security/policy.txt new file mode 100644 index 0000000000..792ed2c236 --- /dev/null +++ b/tools/security/policy.txt @@ -0,0 +1,405 @@ +## +# policy.txt +# +# Author: +# Reiner Sailer 08/15/2005 +# +# +# This file gives an overview of the security policies currently +# provided and also gives some reasoning about how to assign +# labels to domains. +## + +Xen access control policies + + +General explanation of supported security policies: +===================================================== + +We have implemented the mandatory access control architecture of our +hypervisor security architecture (sHype) for the Xen hypervisor. It +controls communication (in Xen: event channels, grant tables) between +Virtual Machines (from here on called domains) and through this the +virtual block devices, networking, and shared memory are implemented +on top of these communication means. While we have implemented the +described policies and access control architecture for other +hypervisor systems, we will describe below specifically its +implementation and use in the Xen hypervisor. The policy enforcement +is called mandatory regarding user domains since the policy it is +given by the security administration and enforced independently of the +user domains by the Xen hypervisor in cooperation with the domain +management. + +The access control architecture consists of three parts: + +i) The access control policy determines the "command set" of the ACM +and the hooks with which they can be configured to constrain the +sharing of virtual resources. The current access control architecture +implemented for Xen supports two policies: Chinese Wall and Simple +Type Enforcement, which we describe in turn below. + + +ii) The actually enforced policy instantiation uses the policy +language (i) to configure the Xen access control in a way that suits +the specific application (home desktop environment, company desktop, +Web server system, etc.). We have defined an exemplary policy +instantiation for Chinese Wall (chwall policy) and Simple Type +Enforcement (ste policy) for a desktop system. We offer these policies +in combination since they are controlling orthogonal events. + + +iii) The access control module (ACM) and related hooks are part of the +core hypervisor and their controls cannot be bypassed by domains. The +ACM and hooks are the active security components. We refer to +publications that describe how access control is enforced in the Xen +hypervisor using the ACM (access decision) and the hooks (decision +enforcement) inserted into the setup of event channels and grant +tables, and into domain operations (create, destroy, save, restore, +migrate). These controls decide based on the active policy +configuration (see i. and ii.) if the operation proceeds of if the +operation is aborted (denied). + + +In general, security policy instantiations in the Xen access control +framework are defined by two files: + +a) a single "policy-name"-security_policy.xml file that defines the +types known to the ACM and policy rules based on these types + +b) a single "policy-name"-security_label_template.xml file that +defines labels based on known types + +Every security policy has its own sub-directory under +"Xen-root"/tools/security/policies in order to simplify their +management and the security policy tools. We will describe those files +for our example policy (Chinese Wall and Simple Type Enforcement) in +more detail as we go along. Eventually, we will move towards a system +installation where the policies will reside under /etc. + + +CHINESE WALL +============ + +The Chinese Wall policy enables the user to define "which workloads +(domain payloads) cannot run on a single physical system at the same +time". Why would we want to prevent workloads from running at the same +time on the same system? This supports requirements that can (but +don't have to) be rooted in the measure of trust into the isolation of +different domains that share the same hardware. Since the access +control architecture aims at high performance and non-intrusive +implementation, it currently does not address covert (timing) channels +and aims at medium assurance. Users can apply the Chinese Wall policy +to guarantee an air-gap between very sensitive payloads both regarding +covert information channels and regarding resource starvation. + +To enable the CW control, each domain is labeled with a set of Chinese +Wall types and CW Conflict Sets are defined which include those CW +types that cannot run simultaneously on the same hardware. This +interpretation of conflict sets is the only policy rule for the Chines +Wall policy. + +This is enforced by controlling the start of domains according to +their assigned CW worload types. Domains with Chinese Wall types that +appear in a common conflict set are running mutually exclusive on a +platform, i.e., once a domain with one of the cw-types of a conflict +set is running, no domain with another cw-type of the same conflict +set can start until the first domain is destroyed, paused, or migrated +away from the physical system (this assumes that such a partition can +no longer be observed). The idea is to assign cw-types according to +the type of payload that a domain runs and to use the Chinese Wall +policy to ensure that payload types can be differentiated by the +hypervisor and can be prevented from being executed on the same system +at the same time. Using the flexible CW policy maintains system +consolidation and workload-balancing while introducing guaranteed +constraints where necessary. + + +Example of a Chinese Wall Policy Instantiation +---------------------------------------------- + +The file chwall-security_policy.xml defines the Chinese Wall types as +well as the conflict sets for our example policy (you find it in the +directory "xen_root"/tools/security/policies/chwall). + +It defines four Chinese Wall types (prefixed with cw_) with the +following meaning: + +* cw_SystemsManagement is a type identifying workloads for systems +management, e.g., domain management, device management, or hypervisor +management. + +* cw_Sensitive is identifying workloads that are critical to the user +for one reason or another. + +* cw_Distrusted is identifying workloads a user does not have much +confidence in. E.g. a domain used for surfing in the internet without +protection( i.e., active-X, java, java-script, executing web content) +or for (Internet) Games should be typed this way. + +* cw_Isolated is identifying workloads that are supposedly isolated by +use of the type enforcement policy (described below). For example, if +a user wants to donate cycles to seti@home, she can setup a separate +domain for a Boinc (http://boinc.ssl.berkeley.edu/) client, disable +this domain from accessing the hard drive and from communicating to +other local domains, and type it as cw_Isolated. We will look at a +specific example later. + +The example policy uses the defined types to define one conflict set: +Protection1 = {cw_Sensitive, cw_Distrusted}. This conflict set tells +the hypervisor that once a domain typed as cw_Sensitive is running, a +domain typed as cw_Distrusted cannot run concurrently (and the other +way round). With this policy, a domain typed as cw_Isolated is allowed +to run simultaneously with domains tagged as cw_Sensitive. + +Consequently, the access control module in the Xen hypervisor +distinguishes in this example policy 4 different workload types in +this example policy. It is the user's responsibility to type the +domains in a way that reflects the workloads of these domains and, in +the case of cw_Isolated, its properties, e.g. by configuring the +sharing capabilities of the domain accordingly by using the simple +type enforcement policy. + +Users can define their own or change the existing example policy +according to their working environment and security requirements. To +do so, replace the file chwall-security_policy.xml with the new +policy. + + +SIMPLE TYPE ENFORCEMENT +======================= + +The file ste-security_policy.xml defines the simple type enforcement +types for our example policy (you find it in the directory +"xen_root"/tools/security/policies/ste). The Simple Type Enforcement +policy defines which domains can share information with which other +domains. To this end, it controls + +i) inter-domain communication channels (e.g., network traffic, events, +and shared memory). + +ii) access of domains to physical resources (e.g., hard drive, network +cards, graphics adapter, keyboard). + +In order to enable the hypervisor to distinguish different domains and +the user to express access rules, the simple type enforcement defines +a set of types (ste_types). + +The policy defines that communication between domains is allowed if +the domains share a common STE type. As with the chwall types, STE +types should enable the differentiation of workloads. The simple type +enforcement access control implementation in the hypervisor enforces +that domains can only communicate (setup event channels, grant tables) +if they share a common type, i.e., both domains have assigned at least +on type in common. A domain can access a resource, if the domain and +the resource share a common type. Hence, assigning STE types to +domains and resources allows users to define constraints on sharing +between domains and to keep sensitive data confined from distrusted +domains. + +Domain <--> Domain Sharing +'''''''''''''''''''''''''' +(implemented but its effective use requires factorization of Dom0) + +a) Domains with a single STE type (general user domains): Sharing +between such domains is enforced entirely by the hypervisor access +control. It is independent of the domains and does not require their +co-operation. + +b) Domains with multiple STE types: One example is a domain that +virtualizes a physical resource (e.g., hard drive) and serves it as +multiple virtual resources (virtual block drives) to other domains of +different types. The idea is that only a specific device domain has +assigned the type required to access the physical hard-drive. Logical +drives are then assigned the types of domains that have access to this +logical drive. Since the Xen hypervisor cannot distinguish between the +logical drives, the access control (type enforcement) is delegated to +the device domain, which has access to the types of domains requesting +to mount a logical drive as well as the types assigned to the +different available logical drives. + +Currently in Xen, Dom0 controls all hardware, needs to communicate +with all domains during their setup, and intercepts all communication +between domains. Consequently, Dom0 needs to be assigned all types +used and must be completely trusted to maintain the separation of +informatio ncoming from domains with different STE types. Thus a +refactoring of Dom0 is recommended for stronger confinement +guarantees. + +Domain --> RESOURCES Access +''''''''''''''''''''''''''' +(current work) + +We define for each resource that we want to distinguish a separate STE +type. Each STE type is assigned to the respective resource and to +those domains that are allowed to access this resource. Type +enforcement will guarantee that other domains cannot access this +resource since they don't share the resource's STE type. + +Since in the current implementation of Xen, Dom0 controls access to +all hardware (e.g., disk drives, network), Domain-->Resource access +control enforcement must be implemented in Dom0. This is possible +since Dom0 has access to both the domain configuration (including the +domain STE types) and the resource configuration (including the +resource STE types). + +For purposes of gaining higher assurance in the resulting system, it +may be desirable to reduce the size of dom0 by adding one or more +"device domains" (DDs). These DDs, e.g. providing storage or network +access, can support one or more physical devices, and manage +enforcement of MAC policy relevant for said devices. Security benefits +come from the smaller size of these DDs, as they can be more easily +audited than monolithic device driver domains. DDs can help to obtain +maximum security benefit from sHype. + + +Example of a Simple Type Enforcement Policy Instantiation +--------------------------------------------------------- + +We define the following types: + +* ste_SystemManagement identifies workloads (and domains that runs +them) that must share information to accomplish the management of the +system + +* ste_PersonalFinances identifies workloads that are related to +sensitive programs such as HomeBanking applications or safely +configured web browsers for InternetBanking + +* ste_InternetInsecure identifies workloads that are very +function-rich and unrestricted to offer for example an environment +where internet games can run efficiently + +* ste_DonatedCycles identifies workloads that run on behalf of others, +e.g. a Boinc client + +* ste_PersistentStorage identifies workloads that have direct access +to persistent storage (e.g., hard drive) + +* ste_NetworkAccess identifies workload that have direct access to +network cards and related networks + + + +SECURITY LABEL TEMPLATES +======================== + +We introduce security label templates because it is difficult for +users to ensure tagging of domains consistently and since there are +--as we have seen in the case of isolation-- useful dependencies +between the policies. Security Label Templates define type sets that +can be addressed by more user-friendly label names, +e.g. dom_Homebanking describes a typical typeset tagged to domains +used for sensitive Homebanking work-loads. Labels are defined in the +file + +Using Security Label Templates has multiple advantages: +a) easy reference of typical sets of type assignments +b) consistent interpretation of type combinations +c) meaningful application-level label names + +The definition of label templates depends on the combination of +policies that are used. We will describe some of the labels defined +for the Chinese Wall and Simple Type Enforcement combination. + +In the BoincClient example, the label_template file specifies that +this Label is assigned the Chinese Wall type cw_Isolated. We do this +assuming that this BoincClient is isolated against the rest of the +system infrastructure (no persistent memory, no sharing with local +domains). Since cw_Isolated is not included in any conflict set, it +can run at any time concurrently with any other domain. The +ste_DonatedCycles type assigned to the BoincClient reflect the +isolation assumption: it is only assigned to the dom_NetworkDomain +giving the BoincClient domain access to the network to communicate +with its BoincServer. + +The strategy for combining types into Labels is the following: First +we define a label for each type of general user domain +(workload-oriented). Then we define a new label for each physical +resource that shall be shared using a DD domain (e.g., disk) and for +each logical resource offered through this physical resource (logical +disk partition). We define then device domain labels (here: +dom_SystemManagement, dom_StorageDomain, dom_NetworkDomain) which +include the types of the physical resources (e.g. hda) their domains +need to connect to. Such physical resources can only be accessed +directly by device domains types with the respective device's STE +type. Additionally we assign to such a device domain Label the STE +types of those user domains that are allowed to access one of the +logical resources (e.g., hda1, hda2) built on top of this physical +resource through the device domain. + + +Label Construction Example: +--------------------------- + +We define here a storage domain label for a domain that owns a real +disk drive and creates the logical disk partitions hda1 and hda2 which +it serves to domains labeled dom_HomeBanking and dom_Fun +respectively. The labels we refer to are defined in the label template +file policies/chwall_ste/chwall_ste-security-label-template.xml. + +step1: To distinguish different shared disk drives, we create a +separate Label and STE type for each of them. Here: we create a type +ste_PersistentStorageA for disk drive hda. If you have another disk +drive, you may define another persistent storage type +ste_PersistentStorageB in the chwall_ste-security_policy.xml. + +step2: To distinguish different domains, we create multiple domain +labels including different types. Here: label dom_HomeBanking includes +STE type ste_PersonalFinances, label dom_Fun includes STE type +ste_InternetInsecure. + +step3: The storage domain in charge of the hard drive A needs access +to this hard drive. Therefore the storage domain label +dom_StorageDomain must include the type assigned to the hard drive +(ste_PersistentStorageA). + +step4: In order to serve dom hda1 to domains labeled dom_HomeBanking +and hda2 to domains labeled dom_Fun, the storage domain label must +include the types of those domains as well (ste_PersonalFinance, +ste_InternetInsecure). + +step5: In order to keep the data for different types safely apart, the +different logical disk partitions must be assigned unique labels and +types, which are used inside the storage domain to extend the ACM +access enforcement to logical resources served from inside the storage +domain. We define labels "res_LogicalDiskPartition1 (hda1)" and assign +it to hda1 and "res_LogicalDiskPartition2 (hda2)" and assign it to +hda2. These labels must include the STE types of those domains that +are allowed to use them (e.g., ste_PersonalFinances for hda1). + +The overall mandatory access control is then enforced in 3 different +Xen components and these components use a single consistent policy to +co-operatively enforce the policy. In the storage domain example, we +have three components that co-operate: + +1. The ACM module inside the hypervisor enforces: communication between +user domains and the storage domain (only domains including types +ste_PersonalFinances or ste_InternetInsecure can communicate with the +storage domain and request access to logical resource). This confines +the sharing to the types assigned to the storage domain. + +2. The domain management will enforce (work in progress): assignment of +real resources (hda) to domains (storage domain) that share a +type with the resource. + +3. If the storage domain serves multiple STE types (as in our example), +it enforces (work in progress): that domains can access (mount) +logical resources only if they share an STE type with the respective +resource. In our example, domains with the STE type +ste_PersonalFinances can request access (mount) to logical resource +hda1 from the storage domain. + +If you look at the virtual machine label dom_StorageDomain, you will +see the minimal set of types assigned to our domain manageing disk +drive hda for serving logical disk partitions exclusively to +dom_HomeBanking and dom_Fun. + +Similary, network domains can confine access to the network or +network communication between user domains. + +As a result, device domains (e.g., storage domain, network domain) +must be simple and small to ensure their correct co-operation in the +type enforcement model. If such trust is not possible, then hardware +should be assigned exclusively to a single type (or to a single +partition) in which case the hypervisor ACM enforcement enforces the +types independently. diff --git a/tools/security/readme.txt b/tools/security/readme.txt new file mode 100644 index 0000000000..688d640b0c --- /dev/null +++ b/tools/security/readme.txt @@ -0,0 +1,29 @@ + +## +# readme.txt +# +# Author: +# Reiner Sailer 08/15/2005 +# +# +# This file is a toc for information regarding +# the access control policy and tools in Xen. +## + +1. policy.txt: + + describes the general reasoning and examples for access + control policies in Xen + + +2. install.txt + + describes the activation of the access control framework + in Xen + +3. example.txt + + describes the available tools for managing security policies + in Xen and the tools to label domains + + diff --git a/tools/security/secpol_compat.h b/tools/security/secpol_compat.h new file mode 100644 index 0000000000..7f497ba2fc --- /dev/null +++ b/tools/security/secpol_compat.h @@ -0,0 +1,14 @@ +/* secpol_compat.h + * 'translates' data types necessary to + * include + */ +#include + +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; diff --git a/tools/security/secpol_tool.c b/tools/security/secpol_tool.c index f7a084eb77..a22908d7c0 100644 --- a/tools/security/secpol_tool.c +++ b/tools/security/secpol_tool.c @@ -31,18 +31,8 @@ #include #include #include -#include #include - -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 "secpol_compat.h" #include #include #include @@ -270,171 +260,6 @@ void acm_dump_policy_buffer(void *buf, int buflen) } } -/*************************** set policy ****************************/ - -int acm_domain_set_chwallpolicy(void *bufstart, int buflen) -{ -#define CWALL_MAX_SSIDREFS 6 -#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 j; - - chwall_bin_pol->chwall_max_types = htonl(CWALL_MAX_TYPES); - chwall_bin_pol->chwall_max_ssidrefs = htonl(CWALL_MAX_SSIDREFS); - chwall_bin_pol->policy_code = htonl(ACM_CHINESE_WALL_POLICY); - chwall_bin_pol->policy_version = htonl(ACM_CHWALL_VERSION); - chwall_bin_pol->chwall_ssid_offset = - htonl(sizeof(struct acm_chwall_policy_buffer)); - chwall_bin_pol->chwall_max_conflictsets = - htonl(CWALL_MAX_CONFLICTSETS); - chwall_bin_pol->chwall_conflict_sets_offset = - htonl(ntohl(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 + - ntohl(chwall_bin_pol->chwall_ssid_offset)); - memset(ssidrefs, 0, - CWALL_MAX_TYPES * CWALL_MAX_SSIDREFS * sizeof(domaintype_t)); - - /* now set type j-1 for ssidref i+1 */ - for (j = 0; j <= CWALL_MAX_SSIDREFS; j++) - if ((0 < j) && (j <= CWALL_MAX_TYPES)) - ssidrefs[j * CWALL_MAX_TYPES + j - 1] = 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 + - ntohl(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]={1,5,6} */ - if (CWALL_MAX_TYPES > 3) - { - conflicts[2] = htons(1); - conflicts[3] = htons(1); /* {2,3} */ - conflicts[CWALL_MAX_TYPES + 1] = 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 6 -#define STE_MAX_TYPES 5 - - struct acm_ste_policy_buffer *ste_bin_pol = - (struct acm_ste_policy_buffer *) bufstart; - domaintype_t *ssidrefs; - int j, ret = 0; - - ste_bin_pol->ste_max_types = htonl(STE_MAX_TYPES); - ste_bin_pol->ste_max_ssidrefs = htonl(STE_MAX_SSIDREFS); - ste_bin_pol->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); - ste_bin_pol->policy_version = htonl(ACM_STE_VERSION); - ste_bin_pol->ste_ssid_offset = - htonl(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 + ntohl(ste_bin_pol->ste_ssid_offset)); - memset(ssidrefs, 0, - STE_MAX_TYPES * STE_MAX_SSIDREFS * sizeof(domaintype_t)); - /* all types 1 for ssidref 1 */ - for (j = 0; j < STE_MAX_TYPES; j++) - ssidrefs[1 * STE_MAX_TYPES + j] = htons(1); - /* now set type j-1 for ssidref j */ - for (j = 0; j < STE_MAX_SSIDREFS; j++) - if ((0 < j) && (j <= STE_MAX_TYPES)) - ssidrefs[j * STE_MAX_TYPES + j - 1] = 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; - acm_op_t op; - - /* future: read policy from file and set it */ - bin_pol = (struct acm_policy_buffer *) push_buffer; - bin_pol->policy_version = htonl(ACM_POLICY_VERSION); - bin_pol->magic = htonl(ACM_MAGIC); - bin_pol->primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY); - bin_pol->secondary_policy_code = - htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); - - bin_pol->len = htonl(sizeof(struct acm_policy_buffer)); - bin_pol->primary_buffer_offset = htonl(ntohl(bin_pol->len)); - ret = - acm_domain_set_chwallpolicy(push_buffer + - ntohl(bin_pol->primary_buffer_offset), - MAX_PUSH_BUFFER - - ntohl(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 = htonl(ntohl(bin_pol->len)); - ret = acm_domain_set_stepolicy(push_buffer + - ntohl(bin_pol->secondary_buffer_offset), - MAX_PUSH_BUFFER - - ntohl(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 = ACM_SETPOLICY; - op.interface_version = ACM_INTERFACE_VERSION; - op.u.setpolicy.pushcache = (void *) push_buffer; - op.u.setpolicy.pushcache_size = ntohl(bin_pol->len); - ret = do_acm_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 @@ -602,7 +427,6 @@ int acm_domain_dumpstats(int xc_handle) void usage(char *progname) { printf("Use: %s \n" - "\t setpolicy\n" "\t getpolicy\n" "\t dumpstats\n" "\t loadpolicy \n", progname); @@ -623,12 +447,7 @@ int main(int argc, char **argv) exit(-1); } - if (!strcmp(argv[1], "setpolicy")) - { - if (argc != 2) - usage(argv[0]); - ret = acm_domain_setpolicy(acm_cmd_fd); - } else if (!strcmp(argv[1], "getpolicy")) { + if (!strcmp(argv[1], "getpolicy")) { if (argc != 2) usage(argv[0]); ret = acm_domain_getpolicy(acm_cmd_fd); diff --git a/tools/security/secpol_xml2bin.c b/tools/security/secpol_xml2bin.c new file mode 100644 index 0000000000..aaa3744f08 --- /dev/null +++ b/tools/security/secpol_xml2bin.c @@ -0,0 +1,1396 @@ +/**************************************************************** + * secpol_xml2bin.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: Reiner Sailer + * + * Maintained: + * Reiner Sailer + * 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. + * + * sHype policy translation tool. This tool takes an XML + * policy specification as input and produces a binary + * policy file that can be loaded into Xen through the + * ACM operations (secpol_tool loadpolicy) interface or at + * boot time (grub module parameter) + * + * indent -i4 -kr -nut + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "secpol_compat.h" +#include + +#include "secpol_xml2bin.h" + +#define DEBUG 0 + +/* primary / secondary policy component setting */ +enum policycomponent { CHWALL, STE, NULLPOLICY } + primary = NULLPOLICY, secondary = NULLPOLICY; + +/* general list element for ste and chwall type queues */ +struct type_entry { + TAILQ_ENTRY(type_entry) entries; + char *name; /* name of type from xml file */ + type_t mapping; /* type mapping into 16bit */ +}; + +TAILQ_HEAD(tailhead, type_entry) ste_head, chwall_head; + +/* general list element for all label queues */ +enum label_type { VM, RES, ANY }; +struct ssid_entry { + TAILQ_ENTRY(ssid_entry) entries; + char *name; /* label name */ + enum label_type type; /* type: VM / RESOURCE LABEL */ + u_int32_t num; /* ssid or referenced ssid */ + int is_ref; /* if this entry references earlier ssid number */ + unsigned char *row; /* index of types (if not a reference) */ +}; + +TAILQ_HEAD(tailhead_ssid, ssid_entry) ste_ssid_head, chwall_ssid_head, + conflictsets_head; +struct ssid_entry *current_chwall_ssid_p = NULL; +struct ssid_entry *current_ste_ssid_p = NULL; +struct ssid_entry *current_conflictset_p = NULL; + +/* which label to assign to dom0 during boot */ +char *bootstrap_label; + +u_int32_t max_ste_ssids = 0; +u_int32_t max_chwall_ssids = 0; +u_int32_t max_chwall_labels = 0; +u_int32_t max_ste_labels = 0; +u_int32_t max_conflictsets = 0; + +char *current_ssid_name; /* store name until structure is allocated */ +char *current_conflictset_name; /* store name until structure is allocated */ + +/* dynamic list of type mappings for STE */ +u_int32_t max_ste_types = 0; + +/* dynamic list of type mappings for CHWALL */ +u_int32_t max_chwall_types = 0; + +/* dynamic list of conflict sets */ +int max_conflict_set = 0; + +/* which policies are defined */ +int have_ste = 0; +int have_chwall = 0; + +/* input/output file names */ +char *policy_filename = NULL, + *label_filename = NULL, + *binary_filename = NULL, *mapping_filename = NULL; + +void usage(char *prg) +{ + printf("usage:\n%s policyname[-policy.xml/-security_label_template.xml]\n", + prg); + exit(EXIT_FAILURE); +} + + +/***************** policy-related parsing *********************/ + +char *type_by_mapping(struct tailhead *head, u_int32_t mapping) +{ + struct type_entry *np; + for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next) + if (np->mapping == mapping) + return np->name; + return NULL; +} + + +struct type_entry *lookup(struct tailhead *head, char *name) +{ + struct type_entry *np; + for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next) + if (!(strcmp(np->name, name))) + return np; + return NULL; +} + +/* enforces single-entry lists */ +int add_entry(struct tailhead *head, char *name, type_t mapping) +{ + struct type_entry *e; + if (lookup(head, name)) + { + printf("Error: Type >%s< defined more than once.\n", name); + return -EFAULT; /* already in the list */ + } + if (!(e = malloc(sizeof(struct type_entry)))) + return -ENOMEM; + + e->name = name; + e->mapping = mapping; + TAILQ_INSERT_TAIL(head, e, entries); + return 0; +} + +int totoken(char *tok) +{ + int i; + for (i = 0; token[i] != NULL; i++) + if (!strcmp(token[i], tok)) + return i; + return -EFAULT; +} + +/* conflictsets use the same data structure as ssids; since + * they are similar in structure (set of types) + */ +int init_next_conflictset(void) +{ + struct ssid_entry *conflictset = malloc(sizeof(struct ssid_entry)); + + if (!conflictset) + return -ENOMEM; + + conflictset->name = current_conflictset_name; + conflictset->num = max_conflictsets++; + conflictset->is_ref = 0; /* n/a for conflictsets */ + /** + * row: allocate one byte per type; + * [i] != 0 --> mapped type >i< is part of the conflictset + */ + conflictset->row = malloc(max_chwall_types); + if (!conflictset->row) + return -ENOMEM; + + memset(conflictset->row, 0, max_chwall_types); + TAILQ_INSERT_TAIL(&conflictsets_head, conflictset, entries); + current_conflictset_p = conflictset; + return 0; +} + +int register_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state) +{ + xmlChar *text; + struct type_entry *e; + + + text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1); + if (!text) + { + printf("Error reading type name!\n"); + return -EFAULT; + } + + switch (state) { + case XML2BIN_stetype_S: + if (add_entry(&ste_head, (char *) text, max_ste_types)) + { + xmlFree(text); + return -EFAULT; + } + max_ste_types++; + break; + + case XML2BIN_chwalltype_S: + if (add_entry(&chwall_head, (char *) text, max_chwall_types)) + { + xmlFree(text); + return -EFAULT; + } + max_chwall_types++; + break; + + case XML2BIN_conflictsettype_S: + /* a) search the type in the chwall_type list */ + e = lookup(&chwall_head, (char *) text); + if (e == NULL) + { + printf("CS type >%s< not a CHWALL type.\n", text); + xmlFree(text); + return -EFAULT; + } + /* b) add type entry to the current cs set */ + if (current_conflictset_p->row[e->mapping]) + { + printf("ERROR: Double entry of type >%s< in conflict set %d.\n", + text, current_conflictset_p->num); + xmlFree(text); + return -EFAULT; + } + current_conflictset_p->row[e->mapping] = 1; + break; + + default: + printf("Incorrect type environment (state = %lx, text = %s).\n", + state, text); + xmlFree(text); + return -EFAULT; + } + return 0; +} + +void set_component_type(xmlNode * cur_node, enum policycomponent pc) +{ + xmlChar *order; + + if ((order = xmlGetProp(cur_node, (xmlChar *) PRIMARY_COMPONENT_ATTR_NAME))) { + if (strcmp((char *) order, PRIMARY_COMPONENT)) + { + printf("ERROR: Illegal attribut value >order=%s<.\n", + (char *) order); + xmlFree(order); + exit(EXIT_FAILURE); + } + if (primary != NULLPOLICY) + { + printf("ERROR: Primary Policy Component set twice!\n"); + exit(EXIT_FAILURE); + } + primary = pc; + xmlFree(order); + } +} + +void walk_policy(xmlNode * start, xmlDocPtr doc, unsigned long state) +{ + xmlNode *cur_node = NULL; + int code; + + for (cur_node = start; cur_node; cur_node = cur_node->next) + { + if ((code = totoken((char *) cur_node->name)) < 0) + { + printf("Unknown token: >%s<. Aborting.\n", cur_node->name); + exit(EXIT_FAILURE); + } + switch (code) { /* adjust state to new state */ + case XML2BIN_SECPOL: + case XML2BIN_STETYPES: + case XML2BIN_CHWALLTYPES: + case XML2BIN_CONFLICTSETS: + walk_policy(cur_node->children, doc, state | (1 << code)); + break; + + case XML2BIN_STE: + if (WRITTEN_AGAINST_ACM_STE_VERSION != ACM_STE_VERSION) + { + printf("ERROR: This program was written against another STE version.\n"); + exit(EXIT_FAILURE); + } + have_ste = 1; + set_component_type(cur_node, STE); + walk_policy(cur_node->children, doc, state | (1 << code)); + break; + + case XML2BIN_CHWALL: + if (WRITTEN_AGAINST_ACM_CHWALL_VERSION != ACM_CHWALL_VERSION) + { + printf("ERROR: This program was written against another CHWALL version.\n"); + exit(EXIT_FAILURE); + } + have_chwall = 1; + set_component_type(cur_node, CHWALL); + walk_policy(cur_node->children, doc, state | (1 << code)); + break; + + case XML2BIN_CSTYPE: + current_conflictset_name = + (char *) xmlGetProp(cur_node, (xmlChar *) "name"); + if (!current_conflictset_name) + current_conflictset_name = ""; + + if (init_next_conflictset()) + { + printf + ("ERROR: creating new conflictset structure failed.\n"); + exit(EXIT_FAILURE); + } + walk_policy(cur_node->children, doc, state | (1 << code)); + break; + + case XML2BIN_TYPE: + if (register_type(cur_node, doc, state)) + exit(EXIT_FAILURE); + /* type leaf */ + break; + + case XML2BIN_TEXT: + case XML2BIN_COMMENT: + case XML2BIN_POLICYHEADER: + /* leaf - nothing to do */ + break; + + default: + printf("Unkonwn token Error (%d)\n", code); + exit(EXIT_FAILURE); + } + + } + return; +} + +int create_type_mapping(xmlDocPtr doc) +{ + xmlNode *root_element = xmlDocGetRootElement(doc); + struct type_entry *te; + struct ssid_entry *se; + int i; + + printf("Creating ssid mappings ...\n"); + + /* initialize the ste and chwall type lists */ + TAILQ_INIT(&ste_head); + TAILQ_INIT(&chwall_head); + TAILQ_INIT(&conflictsets_head); + + walk_policy(root_element, doc, XML2BIN_NULL); + + /* determine primary/secondary policy component orders */ + if ((primary == NULLPOLICY) && have_chwall) + primary = CHWALL; /* default if not set */ + else if ((primary == NULLPOLICY) && have_ste) + primary = STE; + + switch (primary) { + + case CHWALL: + if (have_ste) + secondary = STE; + /* else default = NULLPOLICY */ + break; + + case STE: + if (have_chwall) + secondary = CHWALL; + /* else default = NULLPOLICY */ + break; + + default: + /* NULL/NULL policy */ + break; + } + + if (!DEBUG) + return 0; + + /* print queues */ + if (have_ste) + { + printf("STE-Type queue (%s):\n", + (primary == STE) ? "PRIMARY" : "SECONDARY"); + for (te = ste_head.tqh_first; te != NULL; + te = te->entries.tqe_next) + printf("name=%22s, map=%x\n", te->name, te->mapping); + } + if (have_chwall) + { + printf("CHWALL-Type queue (%s):\n", + (primary == CHWALL) ? "PRIMARY" : "SECONDARY"); + for (te = chwall_head.tqh_first; te != NULL; + te = te->entries.tqe_next) + printf("name=%s, map=%x\n", te->name, te->mapping); + + printf("Conflictset queue (max=%d):\n", max_conflictsets); + for (se = conflictsets_head.tqh_first; se != NULL; + se = se->entries.tqe_next) + { + printf("conflictset name >%s<\n", + se->name ? se->name : "NONAME"); + for (i = 0; i < max_chwall_types; i++) + if (se->row[i]) + printf("#%x ", i); + printf("\n"); + } + } + return 0; +} + + +/***************** template-related parsing *********************/ + +/* add default ssid at head of ssid queues */ +int init_ssid_queues(void) +{ + struct ssid_entry *default_ssid_chwall, *default_ssid_ste; + + default_ssid_chwall = malloc(sizeof(struct ssid_entry)); + default_ssid_ste = malloc(sizeof(struct ssid_entry)); + + if ((!default_ssid_chwall) || (!default_ssid_ste)) + return -ENOMEM; + + /* default chwall ssid */ + default_ssid_chwall->name = "DEFAULT"; + default_ssid_chwall->num = max_chwall_ssids++; + default_ssid_chwall->is_ref = 0; + default_ssid_chwall->type = ANY; + + default_ssid_chwall->row = malloc(max_chwall_types); + + if (!default_ssid_chwall->row) + return -ENOMEM; + + memset(default_ssid_chwall->row, 0, max_chwall_types); + + TAILQ_INSERT_TAIL(&chwall_ssid_head, default_ssid_chwall, entries); + current_chwall_ssid_p = default_ssid_chwall; + max_chwall_labels++; + + /* default ste ssid */ + default_ssid_ste->name = "DEFAULT"; + default_ssid_ste->num = max_ste_ssids++; + default_ssid_ste->is_ref = 0; + default_ssid_ste->type = ANY; + + default_ssid_ste->row = malloc(max_ste_types); + + if (!default_ssid_ste->row) + return -ENOMEM; + + memset(default_ssid_ste->row, 0, max_ste_types); + + TAILQ_INSERT_TAIL(&ste_ssid_head, default_ssid_ste, entries); + current_ste_ssid_p = default_ssid_ste; + max_ste_labels++; + return 0; +} + +int init_next_chwall_ssid(unsigned long state) +{ + struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry)); + + if (!ssid) + return -ENOMEM; + + ssid->name = current_ssid_name; + ssid->num = max_chwall_ssids++; + ssid->is_ref = 0; + + if (state & (1 << XML2BIN_VM)) + ssid->type = VM; + else + ssid->type = RES; + /** + * row: allocate one byte per type; + * [i] != 0 --> mapped type >i< is part of the ssid + */ + ssid->row = malloc(max_chwall_types); + if (!ssid->row) + return -ENOMEM; + + memset(ssid->row, 0, max_chwall_types); + TAILQ_INSERT_TAIL(&chwall_ssid_head, ssid, entries); + current_chwall_ssid_p = ssid; + max_chwall_labels++; + return 0; +} + +int init_next_ste_ssid(unsigned long state) +{ + struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry)); + + if (!ssid) + return -ENOMEM; + + ssid->name = current_ssid_name; + ssid->num = max_ste_ssids++; + ssid->is_ref = 0; + + if (state & (1 << XML2BIN_VM)) + ssid->type = VM; + else + ssid->type = RES; + + /** + * row: allocate one byte per type; + * [i] != 0 --> mapped type >i< is part of the ssid + */ + ssid->row = malloc(max_ste_types); + if (!ssid->row) + return -ENOMEM; + + memset(ssid->row, 0, max_ste_types); + TAILQ_INSERT_TAIL(&ste_ssid_head, ssid, entries); + current_ste_ssid_p = ssid; + max_ste_labels++; + + return 0; +} + + +/* adds a type to the current ssid */ +int add_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state) +{ + xmlChar *text; + struct type_entry *e; + + text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1); + if (!text) + { + printf("Error reading type name!\n"); + return -EFAULT; + } + /* same for all: 1. lookup type mapping, 2. mark type in ssid */ + switch (state) { + case XML2BIN_VM_STE_S: + case XML2BIN_RES_STE_S: + /* lookup the type mapping and include the type mapping into the array */ + if (!(e = lookup(&ste_head, (char *) text))) + { + printf("ERROR: unknown VM STE type >%s<.\n", text); + exit(EXIT_FAILURE); + } + if (current_ste_ssid_p->row[e->mapping]) + printf("Warning: double entry of VM STE type >%s<.\n", text); + + current_ste_ssid_p->row[e->mapping] = 1; + break; + + case XML2BIN_VM_CHWALL_S: + /* lookup the type mapping and include the type mapping into the array */ + if (!(e = lookup(&chwall_head, (char *) text))) + { + printf("ERROR: unknown VM CHWALL type >%s<.\n", text); + exit(EXIT_FAILURE); + } + if (current_chwall_ssid_p->row[e->mapping]) + printf("Warning: double entry of VM CHWALL type >%s<.\n", + text); + + current_chwall_ssid_p->row[e->mapping] = 1; + break; + + default: + printf("Incorrect type environment (state = %lx, text = %s).\n", + state, text); + xmlFree(text); + return -EFAULT; + } + return 0; +} + +void set_bootstrap_label(xmlNode * cur_node) +{ + xmlChar *order; + + if ((order = xmlGetProp(cur_node, (xmlChar *) BOOTSTRAP_LABEL_ATTR_NAME))) + bootstrap_label = (char *)order; + else { + printf("ERROR: No bootstrap label defined!\n"); + exit(EXIT_FAILURE); + } +} + +void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state) +{ + xmlNode *cur_node = NULL; + int code; + + for (cur_node = start; cur_node; cur_node = cur_node->next) + { + if ((code = totoken((char *) cur_node->name)) < 0) + { + printf("Unkonwn token: >%s<. Aborting.\n", cur_node->name); + exit(EXIT_FAILURE); + } + switch (code) { /* adjust state to new state */ + + case XML2BIN_SUBJECTS: + set_bootstrap_label(cur_node); + /* fall through */ + case XML2BIN_VM: + case XML2BIN_RES: + case XML2BIN_SECTEMPLATE: + case XML2BIN_OBJECTS: + walk_labels(cur_node->children, doc, state | (1 << code)); + break; + + case XML2BIN_STETYPES: + /* create new ssid entry to use and point current to it */ + if (init_next_ste_ssid(state)) + { + printf("ERROR: creating new ste ssid structure failed.\n"); + exit(EXIT_FAILURE); + } + walk_labels(cur_node->children, doc, state | (1 << code)); + + break; + + case XML2BIN_CHWALLTYPES: + /* create new ssid entry to use and point current to it */ + if (init_next_chwall_ssid(state)) + { + printf("ERROR: creating new chwall ssid structure failed.\n"); + exit(EXIT_FAILURE); + } + walk_labels(cur_node->children, doc, state | (1 << code)); + + break; + + case XML2BIN_TYPE: + /* add type to current ssid */ + if (add_type(cur_node, doc, state)) + exit(EXIT_FAILURE); + break; + + case XML2BIN_NAME: + if ((state != XML2BIN_VM_S) && (state != XML2BIN_RES_S)) + { + printf("ERROR: >name< out of VM/RES context.\n"); + exit(EXIT_FAILURE); + } + current_ssid_name = (char *) + xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1); + + if (!current_ssid_name) + { + printf("ERROR: empty >nametqh_first; np != NULL; np = np->entries.tqe_next) + { + /* now search from the start until np for the same entry */ + for (ni = head->tqh_first; ni != np; ni = ni->entries.tqe_next) + { + if (ni->is_ref) + continue; + if (memcmp(np->row, ni->row, max_types)) + continue; + /* found one, set np reference to ni */ + np->is_ref = 1; + np->num = ni->num; + (*max_ssids)--; + } + } + + /* now minimize the ssid numbers used (doubles introduce holes) */ + (*max_ssids) = 0; /* reset */ + + for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next) + { + if (np->is_ref) + continue; + + if (np->num != (*max_ssids)) { + /* first reset all later references to the new max_ssid */ + for (ni = np->entries.tqe_next; ni != NULL; ni = ni->entries.tqe_next) + { + if (ni->num == np->num) + ni->num = (*max_ssids); + } + /* now reset num */ + np->num = (*max_ssids)++; + } + else + (*max_ssids)++; + } +} + +/* + * will go away as soon as we have non-static bootstrap ssidref for dom0 + */ +void fixup_bootstrap_label(struct tailhead_ssid *head, + u_int32_t max_types, u_int32_t * max_ssids) +{ + struct ssid_entry *np; + int i; + + /* should not happen if xml / xsd checks work */ + if (!bootstrap_label) + { + printf("ERROR: No bootstrap label defined.\n"); + exit(EXIT_FAILURE); + } + + /* search bootstrap_label */ + for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next) + { + if (!strcmp(np->name, bootstrap_label)) + { + break; + } + } + + if (!np) { + /* bootstrap label not found */ + printf("ERROR: Bootstrap label >%s< not found.\n", bootstrap_label); + exit(EXIT_FAILURE); + } + + /* move this entry ahead in the list right after the default entry so it + * receives ssidref 1/1 */ + TAILQ_REMOVE(head, np, entries); + TAILQ_INSERT_AFTER(head, head->tqh_first, np, entries); + + /* renumber the ssids (we could also just switch places with 1st element) */ + for (np = head->tqh_first, i=0; np != NULL; np = np->entries.tqe_next, i++) + np->num = i; + +} + +int create_ssid_mapping(xmlDocPtr doc) +{ + xmlNode *root_element = xmlDocGetRootElement(doc); + struct ssid_entry *np; + int i; + + printf("Creating label mappings ...\n"); + /* initialize the ste and chwall type lists */ + TAILQ_INIT(&chwall_ssid_head); + TAILQ_INIT(&ste_ssid_head); + + /* init with default ssids */ + if (init_ssid_queues()) + { + printf("ERROR adding default ssids.\n"); + exit(EXIT_FAILURE); + } + + /* now walk the template DOM tree and fill in ssids */ + walk_labels(root_element, doc, XML2BIN_NULL); + + /* + * now sort bootstrap label to the head of the list + * (for now), dom0 assumes its label in the first + * defined ssidref (1/1). 0/0 is the default non-Label + */ + if (have_chwall) + fixup_bootstrap_label(&chwall_ssid_head, max_chwall_types, + &max_chwall_ssids); + if (have_ste) + fixup_bootstrap_label(&ste_ssid_head, max_ste_types, + &max_ste_ssids); + + /* remove any double entries (insert reference instead) */ + if (have_chwall) + remove_doubles(&chwall_ssid_head, max_chwall_types, + &max_chwall_ssids); + if (have_ste) + remove_doubles(&ste_ssid_head, max_ste_types, + &max_ste_ssids); + + if (!DEBUG) + return 0; + + /* print queues */ + if (have_chwall) + { + printf("CHWALL SSID queue (max ssidrefs=%d):\n", max_chwall_ssids); + np = NULL; + for (np = chwall_ssid_head.tqh_first; np != NULL; + np = np->entries.tqe_next) + { + printf("SSID #%02u (Label=%s)\n", np->num, np->name); + if (np->is_ref) + printf("REFERENCE"); + else + for (i = 0; i < max_chwall_types; i++) + if (np->row[i]) + printf("#%02d ", i); + printf("\n\n"); + } + } + if (have_ste) + { + printf("STE SSID queue (max ssidrefs=%d):\n", max_ste_ssids); + np = NULL; + for (np = ste_ssid_head.tqh_first; np != NULL; + np = np->entries.tqe_next) + { + printf("SSID #%02u (Label=%s)\n", np->num, np->name); + if (np->is_ref) + printf("REFERENCE"); + else + for (i = 0; i < max_ste_types; i++) + if (np->row[i]) + printf("#%02d ", i); + printf("\n\n"); + } + } + return 0; +} + +/***************** writing the binary policy *********************/ + +/* + * the mapping file is ascii-based since it will likely be used from + * within scripts (using awk, grep, etc.); + * + * We print from high-level to low-level information so that with one + * pass, any symbol can be resolved (e.g. Label -> types) + */ +int write_mapping(char *filename) +{ + + struct ssid_entry *e; + struct type_entry *t; + int i; + FILE *file; + + if ((file = fopen(filename, "w")) == NULL) + return -EIO; + + fprintf(file, "MAGIC %08x\n", ACM_MAGIC); + fprintf(file, "POLICY %s\n", + basename(policy_filename)); + fprintf(file, "BINARY %s\n", + basename(binary_filename)); + if (have_chwall) + { + fprintf(file, "MAX-CHWALL-TYPES %08x\n", max_chwall_types); + fprintf(file, "MAX-CHWALL-SSIDS %08x\n", max_chwall_ssids); + fprintf(file, "MAX-CHWALL-LABELS %08x\n", max_chwall_labels); + } + if (have_ste) + { + fprintf(file, "MAX-STE-TYPES %08x\n", max_ste_types); + fprintf(file, "MAX-STE-SSIDS %08x\n", max_ste_ssids); + fprintf(file, "MAX-STE-LABELS %08x\n", max_ste_labels); + } + fprintf(file, "\n"); + + /* primary / secondary order for combined ssid synthesis/analysis + * if no primary is named, then chwall is primary */ + switch (primary) { + case CHWALL: + fprintf(file, "PRIMARY CHWALL\n"); + break; + + case STE: + fprintf(file, "PRIMARY STE\n"); + break; + + default: + fprintf(file, "PRIMARY NULL\n"); + break; + } + + switch (secondary) { + case CHWALL: + fprintf(file, "SECONDARY CHWALL\n"); + break; + + case STE: + fprintf(file, "SECONDARY STE\n"); + break; + + default: + fprintf(file, "SECONDARY NULL\n"); + break; + } + fprintf(file, "\n"); + + /* first labels to ssid mappings */ + if (have_chwall) + { + for (e = chwall_ssid_head.tqh_first; e != NULL; + e = e->entries.tqe_next) + { + fprintf(file, "LABEL->SSID %s CHWALL %-25s %8x\n", + (e->type == + VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"), + e->name, e->num); + } + fprintf(file, "\n"); + } + if (have_ste) + { + for (e = ste_ssid_head.tqh_first; e != NULL; + e = e->entries.tqe_next) + { + fprintf(file, "LABEL->SSID %s STE %-25s %8x\n", + (e->type == + VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"), + e->name, e->num); + } + fprintf(file, "\n"); + } + + /* second ssid to type mappings */ + if (have_chwall) + { + for (e = chwall_ssid_head.tqh_first; e != NULL; + e = e->entries.tqe_next) + { + if (e->is_ref) + continue; + + fprintf(file, "SSID->TYPE CHWALL %08x", e->num); + + for (i = 0; i < max_chwall_types; i++) + if (e->row[i]) + fprintf(file, " %s", type_by_mapping(&chwall_head, i)); + + fprintf(file, "\n"); + } + fprintf(file, "\n"); + } + if (have_ste) { + for (e = ste_ssid_head.tqh_first; e != NULL; + e = e->entries.tqe_next) + { + if (e->is_ref) + continue; + + fprintf(file, "SSID->TYPE STE %08x", e->num); + + for (i = 0; i < max_ste_types; i++) + if (e->row[i]) + fprintf(file, " %s", type_by_mapping(&ste_head, i)); + + fprintf(file, "\n"); + } + fprintf(file, "\n"); + } + /* third type mappings */ + if (have_chwall) + { + for (t = chwall_head.tqh_first; t != NULL; t = t->entries.tqe_next) + { + fprintf(file, "TYPE CHWALL %-25s %8x\n", + t->name, t->mapping); + } + fprintf(file, "\n"); + } + if (have_ste) { + for (t = ste_head.tqh_first; t != NULL; t = t->entries.tqe_next) + { + fprintf(file, "TYPE STE %-25s %8x\n", + t->name, t->mapping); + } + fprintf(file, "\n"); + } + fclose(file); + return 0; +} + +unsigned char *write_chwall_binary(u_int32_t * len_chwall) +{ + unsigned char *buf, *ptr; + struct acm_chwall_policy_buffer *chwall_header; + u_int32_t len; + struct ssid_entry *e; + int i; + + if (!have_chwall) + return NULL; + + len = sizeof(struct acm_chwall_policy_buffer) + + sizeof(type_t) * max_chwall_types * max_chwall_ssids + + sizeof(type_t) * max_chwall_types * max_conflictsets; + + buf = malloc(len); + ptr = buf; + + if (!buf) + { + printf("ERROR: out of memory allocating chwall buffer.\n"); + exit(EXIT_FAILURE); + } + /* chwall has 3 parts : header, types, conflictsets */ + + chwall_header = (struct acm_chwall_policy_buffer *) buf; + chwall_header->chwall_max_types = htonl(max_chwall_types); + chwall_header->chwall_max_ssidrefs = htonl(max_chwall_ssids); + chwall_header->policy_code = htonl(ACM_CHINESE_WALL_POLICY); + chwall_header->policy_version = htonl(ACM_CHWALL_VERSION); + chwall_header->chwall_ssid_offset = + htonl(sizeof(struct acm_chwall_policy_buffer)); + chwall_header->chwall_max_conflictsets = htonl(max_conflictsets); + chwall_header->chwall_conflict_sets_offset = + htonl(ntohl(chwall_header->chwall_ssid_offset) + + sizeof(domaintype_t) * max_chwall_ssids * max_chwall_types); + chwall_header->chwall_running_types_offset = 0; /* not set, only retrieved */ + chwall_header->chwall_conflict_aggregate_offset = 0; /* not set, only retrieved */ + ptr += sizeof(struct acm_chwall_policy_buffer); + + /* types */ + for (e = chwall_ssid_head.tqh_first; e != NULL; + e = e->entries.tqe_next) + { + if (e->is_ref) + continue; + + for (i = 0; i < max_chwall_types; i++) + ((type_t *) ptr)[i] = htons((type_t) e->row[i]); + + ptr += sizeof(type_t) * max_chwall_types; + } + + /* conflictsets */ + for (e = conflictsets_head.tqh_first; e != NULL; + e = e->entries.tqe_next) + { + for (i = 0; i < max_chwall_types; i++) + ((type_t *) ptr)[i] = htons((type_t) e->row[i]); + + ptr += sizeof(type_t) * max_chwall_types; + } + + if ((ptr - buf) != len) + { + printf("ERROR: wrong lengths in %s.\n", __func__); + exit(EXIT_FAILURE); + } + + (*len_chwall) = len; + return buf; +} + +unsigned char *write_ste_binary(u_int32_t * len_ste) +{ + unsigned char *buf, *ptr; + struct acm_ste_policy_buffer *ste_header; + struct ssid_entry *e; + u_int32_t len; + int i; + + if (!have_ste) + return NULL; + + len = sizeof(struct acm_ste_policy_buffer) + + sizeof(type_t) * max_ste_types * max_ste_ssids; + + buf = malloc(len); + ptr = buf; + + if (!buf) + { + printf("ERROR: out of memory allocating chwall buffer.\n"); + exit(EXIT_FAILURE); + } + + /* fill buffer */ + ste_header = (struct acm_ste_policy_buffer *) buf; + ste_header->policy_version = htonl(ACM_STE_VERSION); + ste_header->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); + ste_header->ste_max_types = htonl(max_ste_types); + ste_header->ste_max_ssidrefs = htonl(max_ste_ssids); + ste_header->ste_ssid_offset = + htonl(sizeof(struct acm_ste_policy_buffer)); + + ptr += sizeof(struct acm_ste_policy_buffer); + + /* types */ + for (e = ste_ssid_head.tqh_first; e != NULL; e = e->entries.tqe_next) + { + if (e->is_ref) + continue; + + for (i = 0; i < max_ste_types; i++) + ((type_t *) ptr)[i] = htons((type_t) e->row[i]); + + ptr += sizeof(type_t) * max_ste_types; + } + + if ((ptr - buf) != len) + { + printf("ERROR: wrong lengths in %s.\n", __func__); + exit(EXIT_FAILURE); + } + (*len_ste) = len; + return buf; /* for now */ +} + +int write_binary(char *filename) +{ + struct acm_policy_buffer header; + unsigned char *ste_buffer = NULL, *chwall_buffer = NULL; + u_int32_t len; + int fd; + + u_int32_t len_ste = 0, len_chwall = 0; /* length of policy components */ + + /* open binary file */ + if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) <= 0) + return -EIO; + + ste_buffer = write_ste_binary(&len_ste); + chwall_buffer = write_chwall_binary(&len_chwall); + + /* determine primary component (default chwall) */ + header.policy_version = htonl(ACM_POLICY_VERSION); + header.magic = htonl(ACM_MAGIC); + + len = sizeof(struct acm_policy_buffer); + if (have_chwall) + len += len_chwall; + if (have_ste) + len += len_ste; + header.len = htonl(len); + + header.primary_buffer_offset = htonl(sizeof(struct acm_policy_buffer)); + if (primary == CHWALL) + { + header.primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY); + header.secondary_buffer_offset = + htonl((sizeof(struct acm_policy_buffer)) + len_chwall); + } + else if (primary == STE) + { + header.primary_policy_code = + htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); + header.secondary_buffer_offset = + htonl((sizeof(struct acm_policy_buffer)) + len_ste); + } + else + { + /* null policy */ + header.primary_policy_code = htonl(ACM_NULL_POLICY); + header.secondary_buffer_offset = + htonl(header.primary_buffer_offset); + } + + if (secondary == CHWALL) + header.secondary_policy_code = htonl(ACM_CHINESE_WALL_POLICY); + else if (secondary == STE) + header.secondary_policy_code = + htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); + else + header.secondary_policy_code = htonl(ACM_NULL_POLICY); + + if (write(fd, (void *) &header, sizeof(struct acm_policy_buffer)) + != sizeof(struct acm_policy_buffer)) + return -EIO; + + /* write primary policy component */ + if (primary == CHWALL) + { + if (write(fd, chwall_buffer, len_chwall) != len_chwall) + return -EIO; + } + else if (primary == STE) + { + if (write(fd, ste_buffer, len_ste) != len_ste) + return -EIO; + } else + ; /* NULL POLICY has no policy data */ + + /* write secondary policy component */ + if (secondary == CHWALL) + { + if (write(fd, chwall_buffer, len_chwall) != len_chwall) + return -EIO; + } + else if (secondary == STE) + { + if (write(fd, ste_buffer, len_ste) != len_ste) + return -EIO; + } else; /* NULL POLICY has no policy data */ + + close(fd); + return 0; +} + +int is_valid(xmlDocPtr doc) +{ + int err = 0; + xmlSchemaPtr schema_ctxt = NULL; + xmlSchemaParserCtxtPtr schemaparser_ctxt = NULL; + xmlSchemaValidCtxtPtr schemavalid_ctxt = NULL; + + schemaparser_ctxt = xmlSchemaNewParserCtxt(SCHEMA_FILENAME); + schema_ctxt = xmlSchemaParse(schemaparser_ctxt); + schemavalid_ctxt = xmlSchemaNewValidCtxt(schema_ctxt); + +#ifdef VALIDATE_SCHEMA + /* only tested to be available from libxml2-2.6.20 upwards */ + if ((err = xmlSchemaIsValid(schemavalid_ctxt)) != 1) + { + printf("ERROR: Invalid schema file %s (err=%d)\n", + SCHEMA_FILENAME, err); + err = -EIO; + goto out; + } + else + printf("XML Schema %s valid.\n", SCHEMA_FILENAME); +#endif + if ((err = xmlSchemaValidateDoc(schemavalid_ctxt, doc))) + { + err = -EIO; + goto out; + } + out: + xmlSchemaFreeValidCtxt(schemavalid_ctxt); + xmlSchemaFreeParserCtxt(schemaparser_ctxt); + xmlSchemaFree(schema_ctxt); + return (err != 0) ? 0 : 1; +} + +int main(int argc, char **argv) +{ + xmlDocPtr labeldoc = NULL; + xmlDocPtr policydoc = NULL; + + int err = EXIT_SUCCESS; + + char *file_prefix; + int prefix_len; + + if (ACM_POLICY_VERSION != WRITTEN_AGAINST_ACM_POLICY_VERSION) + { + printf("ERROR: This program was written against an older ACM version.\n"); + exit(EXIT_FAILURE); + } + + if (argc != 2) + usage(basename(argv[0])); + + prefix_len = strlen(POLICY_SUBDIR) + + strlen(argv[1]) + 1 /* "/" */ + + strlen(argv[1]) + 1 /* "/" */ ; + + file_prefix = malloc(prefix_len); + policy_filename = malloc(prefix_len + strlen(POLICY_EXTENSION)); + label_filename = malloc(prefix_len + strlen(LABEL_EXTENSION)); + binary_filename = malloc(prefix_len + strlen(BINARY_EXTENSION)); + mapping_filename = malloc(prefix_len + strlen(MAPPING_EXTENSION)); + + if (!file_prefix || !policy_filename || !label_filename || + !binary_filename || !mapping_filename) + { + printf("ERROR allocating file name memory.\n"); + goto out2; + } + + /* create input/output filenames out of prefix */ + strcat(file_prefix, POLICY_SUBDIR); + strcat(file_prefix, argv[1]); + strcat(file_prefix, "/"); + strcat(file_prefix, argv[1]); + + strcpy(policy_filename, file_prefix); + strcpy(label_filename, file_prefix); + strcpy(binary_filename, file_prefix); + strcpy(mapping_filename, file_prefix); + + strcat(policy_filename, POLICY_EXTENSION); + strcat(label_filename, LABEL_EXTENSION); + strcat(binary_filename, BINARY_EXTENSION); + strcat(mapping_filename, MAPPING_EXTENSION); + + labeldoc = xmlParseFile(label_filename); + + if (labeldoc == NULL) + { + printf("Error: could not parse file %s.\n", argv[1]); + goto out2; + } + + printf("Validating label file %s...\n", label_filename); + if (!is_valid(labeldoc)) + { + printf("ERROR: Failed schema-validation for file %s (err=%d)\n", + label_filename, err); + goto out1; + } + + policydoc = xmlParseFile(policy_filename); + + if (policydoc == NULL) + { + printf("Error: could not parse file %s.\n", argv[1]); + goto out1; + } + + printf("Validating policy file %s...\n", policy_filename); + + if (!is_valid(policydoc)) + { + printf("ERROR: Failed schema-validation for file %s (err=%d)\n", + policy_filename, err); + goto out; + } + + /* Init queues and parse policy */ + create_type_mapping(policydoc); + + /* create ssids */ + create_ssid_mapping(labeldoc); + + /* write label mapping file */ + if (write_mapping(mapping_filename)) + { + printf("ERROR: writing mapping file %s.\n", mapping_filename); + goto out; + } + + /* write binary file */ + if (write_binary(binary_filename)) + { + printf("ERROR: writing binary file %s.\n", binary_filename); + goto out; + } + + /* write stats */ + if (have_chwall) + { + printf("Max chwall labels: %u\n", max_chwall_labels); + printf("Max chwall-types: %u\n", max_chwall_types); + printf("Max chwall-ssids: %u\n", max_chwall_ssids); + } + + if (have_ste) + { + printf("Max ste labels: %u\n", max_ste_labels); + printf("Max ste-types: %u\n", max_ste_types); + printf("Max ste-ssids: %u\n", max_ste_ssids); + } + /* cleanup */ + out: + xmlFreeDoc(policydoc); + out1: + xmlFreeDoc(labeldoc); + out2: + xmlCleanupParser(); + return err; +} + diff --git a/tools/security/secpol_xml2bin.h b/tools/security/secpol_xml2bin.h new file mode 100644 index 0000000000..cae08f33d0 --- /dev/null +++ b/tools/security/secpol_xml2bin.h @@ -0,0 +1,139 @@ +/**************************************************************** + * secpol_xml2bin.h + * + * Copyright (C) 2005 IBM Corporation + * + * Authors: + * Reiner Sailer + * + * 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. + * + */ +#define POLICY_SUBDIR "policies/" +#define POLICY_EXTENSION "-security_policy.xml" +#define LABEL_EXTENSION "-security_label_template.xml" +#define BINARY_EXTENSION ".bin" +#define MAPPING_EXTENSION ".map" +#define PRIMARY_COMPONENT_ATTR_NAME "order" +#define BOOTSTRAP_LABEL_ATTR_NAME "bootstrap" +#define PRIMARY_COMPONENT "PrimaryPolicyComponent" +#define SCHEMA_FILENAME "policies/security_policy.xsd" + +/* basic states (used as 1 << X) */ +#define XML2BIN_SECPOL 0 /* policy tokens */ +#define XML2BIN_STE 1 +#define XML2BIN_CHWALL 2 +#define XML2BIN_CONFLICTSETS 3 +#define XML2BIN_CSTYPE 4 + +#define XML2BIN_SECTEMPLATE 5 /* label tokens */ +#define XML2BIN_POLICYHEADER 6 +#define XML2BIN_LABELHEADER 7 +#define XML2BIN_SUBJECTS 8 +#define XML2BIN_OBJECTS 9 +#define XML2BIN_VM 10 +#define XML2BIN_RES 11 + +#define XML2BIN_STETYPES 12 /* shared tokens */ +#define XML2BIN_CHWALLTYPES 13 +#define XML2BIN_TYPE 14 +#define XML2BIN_NAME 15 +#define XML2BIN_TEXT 16 +#define XML2BIN_COMMENT 17 + +/* type "data type" (currently 16bit) */ +typedef u_int16_t type_t; + +/* list of known elements and token equivalent * + * state constants and token positions must be * + * in sync for correct state recognition */ + +char *token[20] = /* parser triggers */ +{ + [0] = "SecurityPolicyDefinition", /* policy xml */ + [1] = "SimpleTypeEnforcement", + [2] = "ChineseWall", + [3] = "ConflictSets", + [4] = "Conflict", /* label-template xml */ + [5] = "SecurityLabelTemplate", + [6] = "PolicyHeader", + [7] = "LabelHeader", + [8] = "SubjectLabels", + [9] = "ObjectLabels", + [10] = "VirtualMachineLabel", + [11] = "ResourceLabel", + [12] = "SimpleTypeEnforcementTypes", /* common tags */ + [13] = "ChineseWallTypes", + [14] = "Type", + [15] = "Name", + [16] = "text", + [17] = "comment", + [18] = NULL, +}; + +/* important combined states */ +#define XML2BIN_NULL 0 + +/* policy xml parsing states _S */ + +/* e.g., here we are in a environment, * + * so when finding a type element, we know where to put it */ +#define XML2BIN_stetype_S ((1 << XML2BIN_SECPOL) | \ + (1 << XML2BIN_STE) | \ + (1 << XML2BIN_STETYPES)) + +#define XML2BIN_chwalltype_S ((1 << XML2BIN_SECPOL) | \ + (1 << XML2BIN_CHWALL) | \ + (1 << XML2BIN_CHWALLTYPES)) + +#define XML2BIN_conflictset_S ((1 << XML2BIN_SECPOL) | \ + (1 << XML2BIN_CHWALL) | \ + (1 << XML2BIN_CONFLICTSETS)) + +#define XML2BIN_conflictsettype_S ((1 << XML2BIN_SECPOL) | \ + (1 << XML2BIN_CHWALL) | \ + (1 << XML2BIN_CONFLICTSETS) | \ + (1 << XML2BIN_CSTYPE)) + + +/* label xml states */ +#define XML2BIN_VM_S ((1 << XML2BIN_SECTEMPLATE) | \ + (1 << XML2BIN_SUBJECTS) | \ + (1 << XML2BIN_VM)) + +#define XML2BIN_RES_S ((1 << XML2BIN_SECTEMPLATE) | \ + (1 << XML2BIN_OBJECTS) | \ + (1 << XML2BIN_RES)) + +#define XML2BIN_VM_STE_S ((1 << XML2BIN_SECTEMPLATE) | \ + (1 << XML2BIN_SUBJECTS) | \ + (1 << XML2BIN_VM) | \ + (1 << XML2BIN_STETYPES)) + +#define XML2BIN_VM_CHWALL_S ((1 << XML2BIN_SECTEMPLATE) | \ + (1 << XML2BIN_SUBJECTS) | \ + (1 << XML2BIN_VM) | \ + (1 << XML2BIN_CHWALLTYPES)) + +#define XML2BIN_RES_STE_S ((1 << XML2BIN_SECTEMPLATE) | \ + (1 << XML2BIN_OBJECTS) | \ + (1 << XML2BIN_RES) | \ + (1 << XML2BIN_STETYPES)) + + + +/* check versions of headers against which the + * xml2bin translation tool was written + */ + +/* protects from unnoticed changes in struct acm_policy_buffer */ +#define WRITTEN_AGAINST_ACM_POLICY_VERSION 1 + +/* protects from unnoticed changes in struct acm_chwall_policy_buffer */ +#define WRITTEN_AGAINST_ACM_CHWALL_VERSION 1 + +/* protects from unnoticed changes in struct acm_ste_policy_buffer */ +#define WRITTEN_AGAINST_ACM_STE_VERSION 1 diff --git a/tools/security/setlabel.sh b/tools/security/setlabel.sh new file mode 100644 index 0000000000..e0d8ed741a --- /dev/null +++ b/tools/security/setlabel.sh @@ -0,0 +1,345 @@ +#!/bin/sh +# * +# * setlabel +# * +# * Copyright (C) 2005 IBM Corporation +# * +# * Authors: +# * Stefan Berger +# * +# * 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. +# * +# * 'setlabel' labels virtual machine (domain) configuration files with +# * security identifiers that can be enforced in Xen. +# * +# * 'setlabel -?' shows the usage of the program +# * +# * 'setlabel -l vmconfig-file' lists all available labels (only VM +# * labels are used right now) +# * +# * 'setlabel vmconfig-file security-label map-file' inserts the 'ssidref' +# * that corresponds to the security-label under the +# * current policy (if policy changes, 'label' +# * must be re-run over the configuration files; +# * map-file is created during policy translation and +# * is found in the policy's directory +# + +if [ -z "$runbash" ]; then + runbash="1" + export runbash + exec sh -c "bash $0 $*" +fi + + +usage () +{ + echo "Usage: $0 [Option]