#include <stdint.h>
+/* Global flag set by hal_cpu_detect_features() when SMAP is enabled in CR4. */
+extern int g_smap_enabled;
+
+/* STAC/CLAC — toggle EFLAGS.AC for SMAP bypass.
+ * Encoded as raw bytes for compatibility with older assemblers.
+ * Only executed when SMAP is actually enabled to avoid #UD. */
+static inline void stac(void) {
+ if (g_smap_enabled)
+ __asm__ volatile(".byte 0x0F, 0x01, 0xCB" ::: "memory");
+}
+static inline void clac(void) {
+ if (g_smap_enabled)
+ __asm__ volatile(".byte 0x0F, 0x01, 0xCA" ::: "memory");
+}
+
static int x86_user_range_basic_ok(uintptr_t uaddr, size_t len) {
if (len == 0) return 1;
if (uaddr == 0) return 0;
g_uaccess_recover_eip = (uintptr_t)&&uaccess_fault;
g_uaccess_active = 1;
+ stac();
uintptr_t up = (uintptr_t)src_user;
for (size_t i = 0; i < len; i++) {
((uint8_t*)dst)[i] = ((const volatile uint8_t*)up)[i];
}
+ clac();
g_uaccess_active = 0;
g_uaccess_recover_eip = 0;
return 0;
uaccess_fault:
+ clac();
g_uaccess_active = 0;
g_uaccess_faulted = 0;
g_uaccess_recover_eip = 0;
g_uaccess_recover_eip = (uintptr_t)&&uaccess_fault2;
g_uaccess_active = 1;
+ stac();
uintptr_t up = (uintptr_t)dst_user;
for (size_t i = 0; i < len; i++) {
((volatile uint8_t*)up)[i] = ((const uint8_t*)src)[i];
}
+ clac();
g_uaccess_active = 0;
g_uaccess_recover_eip = 0;
return 0;
uaccess_fault2:
+ clac();
g_uaccess_active = 0;
g_uaccess_faulted = 0;
g_uaccess_recover_eip = 0;
__asm__ volatile("mov %0, %%cr4" :: "r"(val) : "memory");
}
+int g_smap_enabled = 0;
+
static struct cpu_features g_features;
static struct x86_cpu_features g_x86_features;
kprintf("[CPU] SMEP enabled.\n");
}
- /* SMAP (Supervisor Mode Access Prevention) is NOT enabled yet because
- * copy_from_user/copy_to_user do not bracket accesses with STAC/CLAC.
- * Enabling SMAP without STAC/CLAC would fault on every user memory access.
- * TODO: Add STAC/CLAC to x86 uaccess.c, then enable SMAP here. */
+ /* Enable SMAP if supported: prevents kernel from accidentally reading/writing
+ * user-mapped pages. copy_from_user/copy_to_user bracket accesses with
+ * STAC/CLAC so legitimate user copies still work. */
+ if (g_x86_features.smap) {
+ uint32_t cr4 = read_cr4();
+ cr4 |= CR4_SMAP;
+ write_cr4(cr4);
+ g_smap_enabled = 1;
+ kprintf("[CPU] SMAP enabled.\n");
+ }
}
const struct cpu_features* hal_cpu_get_features(void) {