Skip to content

Commit e1246f3

Browse files
author
Marc Zyngier
committed
KVM: arm64: vgic-v3: Consolidate userspace access for MMIO registers
For userspace accesses to GICv3 MMIO registers (and related data), vgic_v3_{get,set}_attr are littered with {get,put}_user() calls, making it hard to audit and reason about. Consolidate all userspace accesses in vgic_v3_attr_regs_access(), making the code far simpler to audit. Reviewed-by: Reiji Watanabe <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 38cf0bb commit e1246f3

File tree

1 file changed

+37
-66
lines changed

1 file changed

+37
-66
lines changed

arch/arm64/kvm/vgic/vgic-kvm-device.c

Lines changed: 37 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -512,18 +512,18 @@ int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
512512
*
513513
* @dev: kvm device handle
514514
* @attr: kvm device attribute
515-
* @reg: address the value is read or written, NULL for sysregs
516515
* @is_write: true if userspace is writing a register
517516
*/
518517
static int vgic_v3_attr_regs_access(struct kvm_device *dev,
519518
struct kvm_device_attr *attr,
520-
u64 *reg, bool is_write)
519+
bool is_write)
521520
{
522521
struct vgic_reg_attr reg_attr;
523522
gpa_t addr;
524523
struct kvm_vcpu *vcpu;
524+
bool uaccess;
525+
u32 val;
525526
int ret;
526-
u32 tmp32;
527527

528528
ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
529529
if (ret)
@@ -532,6 +532,21 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
532532
vcpu = reg_attr.vcpu;
533533
addr = reg_attr.addr;
534534

535+
switch (attr->group) {
536+
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
537+
/* Sysregs uaccess is performed by the sysreg handling code */
538+
uaccess = false;
539+
break;
540+
default:
541+
uaccess = true;
542+
}
543+
544+
if (uaccess && is_write) {
545+
u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
546+
if (get_user(val, uaddr))
547+
return -EFAULT;
548+
}
549+
535550
mutex_lock(&dev->kvm->lock);
536551

537552
if (unlikely(!vgic_initialized(dev->kvm))) {
@@ -546,20 +561,10 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
546561

547562
switch (attr->group) {
548563
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
549-
if (is_write)
550-
tmp32 = *reg;
551-
552-
ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
553-
if (!is_write)
554-
*reg = tmp32;
564+
ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &val);
555565
break;
556566
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
557-
if (is_write)
558-
tmp32 = *reg;
559-
560-
ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
561-
if (!is_write)
562-
*reg = tmp32;
567+
ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &val);
563568
break;
564569
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
565570
ret = vgic_v3_cpu_sysregs_uaccess(vcpu, attr, is_write);
@@ -570,14 +575,10 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
570575
info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
571576
KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
572577
if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
573-
if (is_write)
574-
tmp32 = *reg;
575578
intid = attr->attr &
576579
KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
577580
ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
578-
intid, &tmp32);
579-
if (!is_write)
580-
*reg = tmp32;
581+
intid, &val);
581582
} else {
582583
ret = -EINVAL;
583584
}
@@ -591,6 +592,12 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
591592
unlock_all_vcpus(dev->kvm);
592593
out:
593594
mutex_unlock(&dev->kvm->lock);
595+
596+
if (!ret && uaccess && !is_write) {
597+
u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
598+
ret = put_user(val, uaddr);
599+
}
600+
594601
return ret;
595602
}
596603

@@ -605,30 +612,12 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
605612

606613
switch (attr->group) {
607614
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
608-
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
609-
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
610-
u32 tmp32;
611-
u64 reg;
612-
613-
if (get_user(tmp32, uaddr))
614-
return -EFAULT;
615-
616-
reg = tmp32;
617-
return vgic_v3_attr_regs_access(dev, attr, &reg, true);
618-
}
615+
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
616+
return vgic_v3_attr_regs_access(dev, attr, true);
619617
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
620-
return vgic_v3_attr_regs_access(dev, attr, NULL, true);
621-
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
622-
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
623-
u64 reg;
624-
u32 tmp32;
625-
626-
if (get_user(tmp32, uaddr))
627-
return -EFAULT;
628-
629-
reg = tmp32;
630-
return vgic_v3_attr_regs_access(dev, attr, &reg, true);
631-
}
618+
return vgic_v3_attr_regs_access(dev, attr, true);
619+
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
620+
return vgic_v3_attr_regs_access(dev, attr, true);
632621
case KVM_DEV_ARM_VGIC_GRP_CTRL: {
633622
int ret;
634623

@@ -662,30 +651,12 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
662651

663652
switch (attr->group) {
664653
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
665-
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
666-
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
667-
u64 reg;
668-
u32 tmp32;
669-
670-
ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
671-
if (ret)
672-
return ret;
673-
tmp32 = reg;
674-
return put_user(tmp32, uaddr);
675-
}
654+
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
655+
return vgic_v3_attr_regs_access(dev, attr, false);
676656
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
677-
return vgic_v3_attr_regs_access(dev, attr, NULL, false);
678-
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
679-
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
680-
u64 reg;
681-
u32 tmp32;
682-
683-
ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
684-
if (ret)
685-
return ret;
686-
tmp32 = reg;
687-
return put_user(tmp32, uaddr);
688-
}
657+
return vgic_v3_attr_regs_access(dev, attr, false);
658+
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
659+
return vgic_v3_attr_regs_access(dev, attr, false);
689660
}
690661
return -ENXIO;
691662
}

0 commit comments

Comments
 (0)