task.c 8.5 KB

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