| .. | .. |
|---|
| 12 | 12 | * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> |
|---|
| 13 | 13 | */ |
|---|
| 14 | 14 | |
|---|
| 15 | +#include <linux/audit.h> |
|---|
| 15 | 16 | #include <linux/errno.h> |
|---|
| 16 | 17 | #include <linux/hw_breakpoint.h> |
|---|
| 17 | 18 | #include <linux/kernel.h> |
|---|
| 18 | 19 | #include <linux/mm.h> |
|---|
| 19 | 20 | #include <linux/perf_event.h> |
|---|
| 20 | 21 | #include <linux/ptrace.h> |
|---|
| 22 | +#include <linux/regset.h> |
|---|
| 21 | 23 | #include <linux/sched.h> |
|---|
| 22 | 24 | #include <linux/sched/task_stack.h> |
|---|
| 25 | +#include <linux/seccomp.h> |
|---|
| 23 | 26 | #include <linux/security.h> |
|---|
| 24 | 27 | #include <linux/signal.h> |
|---|
| 25 | 28 | #include <linux/smp.h> |
|---|
| 26 | 29 | #include <linux/tracehook.h> |
|---|
| 27 | 30 | #include <linux/uaccess.h> |
|---|
| 28 | 31 | |
|---|
| 32 | +#define CREATE_TRACE_POINTS |
|---|
| 33 | +#include <trace/events/syscalls.h> |
|---|
| 34 | + |
|---|
| 29 | 35 | #include <asm/coprocessor.h> |
|---|
| 30 | 36 | #include <asm/elf.h> |
|---|
| 31 | 37 | #include <asm/page.h> |
|---|
| 32 | | -#include <asm/pgtable.h> |
|---|
| 33 | 38 | #include <asm/ptrace.h> |
|---|
| 34 | 39 | |
|---|
| 40 | +static int gpr_get(struct task_struct *target, |
|---|
| 41 | + const struct user_regset *regset, |
|---|
| 42 | + struct membuf to) |
|---|
| 43 | +{ |
|---|
| 44 | + struct pt_regs *regs = task_pt_regs(target); |
|---|
| 45 | + struct user_pt_regs newregs = { |
|---|
| 46 | + .pc = regs->pc, |
|---|
| 47 | + .ps = regs->ps & ~(1 << PS_EXCM_BIT), |
|---|
| 48 | + .lbeg = regs->lbeg, |
|---|
| 49 | + .lend = regs->lend, |
|---|
| 50 | + .lcount = regs->lcount, |
|---|
| 51 | + .sar = regs->sar, |
|---|
| 52 | + .threadptr = regs->threadptr, |
|---|
| 53 | + .windowbase = regs->windowbase, |
|---|
| 54 | + .windowstart = regs->windowstart, |
|---|
| 55 | + .syscall = regs->syscall, |
|---|
| 56 | + }; |
|---|
| 57 | + |
|---|
| 58 | + memcpy(newregs.a, |
|---|
| 59 | + regs->areg + XCHAL_NUM_AREGS - regs->windowbase * 4, |
|---|
| 60 | + regs->windowbase * 16); |
|---|
| 61 | + memcpy(newregs.a + regs->windowbase * 4, |
|---|
| 62 | + regs->areg, |
|---|
| 63 | + (WSBITS - regs->windowbase) * 16); |
|---|
| 64 | + |
|---|
| 65 | + return membuf_write(&to, &newregs, sizeof(newregs)); |
|---|
| 66 | +} |
|---|
| 67 | + |
|---|
| 68 | +static int gpr_set(struct task_struct *target, |
|---|
| 69 | + const struct user_regset *regset, |
|---|
| 70 | + unsigned int pos, unsigned int count, |
|---|
| 71 | + const void *kbuf, const void __user *ubuf) |
|---|
| 72 | +{ |
|---|
| 73 | + int ret; |
|---|
| 74 | + struct user_pt_regs newregs = {0}; |
|---|
| 75 | + struct pt_regs *regs; |
|---|
| 76 | + const u32 ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; |
|---|
| 77 | + |
|---|
| 78 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1); |
|---|
| 79 | + if (ret) |
|---|
| 80 | + return ret; |
|---|
| 81 | + |
|---|
| 82 | + if (newregs.windowbase >= XCHAL_NUM_AREGS / 4) |
|---|
| 83 | + return -EINVAL; |
|---|
| 84 | + |
|---|
| 85 | + regs = task_pt_regs(target); |
|---|
| 86 | + regs->pc = newregs.pc; |
|---|
| 87 | + regs->ps = (regs->ps & ~ps_mask) | (newregs.ps & ps_mask); |
|---|
| 88 | + regs->lbeg = newregs.lbeg; |
|---|
| 89 | + regs->lend = newregs.lend; |
|---|
| 90 | + regs->lcount = newregs.lcount; |
|---|
| 91 | + regs->sar = newregs.sar; |
|---|
| 92 | + regs->threadptr = newregs.threadptr; |
|---|
| 93 | + |
|---|
| 94 | + if (newregs.syscall) |
|---|
| 95 | + regs->syscall = newregs.syscall; |
|---|
| 96 | + |
|---|
| 97 | + if (newregs.windowbase != regs->windowbase || |
|---|
| 98 | + newregs.windowstart != regs->windowstart) { |
|---|
| 99 | + u32 rotws, wmask; |
|---|
| 100 | + |
|---|
| 101 | + rotws = (((newregs.windowstart | |
|---|
| 102 | + (newregs.windowstart << WSBITS)) >> |
|---|
| 103 | + newregs.windowbase) & |
|---|
| 104 | + ((1 << WSBITS) - 1)) & ~1; |
|---|
| 105 | + wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) | |
|---|
| 106 | + (rotws & 0xF) | 1; |
|---|
| 107 | + regs->windowbase = newregs.windowbase; |
|---|
| 108 | + regs->windowstart = newregs.windowstart; |
|---|
| 109 | + regs->wmask = wmask; |
|---|
| 110 | + } |
|---|
| 111 | + |
|---|
| 112 | + memcpy(regs->areg + XCHAL_NUM_AREGS - newregs.windowbase * 4, |
|---|
| 113 | + newregs.a, newregs.windowbase * 16); |
|---|
| 114 | + memcpy(regs->areg, newregs.a + newregs.windowbase * 4, |
|---|
| 115 | + (WSBITS - newregs.windowbase) * 16); |
|---|
| 116 | + |
|---|
| 117 | + return 0; |
|---|
| 118 | +} |
|---|
| 119 | + |
|---|
| 120 | +static int tie_get(struct task_struct *target, |
|---|
| 121 | + const struct user_regset *regset, |
|---|
| 122 | + struct membuf to) |
|---|
| 123 | +{ |
|---|
| 124 | + int ret; |
|---|
| 125 | + struct pt_regs *regs = task_pt_regs(target); |
|---|
| 126 | + struct thread_info *ti = task_thread_info(target); |
|---|
| 127 | + elf_xtregs_t *newregs = kzalloc(sizeof(elf_xtregs_t), GFP_KERNEL); |
|---|
| 128 | + |
|---|
| 129 | + if (!newregs) |
|---|
| 130 | + return -ENOMEM; |
|---|
| 131 | + |
|---|
| 132 | + newregs->opt = regs->xtregs_opt; |
|---|
| 133 | + newregs->user = ti->xtregs_user; |
|---|
| 134 | + |
|---|
| 135 | +#if XTENSA_HAVE_COPROCESSORS |
|---|
| 136 | + /* Flush all coprocessor registers to memory. */ |
|---|
| 137 | + coprocessor_flush_all(ti); |
|---|
| 138 | + newregs->cp0 = ti->xtregs_cp.cp0; |
|---|
| 139 | + newregs->cp1 = ti->xtregs_cp.cp1; |
|---|
| 140 | + newregs->cp2 = ti->xtregs_cp.cp2; |
|---|
| 141 | + newregs->cp3 = ti->xtregs_cp.cp3; |
|---|
| 142 | + newregs->cp4 = ti->xtregs_cp.cp4; |
|---|
| 143 | + newregs->cp5 = ti->xtregs_cp.cp5; |
|---|
| 144 | + newregs->cp6 = ti->xtregs_cp.cp6; |
|---|
| 145 | + newregs->cp7 = ti->xtregs_cp.cp7; |
|---|
| 146 | +#endif |
|---|
| 147 | + ret = membuf_write(&to, newregs, sizeof(*newregs)); |
|---|
| 148 | + kfree(newregs); |
|---|
| 149 | + return ret; |
|---|
| 150 | +} |
|---|
| 151 | + |
|---|
| 152 | +static int tie_set(struct task_struct *target, |
|---|
| 153 | + const struct user_regset *regset, |
|---|
| 154 | + unsigned int pos, unsigned int count, |
|---|
| 155 | + const void *kbuf, const void __user *ubuf) |
|---|
| 156 | +{ |
|---|
| 157 | + int ret; |
|---|
| 158 | + struct pt_regs *regs = task_pt_regs(target); |
|---|
| 159 | + struct thread_info *ti = task_thread_info(target); |
|---|
| 160 | + elf_xtregs_t *newregs = kzalloc(sizeof(elf_xtregs_t), GFP_KERNEL); |
|---|
| 161 | + |
|---|
| 162 | + if (!newregs) |
|---|
| 163 | + return -ENOMEM; |
|---|
| 164 | + |
|---|
| 165 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
|---|
| 166 | + newregs, 0, -1); |
|---|
| 167 | + |
|---|
| 168 | + if (ret) |
|---|
| 169 | + goto exit; |
|---|
| 170 | + regs->xtregs_opt = newregs->opt; |
|---|
| 171 | + ti->xtregs_user = newregs->user; |
|---|
| 172 | + |
|---|
| 173 | +#if XTENSA_HAVE_COPROCESSORS |
|---|
| 174 | + /* Flush all coprocessors before we overwrite them. */ |
|---|
| 175 | + coprocessor_flush_all(ti); |
|---|
| 176 | + coprocessor_release_all(ti); |
|---|
| 177 | + ti->xtregs_cp.cp0 = newregs->cp0; |
|---|
| 178 | + ti->xtregs_cp.cp1 = newregs->cp1; |
|---|
| 179 | + ti->xtregs_cp.cp2 = newregs->cp2; |
|---|
| 180 | + ti->xtregs_cp.cp3 = newregs->cp3; |
|---|
| 181 | + ti->xtregs_cp.cp4 = newregs->cp4; |
|---|
| 182 | + ti->xtregs_cp.cp5 = newregs->cp5; |
|---|
| 183 | + ti->xtregs_cp.cp6 = newregs->cp6; |
|---|
| 184 | + ti->xtregs_cp.cp7 = newregs->cp7; |
|---|
| 185 | +#endif |
|---|
| 186 | +exit: |
|---|
| 187 | + kfree(newregs); |
|---|
| 188 | + return ret; |
|---|
| 189 | +} |
|---|
| 190 | + |
|---|
| 191 | +enum xtensa_regset { |
|---|
| 192 | + REGSET_GPR, |
|---|
| 193 | + REGSET_TIE, |
|---|
| 194 | +}; |
|---|
| 195 | + |
|---|
| 196 | +static const struct user_regset xtensa_regsets[] = { |
|---|
| 197 | + [REGSET_GPR] = { |
|---|
| 198 | + .core_note_type = NT_PRSTATUS, |
|---|
| 199 | + .n = sizeof(struct user_pt_regs) / sizeof(u32), |
|---|
| 200 | + .size = sizeof(u32), |
|---|
| 201 | + .align = sizeof(u32), |
|---|
| 202 | + .regset_get = gpr_get, |
|---|
| 203 | + .set = gpr_set, |
|---|
| 204 | + }, |
|---|
| 205 | + [REGSET_TIE] = { |
|---|
| 206 | + .core_note_type = NT_PRFPREG, |
|---|
| 207 | + .n = sizeof(elf_xtregs_t) / sizeof(u32), |
|---|
| 208 | + .size = sizeof(u32), |
|---|
| 209 | + .align = sizeof(u32), |
|---|
| 210 | + .regset_get = tie_get, |
|---|
| 211 | + .set = tie_set, |
|---|
| 212 | + }, |
|---|
| 213 | +}; |
|---|
| 214 | + |
|---|
| 215 | +static const struct user_regset_view user_xtensa_view = { |
|---|
| 216 | + .name = "xtensa", |
|---|
| 217 | + .e_machine = EM_XTENSA, |
|---|
| 218 | + .regsets = xtensa_regsets, |
|---|
| 219 | + .n = ARRAY_SIZE(xtensa_regsets) |
|---|
| 220 | +}; |
|---|
| 221 | + |
|---|
| 222 | +const struct user_regset_view *task_user_regset_view(struct task_struct *task) |
|---|
| 223 | +{ |
|---|
| 224 | + return &user_xtensa_view; |
|---|
| 225 | +} |
|---|
| 35 | 226 | |
|---|
| 36 | 227 | void user_enable_single_step(struct task_struct *child) |
|---|
| 37 | 228 | { |
|---|
| 38 | | - child->ptrace |= PT_SINGLESTEP; |
|---|
| 229 | + set_tsk_thread_flag(child, TIF_SINGLESTEP); |
|---|
| 39 | 230 | } |
|---|
| 40 | 231 | |
|---|
| 41 | 232 | void user_disable_single_step(struct task_struct *child) |
|---|
| 42 | 233 | { |
|---|
| 43 | | - child->ptrace &= ~PT_SINGLESTEP; |
|---|
| 234 | + clear_tsk_thread_flag(child, TIF_SINGLESTEP); |
|---|
| 44 | 235 | } |
|---|
| 45 | 236 | |
|---|
| 46 | 237 | /* |
|---|
| .. | .. |
|---|
| 54 | 245 | |
|---|
| 55 | 246 | static int ptrace_getregs(struct task_struct *child, void __user *uregs) |
|---|
| 56 | 247 | { |
|---|
| 57 | | - struct pt_regs *regs = task_pt_regs(child); |
|---|
| 58 | | - xtensa_gregset_t __user *gregset = uregs; |
|---|
| 59 | | - unsigned long wb = regs->windowbase; |
|---|
| 60 | | - int i; |
|---|
| 61 | | - |
|---|
| 62 | | - if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) |
|---|
| 63 | | - return -EIO; |
|---|
| 64 | | - |
|---|
| 65 | | - __put_user(regs->pc, &gregset->pc); |
|---|
| 66 | | - __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); |
|---|
| 67 | | - __put_user(regs->lbeg, &gregset->lbeg); |
|---|
| 68 | | - __put_user(regs->lend, &gregset->lend); |
|---|
| 69 | | - __put_user(regs->lcount, &gregset->lcount); |
|---|
| 70 | | - __put_user(regs->windowstart, &gregset->windowstart); |
|---|
| 71 | | - __put_user(regs->windowbase, &gregset->windowbase); |
|---|
| 72 | | - __put_user(regs->threadptr, &gregset->threadptr); |
|---|
| 73 | | - |
|---|
| 74 | | - for (i = 0; i < XCHAL_NUM_AREGS; i++) |
|---|
| 75 | | - __put_user(regs->areg[i], |
|---|
| 76 | | - gregset->a + ((wb * 4 + i) % XCHAL_NUM_AREGS)); |
|---|
| 77 | | - |
|---|
| 78 | | - return 0; |
|---|
| 248 | + return copy_regset_to_user(child, &user_xtensa_view, REGSET_GPR, |
|---|
| 249 | + 0, sizeof(xtensa_gregset_t), uregs); |
|---|
| 79 | 250 | } |
|---|
| 80 | 251 | |
|---|
| 81 | 252 | static int ptrace_setregs(struct task_struct *child, void __user *uregs) |
|---|
| 82 | 253 | { |
|---|
| 83 | | - struct pt_regs *regs = task_pt_regs(child); |
|---|
| 84 | | - xtensa_gregset_t *gregset = uregs; |
|---|
| 85 | | - const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; |
|---|
| 86 | | - unsigned long ps; |
|---|
| 87 | | - unsigned long wb, ws; |
|---|
| 88 | | - |
|---|
| 89 | | - if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) |
|---|
| 90 | | - return -EIO; |
|---|
| 91 | | - |
|---|
| 92 | | - __get_user(regs->pc, &gregset->pc); |
|---|
| 93 | | - __get_user(ps, &gregset->ps); |
|---|
| 94 | | - __get_user(regs->lbeg, &gregset->lbeg); |
|---|
| 95 | | - __get_user(regs->lend, &gregset->lend); |
|---|
| 96 | | - __get_user(regs->lcount, &gregset->lcount); |
|---|
| 97 | | - __get_user(ws, &gregset->windowstart); |
|---|
| 98 | | - __get_user(wb, &gregset->windowbase); |
|---|
| 99 | | - __get_user(regs->threadptr, &gregset->threadptr); |
|---|
| 100 | | - |
|---|
| 101 | | - regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); |
|---|
| 102 | | - |
|---|
| 103 | | - if (wb >= XCHAL_NUM_AREGS / 4) |
|---|
| 104 | | - return -EFAULT; |
|---|
| 105 | | - |
|---|
| 106 | | - if (wb != regs->windowbase || ws != regs->windowstart) { |
|---|
| 107 | | - unsigned long rotws, wmask; |
|---|
| 108 | | - |
|---|
| 109 | | - rotws = (((ws | (ws << WSBITS)) >> wb) & |
|---|
| 110 | | - ((1 << WSBITS) - 1)) & ~1; |
|---|
| 111 | | - wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) | |
|---|
| 112 | | - (rotws & 0xF) | 1; |
|---|
| 113 | | - regs->windowbase = wb; |
|---|
| 114 | | - regs->windowstart = ws; |
|---|
| 115 | | - regs->wmask = wmask; |
|---|
| 116 | | - } |
|---|
| 117 | | - |
|---|
| 118 | | - if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, |
|---|
| 119 | | - gregset->a, wb * 16)) |
|---|
| 120 | | - return -EFAULT; |
|---|
| 121 | | - |
|---|
| 122 | | - if (__copy_from_user(regs->areg, gregset->a + wb * 4, |
|---|
| 123 | | - (WSBITS - wb) * 16)) |
|---|
| 124 | | - return -EFAULT; |
|---|
| 125 | | - |
|---|
| 126 | | - return 0; |
|---|
| 254 | + return copy_regset_from_user(child, &user_xtensa_view, REGSET_GPR, |
|---|
| 255 | + 0, sizeof(xtensa_gregset_t), uregs); |
|---|
| 127 | 256 | } |
|---|
| 128 | | - |
|---|
| 129 | | - |
|---|
| 130 | | -#if XTENSA_HAVE_COPROCESSORS |
|---|
| 131 | | -#define CP_OFFSETS(cp) \ |
|---|
| 132 | | - { \ |
|---|
| 133 | | - .elf_xtregs_offset = offsetof(elf_xtregs_t, cp), \ |
|---|
| 134 | | - .ti_offset = offsetof(struct thread_info, xtregs_cp.cp), \ |
|---|
| 135 | | - .sz = sizeof(xtregs_ ## cp ## _t), \ |
|---|
| 136 | | - } |
|---|
| 137 | | - |
|---|
| 138 | | -static const struct { |
|---|
| 139 | | - size_t elf_xtregs_offset; |
|---|
| 140 | | - size_t ti_offset; |
|---|
| 141 | | - size_t sz; |
|---|
| 142 | | -} cp_offsets[] = { |
|---|
| 143 | | - CP_OFFSETS(cp0), |
|---|
| 144 | | - CP_OFFSETS(cp1), |
|---|
| 145 | | - CP_OFFSETS(cp2), |
|---|
| 146 | | - CP_OFFSETS(cp3), |
|---|
| 147 | | - CP_OFFSETS(cp4), |
|---|
| 148 | | - CP_OFFSETS(cp5), |
|---|
| 149 | | - CP_OFFSETS(cp6), |
|---|
| 150 | | - CP_OFFSETS(cp7), |
|---|
| 151 | | -}; |
|---|
| 152 | | -#endif |
|---|
| 153 | 257 | |
|---|
| 154 | 258 | static int ptrace_getxregs(struct task_struct *child, void __user *uregs) |
|---|
| 155 | 259 | { |
|---|
| 156 | | - struct pt_regs *regs = task_pt_regs(child); |
|---|
| 157 | | - struct thread_info *ti = task_thread_info(child); |
|---|
| 158 | | - elf_xtregs_t __user *xtregs = uregs; |
|---|
| 159 | | - int ret = 0; |
|---|
| 160 | | - int i __maybe_unused; |
|---|
| 161 | | - |
|---|
| 162 | | - if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) |
|---|
| 163 | | - return -EIO; |
|---|
| 164 | | - |
|---|
| 165 | | -#if XTENSA_HAVE_COPROCESSORS |
|---|
| 166 | | - /* Flush all coprocessor registers to memory. */ |
|---|
| 167 | | - coprocessor_flush_all(ti); |
|---|
| 168 | | - |
|---|
| 169 | | - for (i = 0; i < ARRAY_SIZE(cp_offsets); ++i) |
|---|
| 170 | | - ret |= __copy_to_user((char __user *)xtregs + |
|---|
| 171 | | - cp_offsets[i].elf_xtregs_offset, |
|---|
| 172 | | - (const char *)ti + |
|---|
| 173 | | - cp_offsets[i].ti_offset, |
|---|
| 174 | | - cp_offsets[i].sz); |
|---|
| 175 | | -#endif |
|---|
| 176 | | - ret |= __copy_to_user(&xtregs->opt, ®s->xtregs_opt, |
|---|
| 177 | | - sizeof(xtregs->opt)); |
|---|
| 178 | | - ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user, |
|---|
| 179 | | - sizeof(xtregs->user)); |
|---|
| 180 | | - |
|---|
| 181 | | - return ret ? -EFAULT : 0; |
|---|
| 260 | + return copy_regset_to_user(child, &user_xtensa_view, REGSET_TIE, |
|---|
| 261 | + 0, sizeof(elf_xtregs_t), uregs); |
|---|
| 182 | 262 | } |
|---|
| 183 | 263 | |
|---|
| 184 | 264 | static int ptrace_setxregs(struct task_struct *child, void __user *uregs) |
|---|
| 185 | 265 | { |
|---|
| 186 | | - struct thread_info *ti = task_thread_info(child); |
|---|
| 187 | | - struct pt_regs *regs = task_pt_regs(child); |
|---|
| 188 | | - elf_xtregs_t *xtregs = uregs; |
|---|
| 189 | | - int ret = 0; |
|---|
| 190 | | - int i __maybe_unused; |
|---|
| 191 | | - |
|---|
| 192 | | - if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t))) |
|---|
| 193 | | - return -EFAULT; |
|---|
| 194 | | - |
|---|
| 195 | | -#if XTENSA_HAVE_COPROCESSORS |
|---|
| 196 | | - /* Flush all coprocessors before we overwrite them. */ |
|---|
| 197 | | - coprocessor_flush_all(ti); |
|---|
| 198 | | - coprocessor_release_all(ti); |
|---|
| 199 | | - |
|---|
| 200 | | - for (i = 0; i < ARRAY_SIZE(cp_offsets); ++i) |
|---|
| 201 | | - ret |= __copy_from_user((char *)ti + cp_offsets[i].ti_offset, |
|---|
| 202 | | - (const char __user *)xtregs + |
|---|
| 203 | | - cp_offsets[i].elf_xtregs_offset, |
|---|
| 204 | | - cp_offsets[i].sz); |
|---|
| 205 | | -#endif |
|---|
| 206 | | - ret |= __copy_from_user(®s->xtregs_opt, &xtregs->opt, |
|---|
| 207 | | - sizeof(xtregs->opt)); |
|---|
| 208 | | - ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user, |
|---|
| 209 | | - sizeof(xtregs->user)); |
|---|
| 210 | | - |
|---|
| 211 | | - return ret ? -EFAULT : 0; |
|---|
| 266 | + return copy_regset_from_user(child, &user_xtensa_view, REGSET_TIE, |
|---|
| 267 | + 0, sizeof(elf_xtregs_t), uregs); |
|---|
| 212 | 268 | } |
|---|
| 213 | 269 | |
|---|
| 214 | 270 | static int ptrace_peekusr(struct task_struct *child, long regno, |
|---|
| .. | .. |
|---|
| 447 | 503 | void __user *datap = (void __user *) data; |
|---|
| 448 | 504 | |
|---|
| 449 | 505 | switch (request) { |
|---|
| 450 | | - case PTRACE_PEEKTEXT: /* read word at location addr. */ |
|---|
| 451 | | - case PTRACE_PEEKDATA: |
|---|
| 452 | | - ret = generic_ptrace_peekdata(child, addr, data); |
|---|
| 453 | | - break; |
|---|
| 454 | | - |
|---|
| 455 | 506 | case PTRACE_PEEKUSR: /* read register specified by addr. */ |
|---|
| 456 | 507 | ret = ptrace_peekusr(child, addr, datap); |
|---|
| 457 | | - break; |
|---|
| 458 | | - |
|---|
| 459 | | - case PTRACE_POKETEXT: /* write the word at location addr. */ |
|---|
| 460 | | - case PTRACE_POKEDATA: |
|---|
| 461 | | - ret = generic_ptrace_pokedata(child, addr, data); |
|---|
| 462 | 508 | break; |
|---|
| 463 | 509 | |
|---|
| 464 | 510 | case PTRACE_POKEUSR: /* write register specified by addr. */ |
|---|
| .. | .. |
|---|
| 497 | 543 | return ret; |
|---|
| 498 | 544 | } |
|---|
| 499 | 545 | |
|---|
| 500 | | -unsigned long do_syscall_trace_enter(struct pt_regs *regs) |
|---|
| 546 | +void do_syscall_trace_leave(struct pt_regs *regs); |
|---|
| 547 | +int do_syscall_trace_enter(struct pt_regs *regs) |
|---|
| 501 | 548 | { |
|---|
| 502 | | - if (test_thread_flag(TIF_SYSCALL_TRACE) && |
|---|
| 503 | | - tracehook_report_syscall_entry(regs)) |
|---|
| 504 | | - return -1; |
|---|
| 549 | + if (regs->syscall == NO_SYSCALL) |
|---|
| 550 | + regs->areg[2] = -ENOSYS; |
|---|
| 505 | 551 | |
|---|
| 506 | | - return regs->areg[2]; |
|---|
| 552 | + if (test_thread_flag(TIF_SYSCALL_TRACE) && |
|---|
| 553 | + tracehook_report_syscall_entry(regs)) { |
|---|
| 554 | + regs->areg[2] = -ENOSYS; |
|---|
| 555 | + regs->syscall = NO_SYSCALL; |
|---|
| 556 | + return 0; |
|---|
| 557 | + } |
|---|
| 558 | + |
|---|
| 559 | + if (regs->syscall == NO_SYSCALL || |
|---|
| 560 | + secure_computing() == -1) { |
|---|
| 561 | + do_syscall_trace_leave(regs); |
|---|
| 562 | + return 0; |
|---|
| 563 | + } |
|---|
| 564 | + |
|---|
| 565 | + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) |
|---|
| 566 | + trace_sys_enter(regs, syscall_get_nr(current, regs)); |
|---|
| 567 | + |
|---|
| 568 | + audit_syscall_entry(regs->syscall, regs->areg[6], |
|---|
| 569 | + regs->areg[3], regs->areg[4], |
|---|
| 570 | + regs->areg[5]); |
|---|
| 571 | + return 1; |
|---|
| 507 | 572 | } |
|---|
| 508 | 573 | |
|---|
| 509 | 574 | void do_syscall_trace_leave(struct pt_regs *regs) |
|---|
| 510 | 575 | { |
|---|
| 511 | 576 | int step; |
|---|
| 512 | 577 | |
|---|
| 578 | + audit_syscall_exit(regs); |
|---|
| 579 | + |
|---|
| 580 | + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) |
|---|
| 581 | + trace_sys_exit(regs, regs_return_value(regs)); |
|---|
| 582 | + |
|---|
| 513 | 583 | step = test_thread_flag(TIF_SINGLESTEP); |
|---|
| 514 | 584 | |
|---|
| 515 | 585 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
|---|