// 用于手动调用系统调用的包装函数 (如果需要) // #include <sys/syscall.h> // static inline int my_pkey_alloc(unsigned int flags, unsigned int access_rights) { // return syscall(SYS_pkey_alloc, flags, access_rights); // } // static inline int my_pkey_free(int pkey) { // return syscall(SYS_pkey_free, pkey); // }
// 检查系统是否支持内存保护键 int check_pkey_support() { int pkey; // 尝试分配一个 pkey 来检查支持 pkey = pkey_alloc(0, 0); if (pkey == -1) { if (errno == EOPNOTSUPP) { return 0; // Not supported } else { // Other error, but might still support it in general // Let's assume it does and let the main code handle specific errors return 1; } } // Allocation succeeded, support confirmed. Free it. if (pkey_free(pkey) == -1) { perror("pkey_free after check"); } return 1; }
int main() { printf("Checking for Memory Protection Key (MPK) support...\n");
if (!check_pkey_support()) { fprintf(stderr, "Memory Protection Keys (MPK) are NOT supported on this system/CPU.\n"); fprintf(stderr, "This might be because:\n"); fprintf(stderr, " 1. The CPU does not support MPK (e.g., older than Intel Skylake).\n"); fprintf(stderr, " 2. The Linux kernel version is older than 4.9.\n"); fprintf(stderr, " 3. The feature is disabled.\n"); exit(EXIT_FAILURE); }
// 概念性的 PKRU 操作函数 (实际需要内联汇编) // 这里用伪代码表示 void write_pkru(unsigned int pkru_value) { // In real code, this would be inline assembly like: // asm volatile(".byte 0x0f,0x01,0xef\n\t" : : "a" (pkru_value), "d" (0), "c" (0) : "memory"); printf(" [Concept] Writing PKRU with value: 0x%08x\n", pkru_value); // WARNING: This is NOT real code, just for illustration. // Real code needs inline assembly. }
unsigned int read_pkru() { // In real code: // unsigned int pkru; // asm volatile(".byte 0x0f,0x01,0xee\n\t" : "=a" (pkru) : "c" (0) : "rdx", "memory"); // return pkru; printf(" [Concept] Reading PKRU\n"); return 0; // Dummy return }
int main() { if (sysconf(_SC_MPKEY) <= 0) { // Check if supported fprintf(stderr, "MPK not supported by sysconf.\n"); exit(EXIT_FAILURE); }
if (setjmp(jmp_env) == 0) { // This block will be executed first printf(" Trying to read from %p...\n", addr); char first_char = *((char*)addr); // This should trigger SIGSEGV printf(" ERROR: Read succeeded (first char: %c). This should not happen!\n", first_char); } else { // This block will be executed if longjmp is called from signal handler if (sigsegv_caught) { printf(" SUCCESS: SIGSEGV caught as expected. Access denied by pkey.\n"); } else { printf(" Unexpected longjmp.\n"); } }
// 7. 重新允许访问 printf("\n--- Re-enabling access to pkey %d via PKRU ---\n", pkey); // write_pkru(0); // Allow all access again printf(" [Concept] Would reset PKRU to allow all access.\n");
// 8. 再次尝试访问 (应该成功) printf("\n--- Attempting to access memory again (should succeed now) ---\n"); printf(" Reading from %p: %s\n", addr, (char*)addr);
// 9. 清理 if (pkey_free(pkey) == -1) { perror("pkey_free"); } if (munmap(addr, len) == -1) { perror("munmap"); }
printf("\nConceptual pkey example finished.\n"); return 0; }