Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only 2 : /* 3 : * Landlock LSM - Ptrace hooks 4 : * 5 : * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 6 : * Copyright © 2019-2020 ANSSI 7 : */ 8 : 9 : #include <asm/current.h> 10 : #include <linux/cred.h> 11 : #include <linux/errno.h> 12 : #include <linux/kernel.h> 13 : #include <linux/lsm_hooks.h> 14 : #include <linux/rcupdate.h> 15 : #include <linux/sched.h> 16 : 17 : #include "common.h" 18 : #include "cred.h" 19 : #include "ptrace.h" 20 : #include "ruleset.h" 21 : #include "setup.h" 22 : 23 : /** 24 : * domain_scope_le - Checks domain ordering for scoped ptrace 25 : * 26 : * @parent: Parent domain. 27 : * @child: Potential child of @parent. 28 : * 29 : * Checks if the @parent domain is less or equal to (i.e. an ancestor, which 30 : * means a subset of) the @child domain. 31 : */ 32 30 : static bool domain_scope_le(const struct landlock_ruleset *const parent, 33 : const struct landlock_ruleset *const child) 34 : { 35 30 : const struct landlock_hierarchy *walker; 36 : 37 30 : if (!parent) 38 : return true; 39 30 : if (!child) 40 : return false; 41 50 : for (walker = child->hierarchy; walker; walker = walker->parent) { 42 35 : if (walker == parent->hierarchy) 43 : /* @parent is in the scoped hierarchy of @child. */ 44 : return true; 45 : } 46 : /* There is no relationship between @parent and @child. */ 47 : return false; 48 : } 49 : 50 30 : static bool task_is_scoped(const struct task_struct *const parent, 51 : const struct task_struct *const child) 52 : { 53 30 : bool is_scoped; 54 30 : const struct landlock_ruleset *dom_parent, *dom_child; 55 : 56 30 : rcu_read_lock(); 57 30 : dom_parent = landlock_get_task_domain(parent); 58 30 : dom_child = landlock_get_task_domain(child); 59 30 : is_scoped = domain_scope_le(dom_parent, dom_child); 60 30 : rcu_read_unlock(); 61 30 : return is_scoped; 62 : } 63 : 64 236 : static int task_ptrace(const struct task_struct *const parent, 65 : const struct task_struct *const child) 66 : { 67 : /* Quick return for non-landlocked tasks. */ 68 236 : if (!landlocked(parent)) 69 : return 0; 70 30 : if (task_is_scoped(parent, child)) 71 10 : return 0; 72 : return -EPERM; 73 : } 74 : 75 : /** 76 : * hook_ptrace_access_check - Determines whether the current process may access 77 : * another 78 : * 79 : * @child: Process to be accessed. 80 : * @mode: Mode of attachment. 81 : * 82 : * If the current task has Landlock rules, then the child must have at least 83 : * the same rules. Else denied. 84 : * 85 : * Determines whether a process may access another, returning 0 if permission 86 : * granted, -errno if denied. 87 : */ 88 228 : static int hook_ptrace_access_check(struct task_struct *const child, 89 : const unsigned int mode) 90 : { 91 228 : return task_ptrace(current, child); 92 : } 93 : 94 : /** 95 : * hook_ptrace_traceme - Determines whether another process may trace the 96 : * current one 97 : * 98 : * @parent: Task proposed to be the tracer. 99 : * 100 : * If the parent has Landlock rules, then the current task must have the same 101 : * or more rules. Else denied. 102 : * 103 : * Determines whether the nominated task is permitted to trace the current 104 : * process, returning 0 if permission is granted, -errno if denied. 105 : */ 106 8 : static int hook_ptrace_traceme(struct task_struct *const parent) 107 : { 108 8 : return task_ptrace(parent, current); 109 : } 110 : 111 : static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { 112 : LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), 113 : LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), 114 : }; 115 : 116 1 : __init void landlock_add_ptrace_hooks(void) 117 : { 118 1 : security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), 119 : LANDLOCK_NAME); 120 1 : }