LCOV - code coverage report
Current view: top level - include/linux - tracehook.h (source / functions) Hit Total Coverage
Test: landlock.info Lines: 14 43 32.6 %
Date: 2021-04-22 12:43:58 Functions: 2 6 33.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0-only */
       2             : /*
       3             :  * Tracing hooks
       4             :  *
       5             :  * Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved.
       6             :  *
       7             :  * This file defines hook entry points called by core code where
       8             :  * user tracing/debugging support might need to do something.  These
       9             :  * entry points are called tracehook_*().  Each hook declared below
      10             :  * has a detailed kerneldoc comment giving the context (locking et
      11             :  * al) from which it is called, and the meaning of its return value.
      12             :  *
      13             :  * Each function here typically has only one call site, so it is ok
      14             :  * to have some nontrivial tracehook_*() inlines.  In all cases, the
      15             :  * fast path when no tracing is enabled should be very short.
      16             :  *
      17             :  * The purpose of this file and the tracehook_* layer is to consolidate
      18             :  * the interface that the kernel core and arch code uses to enable any
      19             :  * user debugging or tracing facility (such as ptrace).  The interfaces
      20             :  * here are carefully documented so that maintainers of core and arch
      21             :  * code do not need to think about the implementation details of the
      22             :  * tracing facilities.  Likewise, maintainers of the tracing code do not
      23             :  * need to understand all the calling core or arch code in detail, just
      24             :  * documented circumstances of each call, such as locking conditions.
      25             :  *
      26             :  * If the calling core code changes so that locking is different, then
      27             :  * it is ok to change the interface documented here.  The maintainer of
      28             :  * core code changing should notify the maintainers of the tracing code
      29             :  * that they need to work out the change.
      30             :  *
      31             :  * Some tracehook_*() inlines take arguments that the current tracing
      32             :  * implementations might not necessarily use.  These function signatures
      33             :  * are chosen to pass in all the information that is on hand in the
      34             :  * caller and might conceivably be relevant to a tracer, so that the
      35             :  * core code won't have to be updated when tracing adds more features.
      36             :  * If a call site changes so that some of those parameters are no longer
      37             :  * already on hand without extra work, then the tracehook_* interface
      38             :  * can change so there is no make-work burden on the core code.  The
      39             :  * maintainer of core code changing should notify the maintainers of the
      40             :  * tracing code that they need to work out the change.
      41             :  */
      42             : 
      43             : #ifndef _LINUX_TRACEHOOK_H
      44             : #define _LINUX_TRACEHOOK_H      1
      45             : 
      46             : #include <linux/sched.h>
      47             : #include <linux/ptrace.h>
      48             : #include <linux/security.h>
      49             : #include <linux/task_work.h>
      50             : #include <linux/memcontrol.h>
      51             : #include <linux/blk-cgroup.h>
      52             : struct linux_binprm;
      53             : 
      54             : /*
      55             :  * ptrace report for syscall entry and exit looks identical.
      56             :  */
      57           0 : static inline int ptrace_report_syscall(struct pt_regs *regs,
      58             :                                         unsigned long message)
      59             : {
      60           0 :         int ptrace = current->ptrace;
      61             : 
      62           0 :         if (!(ptrace & PT_PTRACED))
      63             :                 return 0;
      64             : 
      65           0 :         current->ptrace_message = message;
      66           0 :         ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
      67             : 
      68             :         /*
      69             :          * this isn't the same as continuing with a signal, but it will do
      70             :          * for normal use.  strace only continues with a signal if the
      71             :          * stopping signal is not SIGTRAP.  -brl
      72             :          */
      73           0 :         if (current->exit_code) {
      74           0 :                 send_sig(current->exit_code, current, 1);
      75           0 :                 current->exit_code = 0;
      76             :         }
      77             : 
      78           0 :         current->ptrace_message = 0;
      79           0 :         return fatal_signal_pending(current);
      80             : }
      81             : 
      82             : /**
      83             :  * tracehook_report_syscall_entry - task is about to attempt a system call
      84             :  * @regs:               user register state of current task
      85             :  *
      86             :  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE or
      87             :  * %SYSCALL_WORK_SYSCALL_EMU have been set, when the current task has just
      88             :  * entered the kernel for a system call.  Full user register state is
      89             :  * available here.  Changing the values in @regs can affect the system
      90             :  * call number and arguments to be tried.  It is safe to block here,
      91             :  * preventing the system call from beginning.
      92             :  *
      93             :  * Returns zero normally, or nonzero if the calling arch code should abort
      94             :  * the system call.  That must prevent normal entry so no system call is
      95             :  * made.  If @task ever returns to user mode after this, its register state
      96             :  * is unspecified, but should be something harmless like an %ENOSYS error
      97             :  * return.  It should preserve enough information so that syscall_rollback()
      98             :  * can work (see asm-generic/syscall.h).
      99             :  *
     100             :  * Called without locks, just after entering kernel mode.
     101             :  */
     102           0 : static inline __must_check int tracehook_report_syscall_entry(
     103             :         struct pt_regs *regs)
     104             : {
     105           0 :         return ptrace_report_syscall(regs, PTRACE_EVENTMSG_SYSCALL_ENTRY);
     106             : }
     107             : 
     108             : /**
     109             :  * tracehook_report_syscall_exit - task has just finished a system call
     110             :  * @regs:               user register state of current task
     111             :  * @step:               nonzero if simulating single-step or block-step
     112             :  *
     113             :  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE has been set, when
     114             :  * the current task has just finished an attempted system call.  Full
     115             :  * user register state is available here.  It is safe to block here,
     116             :  * preventing signals from being processed.
     117             :  *
     118             :  * If @step is nonzero, this report is also in lieu of the normal
     119             :  * trap that would follow the system call instruction because
     120             :  * user_enable_block_step() or user_enable_single_step() was used.
     121             :  * In this case, %SYSCALL_WORK_SYSCALL_TRACE might not be set.
     122             :  *
     123             :  * Called without locks, just before checking for pending signals.
     124             :  */
     125           0 : static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
     126             : {
     127           0 :         if (step)
     128           0 :                 user_single_step_report(regs);
     129             :         else
     130           0 :                 ptrace_report_syscall(regs, PTRACE_EVENTMSG_SYSCALL_EXIT);
     131           0 : }
     132             : 
     133             : /**
     134             :  * tracehook_signal_handler - signal handler setup is complete
     135             :  * @stepping:           nonzero if debugger single-step or block-step in use
     136             :  *
     137             :  * Called by the arch code after a signal handler has been set up.
     138             :  * Register and stack state reflects the user handler about to run.
     139             :  * Signal mask changes have already been made.
     140             :  *
     141             :  * Called without locks, shortly before returning to user mode
     142             :  * (or handling more signals).
     143             :  */
     144         461 : static inline void tracehook_signal_handler(int stepping)
     145             : {
     146         461 :         if (stepping)
     147           0 :                 ptrace_notify(SIGTRAP);
     148             : }
     149             : 
     150             : /**
     151             :  * set_notify_resume - cause tracehook_notify_resume() to be called
     152             :  * @task:               task that will call tracehook_notify_resume()
     153             :  *
     154             :  * Calling this arranges that @task will call tracehook_notify_resume()
     155             :  * before returning to user mode.  If it's already running in user mode,
     156             :  * it will enter the kernel and call tracehook_notify_resume() soon.
     157             :  * If it's blocked, it will not be woken.
     158             :  */
     159       56851 : static inline void set_notify_resume(struct task_struct *task)
     160             : {
     161             : #ifdef TIF_NOTIFY_RESUME
     162       56851 :         if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME))
     163       51358 :                 kick_process(task);
     164             : #endif
     165       56856 : }
     166             : 
     167             : /**
     168             :  * tracehook_notify_resume - report when about to return to user mode
     169             :  * @regs:               user-mode registers of @current task
     170             :  *
     171             :  * This is called when %TIF_NOTIFY_RESUME has been set.  Now we are
     172             :  * about to return to user mode, and the user state in @regs can be
     173             :  * inspected or adjusted.  The caller in arch code has cleared
     174             :  * %TIF_NOTIFY_RESUME before the call.  If the flag gets set again
     175             :  * asynchronously, this will be called again before we return to
     176             :  * user mode.
     177             :  *
     178             :  * Called without locks.
     179             :  */
     180       51832 : static inline void tracehook_notify_resume(struct pt_regs *regs)
     181             : {
     182       51832 :         clear_thread_flag(TIF_NOTIFY_RESUME);
     183             :         /*
     184             :          * This barrier pairs with task_work_add()->set_notify_resume() after
     185             :          * hlist_add_head(task->task_works);
     186             :          */
     187       51854 :         smp_mb__after_atomic();
     188       51854 :         if (unlikely(current->task_works))
     189       51798 :                 task_work_run();
     190             : 
     191             : #ifdef CONFIG_KEYS_REQUEST_CACHE
     192             :         if (unlikely(current->cached_requested_key)) {
     193             :                 key_put(current->cached_requested_key);
     194             :                 current->cached_requested_key = NULL;
     195             :         }
     196             : #endif
     197             : 
     198       51836 :         mem_cgroup_handle_over_high();
     199       51836 :         blkcg_maybe_throttle_current();
     200       51836 : }
     201             : 
     202             : /*
     203             :  * called by exit_to_user_mode_loop() if ti_work & _TIF_NOTIFY_SIGNAL. This
     204             :  * is currently used by TWA_SIGNAL based task_work, which requires breaking
     205             :  * wait loops to ensure that task_work is noticed and run.
     206             :  */
     207           0 : static inline void tracehook_notify_signal(void)
     208             : {
     209           0 :         clear_thread_flag(TIF_NOTIFY_SIGNAL);
     210           0 :         smp_mb__after_atomic();
     211           0 :         if (current->task_works)
     212           0 :                 task_work_run();
     213           0 : }
     214             : 
     215             : /*
     216             :  * Called when we have work to process from exit_to_user_mode_loop()
     217             :  */
     218           0 : static inline void set_notify_signal(struct task_struct *task)
     219             : {
     220           0 :         if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_SIGNAL) &&
     221           0 :             !wake_up_state(task, TASK_INTERRUPTIBLE))
     222           0 :                 kick_process(task);
     223           0 : }
     224             : 
     225             : #endif  /* <linux/tracehook.h> */

Generated by: LCOV version 1.14