|
@@ -4204,66 +4204,85 @@ reset_ept_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
|
|
|
boot_cpu_data.x86_phys_bits, execonly);
|
|
|
}
|
|
|
|
|
|
+#define BYTE_MASK(access) \
|
|
|
+ ((1 & (access) ? 2 : 0) | \
|
|
|
+ (2 & (access) ? 4 : 0) | \
|
|
|
+ (3 & (access) ? 8 : 0) | \
|
|
|
+ (4 & (access) ? 16 : 0) | \
|
|
|
+ (5 & (access) ? 32 : 0) | \
|
|
|
+ (6 & (access) ? 64 : 0) | \
|
|
|
+ (7 & (access) ? 128 : 0))
|
|
|
+
|
|
|
+
|
|
|
static void update_permission_bitmask(struct kvm_vcpu *vcpu,
|
|
|
struct kvm_mmu *mmu, bool ept)
|
|
|
{
|
|
|
- unsigned bit, byte, pfec;
|
|
|
- u8 map;
|
|
|
- bool fault, x, w, u, wf, uf, ff, smapf, cr4_smap, cr4_smep, smap = 0;
|
|
|
+ unsigned byte;
|
|
|
+
|
|
|
+ const u8 x = BYTE_MASK(ACC_EXEC_MASK);
|
|
|
+ const u8 w = BYTE_MASK(ACC_WRITE_MASK);
|
|
|
+ const u8 u = BYTE_MASK(ACC_USER_MASK);
|
|
|
+
|
|
|
+ bool cr4_smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP) != 0;
|
|
|
+ bool cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP) != 0;
|
|
|
+ bool cr0_wp = is_write_protection(vcpu);
|
|
|
|
|
|
- cr4_smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
|
|
|
- cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
|
|
|
for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
|
|
|
- pfec = byte << 1;
|
|
|
- map = 0;
|
|
|
- wf = pfec & PFERR_WRITE_MASK;
|
|
|
- uf = pfec & PFERR_USER_MASK;
|
|
|
- ff = pfec & PFERR_FETCH_MASK;
|
|
|
+ unsigned pfec = byte << 1;
|
|
|
+
|
|
|
/*
|
|
|
- * PFERR_RSVD_MASK bit is set in PFEC if the access is not
|
|
|
- * subject to SMAP restrictions, and cleared otherwise. The
|
|
|
- * bit is only meaningful if the SMAP bit is set in CR4.
|
|
|
+ * Each "*f" variable has a 1 bit for each UWX value
|
|
|
+ * that causes a fault with the given PFEC.
|
|
|
*/
|
|
|
- smapf = !(pfec & PFERR_RSVD_MASK);
|
|
|
- for (bit = 0; bit < 8; ++bit) {
|
|
|
- x = bit & ACC_EXEC_MASK;
|
|
|
- w = bit & ACC_WRITE_MASK;
|
|
|
- u = bit & ACC_USER_MASK;
|
|
|
-
|
|
|
- if (!ept) {
|
|
|
- /* Not really needed: !nx will cause pte.nx to fault */
|
|
|
- x |= !mmu->nx;
|
|
|
- /* Allow supervisor writes if !cr0.wp */
|
|
|
- w |= !is_write_protection(vcpu) && !uf;
|
|
|
- /* Disallow supervisor fetches of user code if cr4.smep */
|
|
|
- x &= !(cr4_smep && u && !uf);
|
|
|
-
|
|
|
- /*
|
|
|
- * SMAP:kernel-mode data accesses from user-mode
|
|
|
- * mappings should fault. A fault is considered
|
|
|
- * as a SMAP violation if all of the following
|
|
|
- * conditions are ture:
|
|
|
- * - X86_CR4_SMAP is set in CR4
|
|
|
- * - A user page is accessed
|
|
|
- * - Page fault in kernel mode
|
|
|
- * - if CPL = 3 or X86_EFLAGS_AC is clear
|
|
|
- *
|
|
|
- * Here, we cover the first three conditions.
|
|
|
- * The fourth is computed dynamically in
|
|
|
- * permission_fault() and is in smapf.
|
|
|
- *
|
|
|
- * Also, SMAP does not affect instruction
|
|
|
- * fetches, add the !ff check here to make it
|
|
|
- * clearer.
|
|
|
- */
|
|
|
- smap = cr4_smap && u && !uf && !ff;
|
|
|
- }
|
|
|
|
|
|
- fault = (ff && !x) || (uf && !u) || (wf && !w) ||
|
|
|
- (smapf && smap);
|
|
|
- map |= fault << bit;
|
|
|
+ /* Faults from writes to non-writable pages */
|
|
|
+ u8 wf = (pfec & PFERR_WRITE_MASK) ? ~w : 0;
|
|
|
+ /* Faults from user mode accesses to supervisor pages */
|
|
|
+ u8 uf = (pfec & PFERR_USER_MASK) ? ~u : 0;
|
|
|
+ /* Faults from fetches of non-executable pages*/
|
|
|
+ u8 ff = (pfec & PFERR_FETCH_MASK) ? ~x : 0;
|
|
|
+ /* Faults from kernel mode fetches of user pages */
|
|
|
+ u8 smepf = 0;
|
|
|
+ /* Faults from kernel mode accesses of user pages */
|
|
|
+ u8 smapf = 0;
|
|
|
+
|
|
|
+ if (!ept) {
|
|
|
+ /* Faults from kernel mode accesses to user pages */
|
|
|
+ u8 kf = (pfec & PFERR_USER_MASK) ? 0 : u;
|
|
|
+
|
|
|
+ /* Not really needed: !nx will cause pte.nx to fault */
|
|
|
+ if (!mmu->nx)
|
|
|
+ ff = 0;
|
|
|
+
|
|
|
+ /* Allow supervisor writes if !cr0.wp */
|
|
|
+ if (!cr0_wp)
|
|
|
+ wf = (pfec & PFERR_USER_MASK) ? wf : 0;
|
|
|
+
|
|
|
+ /* Disallow supervisor fetches of user code if cr4.smep */
|
|
|
+ if (cr4_smep)
|
|
|
+ smepf = (pfec & PFERR_FETCH_MASK) ? kf : 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * SMAP:kernel-mode data accesses from user-mode
|
|
|
+ * mappings should fault. A fault is considered
|
|
|
+ * as a SMAP violation if all of the following
|
|
|
+ * conditions are ture:
|
|
|
+ * - X86_CR4_SMAP is set in CR4
|
|
|
+ * - A user page is accessed
|
|
|
+ * - The access is not a fetch
|
|
|
+ * - Page fault in kernel mode
|
|
|
+ * - if CPL = 3 or X86_EFLAGS_AC is clear
|
|
|
+ *
|
|
|
+ * Here, we cover the first three conditions.
|
|
|
+ * The fourth is computed dynamically in permission_fault();
|
|
|
+ * PFERR_RSVD_MASK bit will be set in PFEC if the access is
|
|
|
+ * *not* subject to SMAP restrictions.
|
|
|
+ */
|
|
|
+ if (cr4_smap)
|
|
|
+ smapf = (pfec & (PFERR_RSVD_MASK|PFERR_FETCH_MASK)) ? 0 : kf;
|
|
|
}
|
|
|
- mmu->permissions[byte] = map;
|
|
|
+
|
|
|
+ mmu->permissions[byte] = ff | uf | wf | smepf | smapf;
|
|
|
}
|
|
|
}
|
|
|
|