Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Landlock LSM - Ptrace hooks
0004  *
0005  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
0006  * Copyright © 2019-2020 ANSSI
0007  */
0008 
0009 #include <asm/current.h>
0010 #include <linux/cred.h>
0011 #include <linux/errno.h>
0012 #include <linux/kernel.h>
0013 #include <linux/lsm_hooks.h>
0014 #include <linux/rcupdate.h>
0015 #include <linux/sched.h>
0016 
0017 #include "common.h"
0018 #include "cred.h"
0019 #include "ptrace.h"
0020 #include "ruleset.h"
0021 #include "setup.h"
0022 
0023 /**
0024  * domain_scope_le - Checks domain ordering for scoped ptrace
0025  *
0026  * @parent: Parent domain.
0027  * @child: Potential child of @parent.
0028  *
0029  * Checks if the @parent domain is less or equal to (i.e. an ancestor, which
0030  * means a subset of) the @child domain.
0031  */
0032 static bool domain_scope_le(const struct landlock_ruleset *const parent,
0033                 const struct landlock_ruleset *const child)
0034 {
0035     const struct landlock_hierarchy *walker;
0036 
0037     if (!parent)
0038         return true;
0039     if (!child)
0040         return false;
0041     for (walker = child->hierarchy; walker; walker = walker->parent) {
0042         if (walker == parent->hierarchy)
0043             /* @parent is in the scoped hierarchy of @child. */
0044             return true;
0045     }
0046     /* There is no relationship between @parent and @child. */
0047     return false;
0048 }
0049 
0050 static bool task_is_scoped(const struct task_struct *const parent,
0051                const struct task_struct *const child)
0052 {
0053     bool is_scoped;
0054     const struct landlock_ruleset *dom_parent, *dom_child;
0055 
0056     rcu_read_lock();
0057     dom_parent = landlock_get_task_domain(parent);
0058     dom_child = landlock_get_task_domain(child);
0059     is_scoped = domain_scope_le(dom_parent, dom_child);
0060     rcu_read_unlock();
0061     return is_scoped;
0062 }
0063 
0064 static int task_ptrace(const struct task_struct *const parent,
0065                const struct task_struct *const child)
0066 {
0067     /* Quick return for non-landlocked tasks. */
0068     if (!landlocked(parent))
0069         return 0;
0070     if (task_is_scoped(parent, child))
0071         return 0;
0072     return -EPERM;
0073 }
0074 
0075 /**
0076  * hook_ptrace_access_check - Determines whether the current process may access
0077  *                another
0078  *
0079  * @child: Process to be accessed.
0080  * @mode: Mode of attachment.
0081  *
0082  * If the current task has Landlock rules, then the child must have at least
0083  * the same rules.  Else denied.
0084  *
0085  * Determines whether a process may access another, returning 0 if permission
0086  * granted, -errno if denied.
0087  */
0088 static int hook_ptrace_access_check(struct task_struct *const child,
0089                     const unsigned int mode)
0090 {
0091     return task_ptrace(current, child);
0092 }
0093 
0094 /**
0095  * hook_ptrace_traceme - Determines whether another process may trace the
0096  *           current one
0097  *
0098  * @parent: Task proposed to be the tracer.
0099  *
0100  * If the parent has Landlock rules, then the current task must have the same
0101  * or more rules.  Else denied.
0102  *
0103  * Determines whether the nominated task is permitted to trace the current
0104  * process, returning 0 if permission is granted, -errno if denied.
0105  */
0106 static int hook_ptrace_traceme(struct task_struct *const parent)
0107 {
0108     return task_ptrace(parent, current);
0109 }
0110 
0111 static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = {
0112     LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
0113     LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
0114 };
0115 
0116 __init void landlock_add_ptrace_hooks(void)
0117 {
0118     security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
0119                LANDLOCK_NAME);
0120 }