diff options
-rw-r--r-- | arch/x86/kernel/umip.c | 62 |
1 files changed, 58 insertions, 4 deletions
diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c index 1f1f2d54dab5..dabbac30acdf 100644 --- a/arch/x86/kernel/umip.c +++ b/arch/x86/kernel/umip.c | |||
@@ -82,6 +82,57 @@ | |||
82 | #define UMIP_INST_SLDT 3 /* 0F 00 /0 */ | 82 | #define UMIP_INST_SLDT 3 /* 0F 00 /0 */ |
83 | #define UMIP_INST_STR 4 /* 0F 00 /1 */ | 83 | #define UMIP_INST_STR 4 /* 0F 00 /1 */ |
84 | 84 | ||
85 | const char * const umip_insns[5] = { | ||
86 | [UMIP_INST_SGDT] = "SGDT", | ||
87 | [UMIP_INST_SIDT] = "SIDT", | ||
88 | [UMIP_INST_SMSW] = "SMSW", | ||
89 | [UMIP_INST_SLDT] = "SLDT", | ||
90 | [UMIP_INST_STR] = "STR", | ||
91 | }; | ||
92 | |||
93 | #define umip_pr_err(regs, fmt, ...) \ | ||
94 | umip_printk(regs, KERN_ERR, fmt, ##__VA_ARGS__) | ||
95 | #define umip_pr_warning(regs, fmt, ...) \ | ||
96 | umip_printk(regs, KERN_WARNING, fmt, ##__VA_ARGS__) | ||
97 | |||
98 | /** | ||
99 | * umip_printk() - Print a rate-limited message | ||
100 | * @regs: Register set with the context in which the warning is printed | ||
101 | * @log_level: Kernel log level to print the message | ||
102 | * @fmt: The text string to print | ||
103 | * | ||
104 | * Print the text contained in @fmt. The print rate is limited to bursts of 5 | ||
105 | * messages every two minutes. The purpose of this customized version of | ||
106 | * printk() is to print messages when user space processes use any of the | ||
107 | * UMIP-protected instructions. Thus, the printed text is prepended with the | ||
108 | * task name and process ID number of the current task as well as the | ||
109 | * instruction and stack pointers in @regs as seen when entering kernel mode. | ||
110 | * | ||
111 | * Returns: | ||
112 | * | ||
113 | * None. | ||
114 | */ | ||
115 | static __printf(3, 4) | ||
116 | void umip_printk(const struct pt_regs *regs, const char *log_level, | ||
117 | const char *fmt, ...) | ||
118 | { | ||
119 | /* Bursts of 5 messages every two minutes */ | ||
120 | static DEFINE_RATELIMIT_STATE(ratelimit, 2 * 60 * HZ, 5); | ||
121 | struct task_struct *tsk = current; | ||
122 | struct va_format vaf; | ||
123 | va_list args; | ||
124 | |||
125 | if (!__ratelimit(&ratelimit)) | ||
126 | return; | ||
127 | |||
128 | va_start(args, fmt); | ||
129 | vaf.fmt = fmt; | ||
130 | vaf.va = &args; | ||
131 | printk("%s" pr_fmt("%s[%d] ip:%lx sp:%lx: %pV"), log_level, tsk->comm, | ||
132 | task_pid_nr(tsk), regs->ip, regs->sp, &vaf); | ||
133 | va_end(args); | ||
134 | } | ||
135 | |||
85 | /** | 136 | /** |
86 | * identify_insn() - Identify a UMIP-protected instruction | 137 | * identify_insn() - Identify a UMIP-protected instruction |
87 | * @insn: Instruction structure with opcode and ModRM byte. | 138 | * @insn: Instruction structure with opcode and ModRM byte. |
@@ -236,10 +287,8 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs) | |||
236 | if (!(show_unhandled_signals && unhandled_signal(tsk, SIGSEGV))) | 287 | if (!(show_unhandled_signals && unhandled_signal(tsk, SIGSEGV))) |
237 | return; | 288 | return; |
238 | 289 | ||
239 | pr_err_ratelimited("%s[%d] umip emulation segfault ip:%lx sp:%lx error:%x in %lx\n", | 290 | umip_pr_err(regs, "segfault in emulation. error%x\n", |
240 | tsk->comm, task_pid_nr(tsk), regs->ip, | 291 | X86_PF_USER | X86_PF_WRITE); |
241 | regs->sp, X86_PF_USER | X86_PF_WRITE, | ||
242 | regs->ip); | ||
243 | } | 292 | } |
244 | 293 | ||
245 | /** | 294 | /** |
@@ -326,10 +375,15 @@ bool fixup_umip_exception(struct pt_regs *regs) | |||
326 | if (umip_inst < 0) | 375 | if (umip_inst < 0) |
327 | return false; | 376 | return false; |
328 | 377 | ||
378 | umip_pr_warning(regs, "%s instruction cannot be used by applications.\n", | ||
379 | umip_insns[umip_inst]); | ||
380 | |||
329 | /* Do not emulate SLDT, STR or user long mode processes. */ | 381 | /* Do not emulate SLDT, STR or user long mode processes. */ |
330 | if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT || user_64bit_mode(regs)) | 382 | if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT || user_64bit_mode(regs)) |
331 | return false; | 383 | return false; |
332 | 384 | ||
385 | umip_pr_warning(regs, "For now, expensive software emulation returns the result.\n"); | ||
386 | |||
333 | if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size)) | 387 | if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size)) |
334 | return false; | 388 | return false; |
335 | 389 | ||