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