Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: Check privilege level on SPRs

We have 3 privilege levels: problem state, supervisor state and hypervisor
state. Each of them can access different SPRs, so we need to check on every
SPR if it's accessible in the respective mode.

Signed-off-by: Alexander Graf <agraf@suse.de>

authored by

Alexander Graf and committed by
Avi Kivity
317a8fa3 9432ba60

+25
+25
arch/powerpc/kvm/book3s_emulate.c
··· 63 63 * function pointers, so let's just disable the define. */ 64 64 #undef mfsrin 65 65 66 + enum priv_level { 67 + PRIV_PROBLEM = 0, 68 + PRIV_SUPER = 1, 69 + PRIV_HYPER = 2, 70 + }; 71 + 72 + static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level) 73 + { 74 + /* PAPR VMs only access supervisor SPRs */ 75 + if (vcpu->arch.papr_enabled && (level > PRIV_SUPER)) 76 + return false; 77 + 78 + /* Limit user space to its own small SPR set */ 79 + if ((vcpu->arch.shared->msr & MSR_PR) && level > PRIV_PROBLEM) 80 + return false; 81 + 82 + return true; 83 + } 84 + 66 85 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, 67 86 unsigned int inst, int *advance) 68 87 { ··· 315 296 316 297 switch (sprn) { 317 298 case SPRN_SDR1: 299 + if (!spr_allowed(vcpu, PRIV_HYPER)) 300 + goto unprivileged; 318 301 to_book3s(vcpu)->sdr1 = spr_val; 319 302 break; 320 303 case SPRN_DSISR: ··· 411 390 case SPRN_PMC4_GEKKO: 412 391 case SPRN_WPAR_GEKKO: 413 392 break; 393 + unprivileged: 414 394 default: 415 395 printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn); 416 396 #ifndef DEBUG_SPR ··· 443 421 break; 444 422 } 445 423 case SPRN_SDR1: 424 + if (!spr_allowed(vcpu, PRIV_HYPER)) 425 + goto unprivileged; 446 426 kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1); 447 427 break; 448 428 case SPRN_DSISR: ··· 500 476 kvmppc_set_gpr(vcpu, rt, 0); 501 477 break; 502 478 default: 479 + unprivileged: 503 480 printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn); 504 481 #ifndef DEBUG_SPR 505 482 emulated = EMULATE_FAIL;