diff options
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index f5704d9e5ddc..813d31038b93 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -3601,20 +3601,27 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu, | |||
3601 | } | 3601 | } |
3602 | } | 3602 | } |
3603 | 3603 | ||
3604 | static void update_permission_bitmask(struct kvm_vcpu *vcpu, | 3604 | void update_permission_bitmask(struct kvm_vcpu *vcpu, |
3605 | struct kvm_mmu *mmu, bool ept) | 3605 | struct kvm_mmu *mmu, bool ept) |
3606 | { | 3606 | { |
3607 | unsigned bit, byte, pfec; | 3607 | unsigned bit, byte, pfec; |
3608 | u8 map; | 3608 | u8 map; |
3609 | bool fault, x, w, u, wf, uf, ff, smep; | 3609 | bool fault, x, w, u, wf, uf, ff, smapf, cr4_smap, cr4_smep, smap = 0; |
3610 | 3610 | ||
3611 | smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); | 3611 | cr4_smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); |
3612 | cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP); | ||
3612 | for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) { | 3613 | for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) { |
3613 | pfec = byte << 1; | 3614 | pfec = byte << 1; |
3614 | map = 0; | 3615 | map = 0; |
3615 | wf = pfec & PFERR_WRITE_MASK; | 3616 | wf = pfec & PFERR_WRITE_MASK; |
3616 | uf = pfec & PFERR_USER_MASK; | 3617 | uf = pfec & PFERR_USER_MASK; |
3617 | ff = pfec & PFERR_FETCH_MASK; | 3618 | ff = pfec & PFERR_FETCH_MASK; |
3619 | /* | ||
3620 | * PFERR_RSVD_MASK bit is set in PFEC if the access is not | ||
3621 | * subject to SMAP restrictions, and cleared otherwise. The | ||
3622 | * bit is only meaningful if the SMAP bit is set in CR4. | ||
3623 | */ | ||
3624 | smapf = !(pfec & PFERR_RSVD_MASK); | ||
3618 | for (bit = 0; bit < 8; ++bit) { | 3625 | for (bit = 0; bit < 8; ++bit) { |
3619 | x = bit & ACC_EXEC_MASK; | 3626 | x = bit & ACC_EXEC_MASK; |
3620 | w = bit & ACC_WRITE_MASK; | 3627 | w = bit & ACC_WRITE_MASK; |
@@ -3626,12 +3633,33 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu, | |||
3626 | /* Allow supervisor writes if !cr0.wp */ | 3633 | /* Allow supervisor writes if !cr0.wp */ |
3627 | w |= !is_write_protection(vcpu) && !uf; | 3634 | w |= !is_write_protection(vcpu) && !uf; |
3628 | /* Disallow supervisor fetches of user code if cr4.smep */ | 3635 | /* Disallow supervisor fetches of user code if cr4.smep */ |
3629 | x &= !(smep && u && !uf); | 3636 | x &= !(cr4_smep && u && !uf); |
3637 | |||
3638 | /* | ||
3639 | * SMAP:kernel-mode data accesses from user-mode | ||
3640 | * mappings should fault. A fault is considered | ||
3641 | * as a SMAP violation if all of the following | ||
3642 | * conditions are ture: | ||
3643 | * - X86_CR4_SMAP is set in CR4 | ||
3644 | * - An user page is accessed | ||
3645 | * - Page fault in kernel mode | ||
3646 | * - if CPL = 3 or X86_EFLAGS_AC is clear | ||
3647 | * | ||
3648 | * Here, we cover the first three conditions. | ||
3649 | * The fourth is computed dynamically in | ||
3650 | * permission_fault() and is in smapf. | ||
3651 | * | ||
3652 | * Also, SMAP does not affect instruction | ||
3653 | * fetches, add the !ff check here to make it | ||
3654 | * clearer. | ||
3655 | */ | ||
3656 | smap = cr4_smap && u && !uf && !ff; | ||
3630 | } else | 3657 | } else |
3631 | /* Not really needed: no U/S accesses on ept */ | 3658 | /* Not really needed: no U/S accesses on ept */ |
3632 | u = 1; | 3659 | u = 1; |
3633 | 3660 | ||
3634 | fault = (ff && !x) || (uf && !u) || (wf && !w); | 3661 | fault = (ff && !x) || (uf && !u) || (wf && !w) || |
3662 | (smapf && smap); | ||
3635 | map |= fault << bit; | 3663 | map |= fault << bit; |
3636 | } | 3664 | } |
3637 | mmu->permissions[byte] = map; | 3665 | mmu->permissions[byte] = map; |