| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Tracing hooks |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This copyrighted material is made available to anyone wishing to use, |
|---|
| 7 | | - * modify, copy, or redistribute it subject to the terms and conditions |
|---|
| 8 | | - * of the GNU General Public License v.2. |
|---|
| 9 | 6 | * |
|---|
| 10 | 7 | * This file defines hook entry points called by core code where |
|---|
| 11 | 8 | * user tracing/debugging support might need to do something. These |
|---|
| .. | .. |
|---|
| 57 | 54 | /* |
|---|
| 58 | 55 | * ptrace report for syscall entry and exit looks identical. |
|---|
| 59 | 56 | */ |
|---|
| 60 | | -static inline int ptrace_report_syscall(struct pt_regs *regs) |
|---|
| 57 | +static inline int ptrace_report_syscall(struct pt_regs *regs, |
|---|
| 58 | + unsigned long message) |
|---|
| 61 | 59 | { |
|---|
| 62 | 60 | int ptrace = current->ptrace; |
|---|
| 63 | 61 | |
|---|
| 64 | 62 | if (!(ptrace & PT_PTRACED)) |
|---|
| 65 | 63 | return 0; |
|---|
| 66 | 64 | |
|---|
| 65 | + current->ptrace_message = message; |
|---|
| 67 | 66 | ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); |
|---|
| 68 | 67 | |
|---|
| 69 | 68 | /* |
|---|
| .. | .. |
|---|
| 76 | 75 | current->exit_code = 0; |
|---|
| 77 | 76 | } |
|---|
| 78 | 77 | |
|---|
| 78 | + current->ptrace_message = 0; |
|---|
| 79 | 79 | return fatal_signal_pending(current); |
|---|
| 80 | 80 | } |
|---|
| 81 | 81 | |
|---|
| .. | .. |
|---|
| 83 | 83 | * tracehook_report_syscall_entry - task is about to attempt a system call |
|---|
| 84 | 84 | * @regs: user register state of current task |
|---|
| 85 | 85 | * |
|---|
| 86 | | - * This will be called if %TIF_SYSCALL_TRACE has been set, when the |
|---|
| 87 | | - * current task has just entered the kernel for a system call. |
|---|
| 86 | + * This will be called if %TIF_SYSCALL_TRACE or %TIF_SYSCALL_EMU have been set, |
|---|
| 87 | + * when the current task has just entered the kernel for a system call. |
|---|
| 88 | 88 | * Full user register state is available here. Changing the values |
|---|
| 89 | 89 | * in @regs can affect the system call number and arguments to be tried. |
|---|
| 90 | 90 | * It is safe to block here, preventing the system call from beginning. |
|---|
| .. | .. |
|---|
| 101 | 101 | static inline __must_check int tracehook_report_syscall_entry( |
|---|
| 102 | 102 | struct pt_regs *regs) |
|---|
| 103 | 103 | { |
|---|
| 104 | | - return ptrace_report_syscall(regs); |
|---|
| 104 | + return ptrace_report_syscall(regs, PTRACE_EVENTMSG_SYSCALL_ENTRY); |
|---|
| 105 | 105 | } |
|---|
| 106 | 106 | |
|---|
| 107 | 107 | /** |
|---|
| .. | .. |
|---|
| 123 | 123 | */ |
|---|
| 124 | 124 | static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) |
|---|
| 125 | 125 | { |
|---|
| 126 | | - if (step) { |
|---|
| 127 | | - siginfo_t info; |
|---|
| 128 | | - clear_siginfo(&info); |
|---|
| 129 | | - user_single_step_siginfo(current, regs, &info); |
|---|
| 130 | | - force_sig_info(SIGTRAP, &info, current); |
|---|
| 131 | | - return; |
|---|
| 132 | | - } |
|---|
| 133 | | - |
|---|
| 134 | | - ptrace_report_syscall(regs); |
|---|
| 126 | + if (step) |
|---|
| 127 | + user_single_step_report(regs); |
|---|
| 128 | + else |
|---|
| 129 | + ptrace_report_syscall(regs, PTRACE_EVENTMSG_SYSCALL_EXIT); |
|---|
| 135 | 130 | } |
|---|
| 136 | 131 | |
|---|
| 137 | 132 | /** |
|---|
| .. | .. |
|---|
| 183 | 178 | */ |
|---|
| 184 | 179 | static inline void tracehook_notify_resume(struct pt_regs *regs) |
|---|
| 185 | 180 | { |
|---|
| 181 | + clear_thread_flag(TIF_NOTIFY_RESUME); |
|---|
| 186 | 182 | /* |
|---|
| 187 | | - * The caller just cleared TIF_NOTIFY_RESUME. This barrier |
|---|
| 188 | | - * pairs with task_work_add()->set_notify_resume() after |
|---|
| 183 | + * This barrier pairs with task_work_add()->set_notify_resume() after |
|---|
| 189 | 184 | * hlist_add_head(task->task_works); |
|---|
| 190 | 185 | */ |
|---|
| 191 | 186 | smp_mb__after_atomic(); |
|---|
| 192 | 187 | if (unlikely(current->task_works)) |
|---|
| 193 | 188 | task_work_run(); |
|---|
| 194 | 189 | |
|---|
| 190 | +#ifdef CONFIG_KEYS_REQUEST_CACHE |
|---|
| 191 | + if (unlikely(current->cached_requested_key)) { |
|---|
| 192 | + key_put(current->cached_requested_key); |
|---|
| 193 | + current->cached_requested_key = NULL; |
|---|
| 194 | + } |
|---|
| 195 | +#endif |
|---|
| 196 | + |
|---|
| 195 | 197 | mem_cgroup_handle_over_high(); |
|---|
| 196 | 198 | blkcg_maybe_throttle_current(); |
|---|
| 197 | 199 | } |
|---|
| 198 | 200 | |
|---|
| 201 | +/* |
|---|
| 202 | + * called by exit_to_user_mode_loop() if ti_work & _TIF_NOTIFY_SIGNAL. This |
|---|
| 203 | + * is currently used by TWA_SIGNAL based task_work, which requires breaking |
|---|
| 204 | + * wait loops to ensure that task_work is noticed and run. |
|---|
| 205 | + */ |
|---|
| 206 | +static inline void tracehook_notify_signal(void) |
|---|
| 207 | +{ |
|---|
| 208 | + clear_thread_flag(TIF_NOTIFY_SIGNAL); |
|---|
| 209 | + smp_mb__after_atomic(); |
|---|
| 210 | + if (current->task_works) |
|---|
| 211 | + task_work_run(); |
|---|
| 212 | +} |
|---|
| 213 | + |
|---|
| 214 | +/* |
|---|
| 215 | + * Called when we have work to process from exit_to_user_mode_loop() |
|---|
| 216 | + */ |
|---|
| 217 | +static inline void set_notify_signal(struct task_struct *task) |
|---|
| 218 | +{ |
|---|
| 219 | + if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_SIGNAL) && |
|---|
| 220 | + !wake_up_state(task, TASK_INTERRUPTIBLE)) |
|---|
| 221 | + kick_process(task); |
|---|
| 222 | +} |
|---|
| 223 | + |
|---|
| 199 | 224 | #endif /* <linux/tracehook.h> */ |
|---|