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 #include <net/af_unix.h> 17 #include <net/sock.h> 18 19 #include "common.h" 20 #include "cred.h" 21 #include "ruleset.h" 22 #include "setup.h" 23 #include "task.h" 24 25 /** 26 * domain_scope_le - Checks domain ordering for scoped ptrace 27 * 28 * @parent: Parent domain. 29 * @child: Potential child of @parent. 30 * 31 * Checks if the @parent domain is less or equal to (i.e. an ancestor, which 32 * means a subset of) the @child domain. 33 */ 34 static bool domain_scope_le(const struct landlock_ruleset *const parent, 35 const struct landlock_ruleset *const child) 36 { 37 const struct landlock_hierarchy *walker; 38 39 if (!parent) 40 return true; 41 if (!child) 42 return false; 43 for (walker = child->hierarchy; walker; walker = walker->parent) { 44 if (walker == parent->hierarchy) 45 /* @parent is in the scoped hierarchy of @child. */ 46 return true; 47 } 48 /* There is no relationship between @parent and @child. */ 49 return false; 50 } 51 52 static bool task_is_scoped(const struct task_struct *const parent, 53 const struct task_struct *const child) 54 { 55 bool is_scoped; 56 const struct landlock_ruleset *dom_parent, *dom_child; 57 58 rcu_read_lock(); 59 dom_parent = landlock_get_task_domain(parent); 60 dom_child = landlock_get_task_domain(child); 61 is_scoped = domain_scope_le(dom_parent, dom_child); 62 rcu_read_unlock(); 63 return is_scoped; 64 } 65 66 static int task_ptrace(const struct task_struct *const parent, 67 const struct task_struct *const child) 68 { 69 /* Quick return for non-landlocked tasks. */ 70 if (!landlocked(parent)) 71 return 0; 72 if (task_is_scoped(parent, child)) 73 return 0; 74 return -EPERM; 75 } 76 77 /** 78 * hook_ptrace_access_check - Determines whether the current process may access 79 * another 80 * 81 * @child: Process to be accessed. 82 * @mode: Mode of attachment. 83 * 84 * If the current task has Landlock rules, then the child must have at least 85 * the same rules. Else denied. 86 * 87 * Determines whether a process may access another, returning 0 if permission 88 * granted, -errno if denied. 89 */ 90 static int hook_ptrace_access_check(struct task_struct *const child, 91 const unsigned int mode) 92 { 93 return task_ptrace(current, child); 94 } 95 96 /** 97 * hook_ptrace_traceme - Determines whether another process may trace the 98 * current one 99 * 100 * @parent: Task proposed to be the tracer. 101 * 102 * If the parent has Landlock rules, then the current task must have the same 103 * or more rules. Else denied. 104 * 105 * Determines whether the nominated task is permitted to trace the current 106 * process, returning 0 if permission is granted, -errno if denied. 107 */ 108 static int hook_ptrace_traceme(struct task_struct *const parent) 109 { 110 return task_ptrace(parent, current); 111 } 112 113 /** 114 * domain_is_scoped - Checks if the client domain is scoped in the same 115 * domain as the server. 116 * 117 * @client: IPC sender domain. 118 * @server: IPC receiver domain. 119 * @scope: The scope restriction criteria. 120 * 121 * Returns: True if the @client domain is scoped to access the @server, 122 * unless the @server is also scoped in the same domain as @client. 123 */ 124 static bool domain_is_scoped(const struct landlock_ruleset *const client, 125 const struct landlock_ruleset *const server, 126 access_mask_t scope) 127 { 128 int client_layer, server_layer; 129 struct landlock_hierarchy *client_walker, *server_walker; 130 131 /* Quick return if client has no domain */ 132 if (WARN_ON_ONCE(!client)) 133 return false; 134 135 client_layer = client->num_layers - 1; 136 client_walker = client->hierarchy; 137 /* 138 * client_layer must be a signed integer with greater capacity 139 * than client->num_layers to ensure the following loop stops. 140 */ 141 BUILD_BUG_ON(sizeof(client_layer) > sizeof(client->num_layers)); 142 143 server_layer = server ? (server->num_layers - 1) : -1; 144 server_walker = server ? server->hierarchy : NULL; 145 146 /* 147 * Walks client's parent domains down to the same hierarchy level 148 * as the server's domain, and checks that none of these client's 149 * parent domains are scoped. 150 */ 151 for (; client_layer > server_layer; client_layer--) { 152 if (landlock_get_scope_mask(client, client_layer) & scope) 153 return true; 154 155 client_walker = client_walker->parent; 156 } 157 /* 158 * Walks server's parent domains down to the same hierarchy level as 159 * the client's domain. 160 */ 161 for (; server_layer > client_layer; server_layer--) 162 server_walker = server_walker->parent; 163 164 for (; client_layer >= 0; client_layer--) { 165 if (landlock_get_scope_mask(client, client_layer) & scope) { 166 /* 167 * Client and server are at the same level in the 168 * hierarchy. If the client is scoped, the request is 169 * only allowed if this domain is also a server's 170 * ancestor. 171 */ 172 return server_walker != client_walker; 173 } 174 client_walker = client_walker->parent; 175 server_walker = server_walker->parent; 176 } 177 return false; 178 } 179 180 static bool sock_is_scoped(struct sock *const other, 181 const struct landlock_ruleset *const domain) 182 { 183 const struct landlock_ruleset *dom_other; 184 185 /* The credentials will not change. */ 186 lockdep_assert_held(&unix_sk(other)->lock); 187 dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain; 188 return domain_is_scoped(domain, dom_other, 189 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET); 190 } 191 192 static bool is_abstract_socket(struct sock *const sock) 193 { 194 struct unix_address *addr = unix_sk(sock)->addr; 195 196 if (!addr) 197 return false; 198 199 if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 && 200 addr->name->sun_path[0] == '\0') 201 return true; 202 203 return false; 204 } 205 206 static int hook_unix_stream_connect(struct sock *const sock, 207 struct sock *const other, 208 struct sock *const newsk) 209 { 210 const struct landlock_ruleset *const dom = 211 landlock_get_current_domain(); 212 213 /* Quick return for non-landlocked tasks. */ 214 if (!dom) 215 return 0; 216 217 if (is_abstract_socket(other) && sock_is_scoped(other, dom)) 218 return -EPERM; 219 220 return 0; 221 } 222 223 static int hook_unix_may_send(struct socket *const sock, 224 struct socket *const other) 225 { 226 const struct landlock_ruleset *const dom = 227 landlock_get_current_domain(); 228 229 if (!dom) 230 return 0; 231 232 /* 233 * Checks if this datagram socket was already allowed to be connected 234 * to other. 235 */ 236 if (unix_peer(sock->sk) == other->sk) 237 return 0; 238 239 if (is_abstract_socket(other->sk) && sock_is_scoped(other->sk, dom)) 240 return -EPERM; 241 242 return 0; 243 } 244 245 static struct security_hook_list landlock_hooks[] __ro_after_init = { 246 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), 247 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), 248 249 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect), 250 LSM_HOOK_INIT(unix_may_send, hook_unix_may_send), 251 }; 252 253 __init void landlock_add_task_hooks(void) 254 { 255 security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), 256 &landlock_lsmid); 257 } 258