Commit message: KVM: PIT: control word is write-only

PIT control word (address 0x43) is write-only, reads are undefined.

Cc: stable@kernel.org
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
CVE: CVE-2015-3214
CWE: CWE-119
Vulnerability description: The pit_ioport_read in i8254.c in the Linux kernel before 2.6.33 and QEMU before 2.3.1 does not distinguish between read lengths and write lengths, which might allow guest OS users to execute arbitrary code on the host OS by triggering use of an invalid index.

Project: linux
File: i8254.c

static void __inject_pit_timer_intr(struct kvm *kvm)
{
	struct kvm_vcpu *vcpu;
	int i;

	kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
	kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);

	/*
	 * Provides NMI watchdog support via Virtual Wire mode.
	 * The route is: PIT -> PIC -> LVT0 in NMI mode.
	 *
	 * Note: Our Virtual Wire implementation is simplified, only
	 * propagating PIT interrupts to all VCPUs when they have set
	 * LVT0 to NMI delivery. Other PIC interrupts are just sent to
	 * VCPU0, and only if its LVT0 is in EXTINT mode.
	 */
	if (kvm->arch.vapics_in_nmi_mode > 0)
		kvm_for_each_vcpu(i, vcpu, kvm)
			kvm_apic_nmi_wd_deliver(vcpu);
}

Project: linux
File: i8254.c

static s64 __kpit_elapsed(struct kvm *kvm)
{
	s64 elapsed;
	ktime_t remaining;
	struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;

	if (!ps->pit_timer.period)
		return 0;

	/*
	 * The Counter does not stop when it reaches zero. In
	 * Modes 0, 1, 4, and 5 the Counter ``wraps around'' to
	 * the highest count, either FFFF hex for binary counting
	 * or 9999 for BCD counting, and continues counting.
	 * Modes 2 and 3 are periodic; the Counter reloads
	 * itself with the initial count and continues counting
	 * from there.
	 */
	remaining = hrtimer_get_remaining(&ps->pit_timer.timer);
	elapsed = ps->pit_timer.period - ktime_to_ns(remaining);
	elapsed = mod_64(elapsed, ps->pit_timer.period);

	return elapsed;
}

Project: linux
File: i8254.c

void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
{
	struct kvm_pit *pit = vcpu->kvm->arch.vpit;
	struct hrtimer *timer;

	if (!kvm_vcpu_is_bsp(vcpu) || !pit)
		return;

	timer = &pit->pit_state.pit_timer.timer;
	if (hrtimer_cancel(timer))
		hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
}

Project: linux
File: i8254.c

static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
{
	struct kvm_timer *pt = &ps->pit_timer;
	s64 interval;

	interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);

	pr_debug("create pit timer, interval is %llu nsec\n", interval);

	/* TODO The new value only affected after the retriggered */
	hrtimer_cancel(&pt->timer);
	pt->period = interval;
	ps->is_periodic = is_period;

	pt->timer.function = kvm_timer_fn;
	pt->t_ops = &kpit_ops;
	pt->kvm = ps->pit->kvm;
	pt->vcpu = pt->kvm->bsp_vcpu;

	atomic_set(&pt->pending, 0);
	ps->irq_ack = 1;

	hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval),
		      HRTIMER_MODE_ABS);
}

Project: linux
File: i8254.c

static void destroy_pit_timer(struct kvm_timer *pt)
{
	pr_debug("execute del timer!\n");
	hrtimer_cancel(&pt->timer);
}

Project: linux
File: i8254.c

static bool kpit_is_periodic(struct kvm_timer *ktimer)
{
	struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state,
						 pit_timer);
	return ps->is_periodic;
}

Project: linux
File: i8254.c

struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
{
	struct kvm_pit *pit;
	struct kvm_kpit_state *pit_state;
	int ret;

	pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
	if (!pit)
		return NULL;

	pit->irq_source_id = kvm_request_irq_source_id(kvm);
	if (pit->irq_source_id < 0) {
		kfree(pit);
		return NULL;
	}

	mutex_init(&pit->pit_state.lock);
	mutex_lock(&pit->pit_state.lock);
	spin_lock_init(&pit->pit_state.inject_lock);

	kvm->arch.vpit = pit;
	pit->kvm = kvm;

	pit_state = &pit->pit_state;
	pit_state->pit = pit;
	hrtimer_init(&pit_state->pit_timer.timer,
		     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	pit_state->irq_ack_notifier.gsi = 0;
	pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
	kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier);
	pit_state->pit_timer.reinject = true;
	mutex_unlock(&pit->pit_state.lock);

	kvm_pit_reset(pit);

	pit->mask_notifier.func = pit_mask_notifer;
	kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);

	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
	ret = __kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
	if (ret < 0)
		goto fail;

	if (flags & KVM_PIT_SPEAKER_DUMMY) {
		kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
		ret = __kvm_io_bus_register_dev(&kvm->pio_bus,
						&pit->speaker_dev);
		if (ret < 0)
			goto fail_unregister;
	}

	return pit;

fail_unregister:
	__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->dev);

fail:
	if (pit->irq_source_id >= 0)
		kvm_free_irq_source_id(kvm, pit->irq_source_id);

	kfree(pit);
	return NULL;
}

Project: linux
File: i8254.c

void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
{
	struct kvm_pit *pit = vcpu->kvm->arch.vpit;
	struct kvm *kvm = vcpu->kvm;
	struct kvm_kpit_state *ps;

	if (pit) {
		int inject = 0;
		ps = &pit->pit_state;

		/* Try to inject pending interrupts when
		 * last one has been acked.
		 */
		spin_lock(&ps->inject_lock);
		if (atomic_read(&ps->pit_timer.pending) && ps->irq_ack) {
			ps->irq_ack = 0;
			inject = 1;
		}
		spin_unlock(&ps->inject_lock);
		if (inject)
			__inject_pit_timer_intr(kvm);
	}
}

Project: linux
File: i8254.c

static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
{
	struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state,
						 irq_ack_notifier);
	spin_lock(&ps->inject_lock);
	if (atomic_dec_return(&ps->pit_timer.pending) < 0)
		atomic_inc(&ps->pit_timer.pending);
	ps->irq_ack = 1;
	spin_unlock(&ps->inject_lock);
}

Project: linux
File: i8254.c

void kvm_pit_reset(struct kvm_pit *pit)
{
	int i;
	struct kvm_kpit_channel_state *c;

	mutex_lock(&pit->pit_state.lock);
	pit->pit_state.flags = 0;
	for (i = 0; i < 3; i++) {
		c = &pit->pit_state.channels[i];
		c->mode = 0xff;
		c->gate = (i != 2);
		pit_load_count(pit->kvm, i, 0);
	}
	mutex_unlock(&pit->pit_state.lock);

	atomic_set(&pit->pit_state.pit_timer.pending, 0);
	pit->pit_state.irq_ack = 1;
}

Project: linux
File: i8254.c

int pit_has_pending_timer(struct kvm_vcpu *vcpu)
{
	struct kvm_pit *pit = vcpu->kvm->arch.vpit;

	if (pit && kvm_vcpu_is_bsp(vcpu) && pit->pit_state.irq_ack)
		return atomic_read(&pit->pit_state.pit_timer.pending);
	return 0;
}

Project: linux
File: i8254.c

static void pit_load_count(struct kvm *kvm, int channel, u32 val)
{
	struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;

	WARN_ON(!mutex_is_locked(&ps->lock));

	pr_debug("load_count val is %d, channel is %d\n", val, channel);

	/*
	 * The largest possible initial count is 0; this is equivalent
	 * to 216 for binary counting and 104 for BCD counting.
	 */
	if (val == 0)
		val = 0x10000;

	ps->channels[channel].count = val;

	if (channel != 0) {
		ps->channels[channel].count_load_time = ktime_get();
		return;
	}

	/* Two types of timer
	 * mode 1 is one shot, mode 2 is period, otherwise del timer */
	switch (ps->channels[0].mode) {
	case 0:
	case 1:
        /* FIXME: enhance mode 4 precision */
	case 4:
		if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)) {
			create_pit_timer(ps, val, 0);
		}
		break;
	case 2:
	case 3:
		if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)){
			create_pit_timer(ps, val, 1);
		}
		break;
	default:
		destroy_pit_timer(&ps->pit_timer);
	}
}

Project: linux
File: i8254.c

static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
{
	struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier);

	if (!mask) {
		atomic_set(&pit->pit_state.pit_timer.pending, 0);
		pit->pit_state.irq_ack = 1;
	}
}