]>
Commit | Line | Data |
---|---|---|
afe81f75 MS |
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 | static bool domain_scope_le(const struct landlock_ruleset *const parent, | |
33 | const struct landlock_ruleset *const child) | |
34 | { | |
35 | const struct landlock_hierarchy *walker; | |
36 | ||
37 | if (!parent) | |
38 | return true; | |
39 | if (!child) | |
40 | return false; | |
41 | for (walker = child->hierarchy; walker; walker = walker->parent) { | |
42 | 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 | static bool task_is_scoped(const struct task_struct *const parent, | |
51 | const struct task_struct *const child) | |
52 | { | |
53 | bool is_scoped; | |
54 | const struct landlock_ruleset *dom_parent, *dom_child; | |
55 | ||
56 | rcu_read_lock(); | |
57 | dom_parent = landlock_get_task_domain(parent); | |
58 | dom_child = landlock_get_task_domain(child); | |
59 | is_scoped = domain_scope_le(dom_parent, dom_child); | |
60 | rcu_read_unlock(); | |
61 | return is_scoped; | |
62 | } | |
63 | ||
64 | 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 | if (!landlocked(parent)) | |
69 | return 0; | |
70 | if (task_is_scoped(parent, child)) | |
71 | 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 | static int hook_ptrace_access_check(struct task_struct *const child, | |
89 | const unsigned int mode) | |
90 | { | |
91 | 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 | static int hook_ptrace_traceme(struct task_struct *const parent) | |
107 | { | |
108 | 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 | __init void landlock_add_ptrace_hooks(void) | |
117 | { | |
118 | security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), | |
119 | LANDLOCK_NAME); | |
120 | } |