162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Landlock LSM - Ptrace hooks 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 662306a36Sopenharmony_ci * Copyright © 2019-2020 ANSSI 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/current.h> 1062306a36Sopenharmony_ci#include <linux/cred.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/lsm_hooks.h> 1462306a36Sopenharmony_ci#include <linux/rcupdate.h> 1562306a36Sopenharmony_ci#include <linux/sched.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "common.h" 1862306a36Sopenharmony_ci#include "cred.h" 1962306a36Sopenharmony_ci#include "ptrace.h" 2062306a36Sopenharmony_ci#include "ruleset.h" 2162306a36Sopenharmony_ci#include "setup.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * domain_scope_le - Checks domain ordering for scoped ptrace 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * @parent: Parent domain. 2762306a36Sopenharmony_ci * @child: Potential child of @parent. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Checks if the @parent domain is less or equal to (i.e. an ancestor, which 3062306a36Sopenharmony_ci * means a subset of) the @child domain. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic bool domain_scope_le(const struct landlock_ruleset *const parent, 3362306a36Sopenharmony_ci const struct landlock_ruleset *const child) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci const struct landlock_hierarchy *walker; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (!parent) 3862306a36Sopenharmony_ci return true; 3962306a36Sopenharmony_ci if (!child) 4062306a36Sopenharmony_ci return false; 4162306a36Sopenharmony_ci for (walker = child->hierarchy; walker; walker = walker->parent) { 4262306a36Sopenharmony_ci if (walker == parent->hierarchy) 4362306a36Sopenharmony_ci /* @parent is in the scoped hierarchy of @child. */ 4462306a36Sopenharmony_ci return true; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci /* There is no relationship between @parent and @child. */ 4762306a36Sopenharmony_ci return false; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic bool task_is_scoped(const struct task_struct *const parent, 5162306a36Sopenharmony_ci const struct task_struct *const child) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci bool is_scoped; 5462306a36Sopenharmony_ci const struct landlock_ruleset *dom_parent, *dom_child; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci rcu_read_lock(); 5762306a36Sopenharmony_ci dom_parent = landlock_get_task_domain(parent); 5862306a36Sopenharmony_ci dom_child = landlock_get_task_domain(child); 5962306a36Sopenharmony_ci is_scoped = domain_scope_le(dom_parent, dom_child); 6062306a36Sopenharmony_ci rcu_read_unlock(); 6162306a36Sopenharmony_ci return is_scoped; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int task_ptrace(const struct task_struct *const parent, 6562306a36Sopenharmony_ci const struct task_struct *const child) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci /* Quick return for non-landlocked tasks. */ 6862306a36Sopenharmony_ci if (!landlocked(parent)) 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci if (task_is_scoped(parent, child)) 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci return -EPERM; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * hook_ptrace_access_check - Determines whether the current process may access 7762306a36Sopenharmony_ci * another 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * @child: Process to be accessed. 8062306a36Sopenharmony_ci * @mode: Mode of attachment. 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * If the current task has Landlock rules, then the child must have at least 8362306a36Sopenharmony_ci * the same rules. Else denied. 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * Determines whether a process may access another, returning 0 if permission 8662306a36Sopenharmony_ci * granted, -errno if denied. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic int hook_ptrace_access_check(struct task_struct *const child, 8962306a36Sopenharmony_ci const unsigned int mode) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci return task_ptrace(current, child); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * hook_ptrace_traceme - Determines whether another process may trace the 9662306a36Sopenharmony_ci * current one 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * @parent: Task proposed to be the tracer. 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * If the parent has Landlock rules, then the current task must have the same 10162306a36Sopenharmony_ci * or more rules. Else denied. 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * Determines whether the nominated task is permitted to trace the current 10462306a36Sopenharmony_ci * process, returning 0 if permission is granted, -errno if denied. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic int hook_ptrace_traceme(struct task_struct *const parent) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return task_ptrace(parent, current); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct security_hook_list landlock_hooks[] __ro_after_init = { 11262306a36Sopenharmony_ci LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), 11362306a36Sopenharmony_ci LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci__init void landlock_add_ptrace_hooks(void) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), 11962306a36Sopenharmony_ci LANDLOCK_NAME); 12062306a36Sopenharmony_ci} 121