0001
0002
0003
0004
0005 #include <linux/sched.h>
0006 #include <linux/sched/task_stack.h>
0007 #include <linux/mm.h>
0008 #include <linux/ptrace.h>
0009 #include <asm/desc.h>
0010 #include <asm/mmu_context.h>
0011
0012 unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs)
0013 {
0014 unsigned long addr, seg;
0015
0016 addr = regs->ip;
0017 seg = regs->cs;
0018 if (v8086_mode(regs)) {
0019 addr = (addr & 0xffff) + (seg << 4);
0020 return addr;
0021 }
0022
0023 #ifdef CONFIG_MODIFY_LDT_SYSCALL
0024
0025
0026
0027
0028
0029
0030 if ((seg & SEGMENT_TI_MASK) == SEGMENT_LDT) {
0031 struct desc_struct *desc;
0032 unsigned long base;
0033
0034 seg >>= 3;
0035
0036 mutex_lock(&child->mm->context.lock);
0037 if (unlikely(!child->mm->context.ldt ||
0038 seg >= child->mm->context.ldt->nr_entries))
0039 addr = -1L;
0040 else {
0041 desc = &child->mm->context.ldt->entries[seg];
0042 base = get_desc_base(desc);
0043
0044
0045 if (!desc->d)
0046 addr &= 0xffff;
0047 addr += base;
0048 }
0049 mutex_unlock(&child->mm->context.lock);
0050 }
0051 #endif
0052
0053 return addr;
0054 }
0055
0056 static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
0057 {
0058 int i, copied;
0059 unsigned char opcode[15];
0060 unsigned long addr = convert_ip_to_linear(child, regs);
0061
0062 copied = access_process_vm(child, addr, opcode, sizeof(opcode),
0063 FOLL_FORCE);
0064 for (i = 0; i < copied; i++) {
0065 switch (opcode[i]) {
0066
0067 case 0x9d: case 0xcf:
0068 return 1;
0069
0070
0071
0072
0073 case 0x66: case 0x67:
0074 continue;
0075
0076 case 0x26: case 0x2e:
0077 case 0x36: case 0x3e:
0078 case 0x64: case 0x65:
0079 case 0xf0: case 0xf2: case 0xf3:
0080 continue;
0081
0082 #ifdef CONFIG_X86_64
0083 case 0x40 ... 0x4f:
0084 if (!user_64bit_mode(regs))
0085
0086 return 0;
0087
0088 continue;
0089 #endif
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 case 0x9c:
0101 default:
0102 return 0;
0103 }
0104 }
0105 return 0;
0106 }
0107
0108
0109
0110
0111 static int enable_single_step(struct task_struct *child)
0112 {
0113 struct pt_regs *regs = task_pt_regs(child);
0114 unsigned long oflags;
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 if (unlikely(test_tsk_thread_flag(child, TIF_SINGLESTEP)))
0127 regs->flags |= X86_EFLAGS_TF;
0128
0129
0130
0131
0132
0133 set_tsk_thread_flag(child, TIF_SINGLESTEP);
0134
0135
0136
0137
0138
0139 set_task_syscall_work(child, SYSCALL_EXIT_TRAP);
0140
0141 oflags = regs->flags;
0142
0143
0144 regs->flags |= X86_EFLAGS_TF;
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 if (is_setting_trap_flag(child, regs)) {
0156 clear_tsk_thread_flag(child, TIF_FORCED_TF);
0157 return 0;
0158 }
0159
0160
0161
0162
0163
0164 if (oflags & X86_EFLAGS_TF)
0165 return test_tsk_thread_flag(child, TIF_FORCED_TF);
0166
0167 set_tsk_thread_flag(child, TIF_FORCED_TF);
0168
0169 return 1;
0170 }
0171
0172 void set_task_blockstep(struct task_struct *task, bool on)
0173 {
0174 unsigned long debugctl;
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 local_irq_disable();
0186 debugctl = get_debugctlmsr();
0187 if (on) {
0188 debugctl |= DEBUGCTLMSR_BTF;
0189 set_tsk_thread_flag(task, TIF_BLOCKSTEP);
0190 } else {
0191 debugctl &= ~DEBUGCTLMSR_BTF;
0192 clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
0193 }
0194 if (task == current)
0195 update_debugctlmsr(debugctl);
0196 local_irq_enable();
0197 }
0198
0199
0200
0201
0202 static void enable_step(struct task_struct *child, bool block)
0203 {
0204
0205
0206
0207
0208
0209
0210
0211 if (enable_single_step(child) && block)
0212 set_task_blockstep(child, true);
0213 else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
0214 set_task_blockstep(child, false);
0215 }
0216
0217 void user_enable_single_step(struct task_struct *child)
0218 {
0219 enable_step(child, 0);
0220 }
0221
0222 void user_enable_block_step(struct task_struct *child)
0223 {
0224 enable_step(child, 1);
0225 }
0226
0227 void user_disable_single_step(struct task_struct *child)
0228 {
0229
0230
0231
0232 if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
0233 set_task_blockstep(child, false);
0234
0235
0236 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
0237 clear_task_syscall_work(child, SYSCALL_EXIT_TRAP);
0238
0239
0240 if (test_and_clear_tsk_thread_flag(child, TIF_FORCED_TF))
0241 task_pt_regs(child)->flags &= ~X86_EFLAGS_TF;
0242 }