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 int hook_unix_stream_connect(struct sock *const sock, 208 struct sock *const other, 209 struct sock *const newsk) 210 { 211 const struct landlock_ruleset *const dom = 212 landlock_get_current_domain(); 213 214 /* Quick return for non-landlocked tasks. */ 215 if (!dom) 216 return 0; 217 218 if (is_abstract_socket(other) && sock_is_scoped(other, dom)) 219 return -EPERM; 220 221 return 0; 222 } 223 224 static int hook_unix_may_send(struct socket *const sock, 225 struct socket *const other) 226 { 227 const struct landlock_ruleset *const dom = 228 landlock_get_current_domain(); 229 230 if (!dom) 231 return 0; 232 233 /* 234 * Checks if this datagram socket was already allowed to be connected 235 * to other. 236 */ 237 if (unix_peer(sock->sk) == other->sk) 238 return 0; 239 240 if (is_abstract_socket(other->sk) && sock_is_scoped(other->sk, dom)) 241 return -EPERM; 242 243 return 0; 244 } 245 246 static int hook_task_kill(struct task_struct *const p, 247 struct kernel_siginfo *const info, const int sig, 248 const struct cred *const cred) 249 { 250 bool is_scoped; 251 const struct landlock_ruleset *dom; 252 253 if (cred) { 254 /* Dealing with USB IO. */ 255 dom = landlock_cred(cred)->domain; 256 } else { 257 dom = landlock_get_current_domain(); 258 } 259 260 /* Quick return for non-landlocked tasks. */ 261 if (!dom) 262 return 0; 263 264 rcu_read_lock(); 265 is_scoped = domain_is_scoped(dom, landlock_get_task_domain(p), 266 LANDLOCK_SCOPE_SIGNAL); 267 rcu_read_unlock(); 268 if (is_scoped) 269 return -EPERM; 270 271 return 0; 272 } 273 274 static int hook_file_send_sigiotask(struct task_struct *tsk, 275 struct fown_struct *fown, int signum) 276 { 277 const struct landlock_ruleset *dom; 278 bool is_scoped = false; 279 280 /* Lock already held by send_sigio() and send_sigurg(). */ 281 lockdep_assert_held(&fown->lock); 282 dom = landlock_file(fown->file)->fown_domain; 283 284 /* Quick return for unowned socket. */ 285 if (!dom) 286 return 0; 287 288 rcu_read_lock(); 289 is_scoped = domain_is_scoped(dom, landlock_get_task_domain(tsk), 290 LANDLOCK_SCOPE_SIGNAL); 291 rcu_read_unlock(); 292 if (is_scoped) 293 return -EPERM; 294 295 return 0; 296 } 297 298 static struct security_hook_list landlock_hooks[] __ro_after_init = { 299 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), 300 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), 301 302 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect), 303 LSM_HOOK_INIT(unix_may_send, hook_unix_may_send), 304 305 LSM_HOOK_INIT(task_kill, hook_task_kill), 306 LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask), 307 }; 308 309 __init void landlock_add_task_hooks(void) 310 { 311 security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), 312 &landlock_lsmid); 313 } 314