ptrace.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Landlock LSM - Ptrace hooks
  4. *
  5. * Copyright © 2017-2020 Mickaël Salaün <[email protected]>
  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 "common.h"
  16. #include "cred.h"
  17. #include "ptrace.h"
  18. #include "ruleset.h"
  19. #include "setup.h"
  20. /**
  21. * domain_scope_le - Checks domain ordering for scoped ptrace
  22. *
  23. * @parent: Parent domain.
  24. * @child: Potential child of @parent.
  25. *
  26. * Checks if the @parent domain is less or equal to (i.e. an ancestor, which
  27. * means a subset of) the @child domain.
  28. */
  29. static bool domain_scope_le(const struct landlock_ruleset *const parent,
  30. const struct landlock_ruleset *const child)
  31. {
  32. const struct landlock_hierarchy *walker;
  33. if (!parent)
  34. return true;
  35. if (!child)
  36. return false;
  37. for (walker = child->hierarchy; walker; walker = walker->parent) {
  38. if (walker == parent->hierarchy)
  39. /* @parent is in the scoped hierarchy of @child. */
  40. return true;
  41. }
  42. /* There is no relationship between @parent and @child. */
  43. return false;
  44. }
  45. static bool task_is_scoped(const struct task_struct *const parent,
  46. const struct task_struct *const child)
  47. {
  48. bool is_scoped;
  49. const struct landlock_ruleset *dom_parent, *dom_child;
  50. rcu_read_lock();
  51. dom_parent = landlock_get_task_domain(parent);
  52. dom_child = landlock_get_task_domain(child);
  53. is_scoped = domain_scope_le(dom_parent, dom_child);
  54. rcu_read_unlock();
  55. return is_scoped;
  56. }
  57. static int task_ptrace(const struct task_struct *const parent,
  58. const struct task_struct *const child)
  59. {
  60. /* Quick return for non-landlocked tasks. */
  61. if (!landlocked(parent))
  62. return 0;
  63. if (task_is_scoped(parent, child))
  64. return 0;
  65. return -EPERM;
  66. }
  67. /**
  68. * hook_ptrace_access_check - Determines whether the current process may access
  69. * another
  70. *
  71. * @child: Process to be accessed.
  72. * @mode: Mode of attachment.
  73. *
  74. * If the current task has Landlock rules, then the child must have at least
  75. * the same rules. Else denied.
  76. *
  77. * Determines whether a process may access another, returning 0 if permission
  78. * granted, -errno if denied.
  79. */
  80. static int hook_ptrace_access_check(struct task_struct *const child,
  81. const unsigned int mode)
  82. {
  83. return task_ptrace(current, child);
  84. }
  85. /**
  86. * hook_ptrace_traceme - Determines whether another process may trace the
  87. * current one
  88. *
  89. * @parent: Task proposed to be the tracer.
  90. *
  91. * If the parent has Landlock rules, then the current task must have the same
  92. * or more rules. Else denied.
  93. *
  94. * Determines whether the nominated task is permitted to trace the current
  95. * process, returning 0 if permission is granted, -errno if denied.
  96. */
  97. static int hook_ptrace_traceme(struct task_struct *const parent)
  98. {
  99. return task_ptrace(parent, current);
  100. }
  101. static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = {
  102. LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
  103. LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
  104. };
  105. __init void landlock_add_ptrace_hooks(void)
  106. {
  107. security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
  108. LANDLOCK_NAME);
  109. }