struct utrace_engine_ops — tracing engine callbacks
struct utrace_engine_ops { u32 (* report_quiesce) (enum utrace_resume_action action,struct utrace_attached_engine *engine,struct task_struct *task,unsigned long event); u32 (* report_signal) (u32 action,struct utrace_attached_engine *engine,struct task_struct *task,struct pt_regs *regs,siginfo_t *info,const struct k_sigaction *orig_ka,struct k_sigaction *return_ka); u32 (* report_clone) (enum utrace_resume_action action,struct utrace_attached_engine *engine,struct task_struct *parent,unsigned long clone_flags,struct task_struct *child); u32 (* report_jctl) (enum utrace_resume_action action,struct utrace_attached_engine *engine,struct task_struct *task,int type, int notify); u32 (* report_exec) (enum utrace_resume_action action,struct utrace_attached_engine *engine,struct task_struct *task,const struct linux_binfmt *fmt,const struct linux_binprm *bprm,struct pt_regs *regs); u32 (* report_syscall_entry) (u32 action,struct utrace_attached_engine *engine,struct task_struct *task,struct pt_regs *regs); u32 (* report_syscall_exit) (enum utrace_resume_action action,struct utrace_attached_engine *engine,struct task_struct *task,struct pt_regs *regs); u32 (* report_exit) (enum utrace_resume_action action,struct utrace_attached_engine *engine,struct task_struct *task,long orig_code, long *code); u32 (* report_death) (struct utrace_attached_engine *engine,struct task_struct *task,bool group_dead, int signal); void (* report_reap) (struct utrace_attached_engine *engine,struct task_struct *task); int (* unsafe_exec) (struct utrace_attached_engine *engine,struct task_struct *task); struct task_struct *(* tracer_task) (struct utrace_attached_engine *engine,struct task_struct *task); };
Requested by UTRACE_EVENT
(QUIESCE
).
This does not indicate any event, but just that task
(the current
thread) is in a safe place for examination. This call is made
before each specific event callback, except for report_reap
.
The event
argument gives the UTRACE_EVENT
(which
) value for
the event occurring. This callback might be made for events engine
has not requested, if some other engine is tracing the event;
calling utrace_set_events
call here can request the immediate
callback for this occurrence of event
. event
is zero when there
is no other event, task
is now ready to check for signals and
return to user mode, and some engine has used UTRACE_REPORT
or
UTRACE_INTERRUPT
to request this callback. For this case,
if report_signal
is not NULL
, the report_quiesce
callback
may be replaced with a report_signal
callback passing
UTRACE_SIGNAL_REPORT
in its action
argument, whenever task
is
entering the signal-check path anyway.
Requested by UTRACE_EVENT
(SIGNAL_
*) or UTRACE_EVENT
(QUIESCE
).
Use utrace_signal_action
and utrace_resume_action
on action
.
The signal action is UTRACE_SIGNAL_REPORT
when some engine has
used UTRACE_REPORT
or UTRACE_INTERRUPT
; the callback can choose
to stop or to deliver an artificial signal, before pending signals.
It's UTRACE_SIGNAL_HANDLER
instead when signal handler setup just
finished (after a previous UTRACE_SIGNAL_DELIVER
return); this
serves in lieu of any UTRACE_SIGNAL_REPORT
callback requested by
UTRACE_REPORT
or UTRACE_INTERRUPT
, and is also implicitly
requested by UTRACE_SINGLESTEP
or UTRACE_BLOCKSTEP
into the
signal delivery. The other signal actions indicate a signal about
to be delivered; the previous engine's return value sets the signal
action seen by the the following engine's callback. The info
data
can be changed at will, including info
->si_signo. The settings in
return_ka
determines what UTRACE_SIGNAL_DELIVER
does. orig_ka
is what was in force before other tracing engines intervened, and
it's NULL
when this report began as UTRACE_SIGNAL_REPORT
or
UTRACE_SIGNAL_HANDLER
. For a report without a new signal, info
is left uninitialized and must be set completely by an engine that
chooses to deliver a signal; if there was a previous report_signal
callback ending in UTRACE_STOP
and it was just resumed using
UTRACE_REPORT
or UTRACE_INTERRUPT
, then info
is left unchanged
from the previous callback. In this way, the original signal can
be left in info
while returning UTRACE_STOP
|UTRACE_SIGNAL_IGN
and then found again when resuming task
with UTRACE_INTERRUPT
.
The UTRACE_SIGNAL_HOLD
flag bit can be OR'd into the return value,
and might be in action
if the previous engine returned it. This
flag asks that the signal in info
be pushed back on task
's queue
so that it will be seen again after whatever action is taken now.
Requested by UTRACE_EVENT
(CLONE
).
Event reported for parent, before the new task child
might run.
clone_flags
gives the flags used in the clone system call,
or equivalent flags for a fork
or vfork
system call.
This function can use utrace_attach_task
on child
. It's guaranteed
that asynchronous utrace_attach_task
calls will be ordered after
any calls in report_clone
callbacks for the parent. Thus
when using UTRACE_ATTACH_EXCLUSIVE
in the asynchronous calls,
you can be sure that the parent's report_clone
callback has
already attached to child
or chosen not to. Passing UTRACE_STOP
to utrace_control
on child
here keeps the child stopped before
it ever runs in user mode, UTRACE_REPORT
or UTRACE_INTERRUPT
ensures a callback from child
before it starts in user mode.
Requested by UTRACE_EVENT
(JCTL
).
Job control event; type
is CLD_STOPPED
or CLD_CONTINUED
,
indicating whether we are stopping or resuming now. If notify
is nonzero, task
is the last thread to stop and so will send
SIGCHLD
to its parent after this callback; notify
reflects
what the parent's SIGCHLD
has in si_code
, which can sometimes
be CLD_STOPPED
even when type
is CLD_CONTINUED
.
Requested by UTRACE_EVENT
(EXEC
).
An execve system call has succeeded and the new program is about to
start running. The initial user register state is handy to be tweaked
directly in regs
. fmt
and bprm
gives the details of this exec.
Requested by UTRACE_EVENT
(SYSCALL_ENTRY
).
Thread has entered the kernel to request a system call.
The user register state is handy to be tweaked directly in regs
.
The action
argument contains an enum utrace_syscall_action,
use utrace_syscall_action
to extract it. The return value
overrides the last engine's action for the system call.
If the final action is UTRACE_SYSCALL_ABORT
, no system call
is made. The details of the system call being attempted can
be fetched here with syscall_get_nr
and syscall_get_arguments
.
The parameter registers can be changed with syscall_set_arguments
.
Requested by UTRACE_EVENT
(SYSCALL_EXIT
).
Thread is about to leave the kernel after a system call request.
The user register state is handy to be tweaked directly in regs
.
The results of the system call attempt can be examined here using
syscall_get_error
and syscall_get_return_value
. It is safe
here to call syscall_set_return_value
or syscall_rollback
.
Requested by UTRACE_EVENT
(EXIT
).
Thread is exiting and cannot be prevented from doing so,
but all its state is still live. The code
value will be
the wait result seen by the parent, and can be changed by
this engine or others. The orig_code
value is the real
status, not changed by any tracing engine. Returning UTRACE_STOP
here keeps task
stopped before it cleans up its state and dies,
so it can be examined by other processes. When task
is allowed
to run, it will die and get to the report_death
callback.
Requested by UTRACE_EVENT
(DEATH
).
Thread is really dead now. It might be reaped by its parent at
any time, or self-reap immediately. Though the actual reaping
may happen in parallel, a report_reap
callback will always be
ordered after a report_death
callback.
Requested by UTRACE_EVENT
(REAP
).
Called when someone reaps the dead task (parent, init, or self).
This means the parent called wait, or else this was a detached
thread or a process whose parent ignores SIGCHLD.
No more callbacks are made after this one.
The engine is always detached.
There is nothing more a tracing engine can do about this thread.
After this callback, the engine
pointer will become invalid.
The task
pointer may become invalid if get_task_struct
hasn't
been used to keep it alive.
An engine should always request this callback if it stores the
engine
pointer or stores any pointer in engine
->data, so it
can clean up its data structures.
Unlike other callbacks, this can be called from the parent's context
rather than from the traced thread itself--it must not delay the
parent by blocking.
Used if not NULL
.
Return LSM_UNSAFE_
* bits that apply to the exec in progress
due to tracing done by this engine. These bits indicate that
someone is able to examine the process and so a set-UID or similar
privilege escalation may not be safe to permit.
Called with task_lock
held.
Used if not NULL
.
Return the struct task_struct for the task using ptrace
on
task
, or NULL
. Always called with rcu_read_lock
held to
keep the returned struct alive. At exec time, this may be
called with task_lock
still held from when unsafe_exec
was
just called. In that case it must give results consistent
with those unsafe_exec
results, i.e. non-NULL
if any
LSM_UNSAFE_PTRACE_
* bits were set. The value is also used to
display after “TracerPid:” in /proc/PID/status, where it is
called with only rcu_read_lock
held. If this engine returns
NULL
, another engine may supply the result.
Each report_
*() callback corresponds to an UTRACE_EVENT
(*) bit.
utrace_set_events
calls on engine
choose which callbacks will be made
to engine
from task
.
Most callbacks take an action
argument, giving the resume action
chosen by other tracing engines. All callbacks take an engine
argument, and a task
argument, which is always equal to current
.
For some calls, action
also includes bits specific to that event
and utrace_resume_action
is used to extract the resume action.
This shows what would happen if engine
wasn't there, or will if
the callback's return value uses UTRACE_RESUME
. This always
starts as UTRACE_RESUME
when no other tracing is being done on
this task.
All return values contain enum utrace_resume_action bits. For
some calls, other bits specific to that kind of event are added to
the resume action bits with OR. These are the same bits used in
the action
argument. The resume action returned by a callback
does not override previous engines' choices, it only says what
engine
wants done. What task
actually does is the action that's
most constrained among the choices made by all attached engines.
See utrace_control
for more information on the actions.
When UTRACE_STOP
is used in report_syscall_entry
, then task
stops before attempting the system call. In other cases, the
resume action does not take effect until task
is ready to check
for signals and return to user mode. If there are more callbacks
to be made, the last round of calls determines the final action.
A report_quiesce
callback with event
zero, or a report_signal
callback, will always be the last one made before task
resumes.
Only UTRACE_STOP
is “sticky”--if engine
returned UTRACE_STOP
then task
stays stopped unless engine
returns different from a
following callback.
The report_death
and report_reap
callbacks do not take action
arguments, and only UTRACE_DETACH
is meaningful in the return value
from a report_death
callback. None of the resume actions applies
to a dead thread.
All report_
*() hooks are called with no locks held, in a generally
safe environment when we will be returning to user mode soon (or just
entered the kernel). It is fine to block for memory allocation and
the like, but all hooks are asynchronous and must not block on
external events! If you want the thread to block, use UTRACE_STOP
in your hook's return value; then later wake it up with utrace_control
.
The unsafe_exec
and tracer_task
hooks are not associated with
event reports. These may be NULL
if the engine has nothing to say.
These hooks are called in more constrained environments and should
not block or do very much.