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