pr_notice_ratelimited( "ptrace %s of \"%s\"[%d] was attempted by \"%s\"[%d]\n",
info->access, target_cmd, info->target->pid, agent_cmd,
info->agent->pid);
/** * yama_ptracer_add - add/replace an exception for this tracer/tracee pair * @tracer: the task_struct of the process doing the ptrace * @tracee: the task_struct of the process to be ptraced * * Each tracee can have, at most, one tracer registered. Each time this * is called, the prior registered tracer will be replaced for the tracee. * * Returns 0 if relationship was added, -ve on error.
*/ staticint yama_ptracer_add(struct task_struct *tracer, struct task_struct *tracee)
{ struct ptrace_relation *relation, *added;
added = kmalloc(sizeof(*added), GFP_KERNEL); if (!added) return -ENOMEM;
/** * yama_task_free - check for task_pid to remove from exception list * @task: task being removed
*/ staticvoid yama_task_free(struct task_struct *task)
{
yama_ptracer_del(task, task);
}
/** * yama_task_prctl - check for Yama-specific prctl operations * @option: operation * @arg2: argument * @arg3: argument * @arg4: argument * @arg5: argument * * Return 0 on success, -ve on error. -ENOSYS is returned when Yama * does not handle the given option.
*/ staticint yama_task_prctl(int option, unsignedlong arg2, unsignedlong arg3, unsignedlong arg4, unsignedlong arg5)
{ int rc = -ENOSYS; struct task_struct *myself;
switch (option) { case PR_SET_PTRACER: /* Since a thread can call prctl(), find the group leader * before calling _add() or _del() on it, since we want * process-level granularity of control. The tracer group * leader checking is handled later when walking the ancestry * at the time of PTRACE_ATTACH check.
*/
myself = current->group_leader;
/** * task_is_descendant - walk up a process family tree looking for a match * @parent: the process to compare against while walking up from child * @child: the process to start from while looking upwards for parent * * Returns 1 if child is a descendant of parent, 0 if not.
*/ staticint task_is_descendant(struct task_struct *parent, struct task_struct *child)
{ int rc = 0; struct task_struct *walker = child;
if (!parent || !child) return 0;
rcu_read_lock(); if (!thread_group_leader(parent))
parent = rcu_dereference(parent->group_leader); while (walker->pid > 0) { if (!thread_group_leader(walker))
walker = rcu_dereference(walker->group_leader); if (walker == parent) {
rc = 1; break;
}
walker = rcu_dereference(walker->real_parent);
}
rcu_read_unlock();
return rc;
}
/** * ptracer_exception_found - tracer registered as exception for this tracee * @tracer: the task_struct of the process attempting ptrace * @tracee: the task_struct of the process to be ptraced * * Returns 1 if tracer has a ptracer exception ancestor for tracee.
*/ staticint ptracer_exception_found(struct task_struct *tracer, struct task_struct *tracee)
{ int rc = 0; struct ptrace_relation *relation; struct task_struct *parent = NULL; bool found = false;
rcu_read_lock();
/* * If there's already an active tracing relationship, then make an * exception for the sake of other accesses, like process_vm_rw().
*/
parent = ptrace_parent(tracee); if (parent != NULL && same_thread_group(parent, tracer)) {
rc = 1; goto unlock;
}
/* Look for a PR_SET_PTRACER relationship. */ if (!thread_group_leader(tracee))
tracee = rcu_dereference(tracee->group_leader);
list_for_each_entry_rcu(relation, &ptracer_relations, node) { if (relation->invalid) continue; if (relation->tracee == tracee) {
parent = relation->tracer;
found = true; break;
}
}
/** * yama_ptrace_access_check - validate PTRACE_ATTACH calls * @child: task that current task is attempting to ptrace * @mode: ptrace attach mode * * Returns 0 if following the ptrace is allowed, -ve on error.
*/ staticint yama_ptrace_access_check(struct task_struct *child, unsignedint mode)
{ int rc = 0;
/* require ptrace target be a child of ptracer on attach */ if (mode & PTRACE_MODE_ATTACH) { switch (ptrace_scope) { case YAMA_SCOPE_DISABLED: /* No additional restrictions. */ break; case YAMA_SCOPE_RELATIONAL:
rcu_read_lock(); if (!pid_alive(child))
rc = -EPERM; if (!rc && !task_is_descendant(current, child) &&
!ptracer_exception_found(current, child) &&
!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
rc = -EPERM;
rcu_read_unlock(); break; case YAMA_SCOPE_CAPABILITY:
rcu_read_lock(); if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
rc = -EPERM;
rcu_read_unlock(); break; case YAMA_SCOPE_NO_ATTACH: default:
rc = -EPERM; break;
}
}
/** * yama_ptrace_traceme - validate PTRACE_TRACEME calls * @parent: task that will become the ptracer of the current task * * Returns 0 if following the ptrace is allowed, -ve on error.
*/ staticint yama_ptrace_traceme(struct task_struct *parent)
{ int rc = 0;
/* Only disallow PTRACE_TRACEME on more aggressive settings. */ switch (ptrace_scope) { case YAMA_SCOPE_CAPABILITY: if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE))
rc = -EPERM; break; case YAMA_SCOPE_NO_ATTACH:
rc = -EPERM; break;
}
if (rc) {
task_lock(current);
report_access("traceme", current, parent);
task_unlock(current);
}
if (write && !capable(CAP_SYS_PTRACE)) return -EPERM;
/* Lock the max value if it ever gets set. */
table_copy = *table; if (*(int *)table_copy.data == *(int *)table_copy.extra2)
table_copy.extra1 = table_copy.extra2;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.