1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Landlock - Credential hooks
4 *
5 * Copyright © 2019-2020 Mickaël Salaün <mic@digikod.net>
6 * Copyright © 2019-2020 ANSSI
7 * Copyright © 2021-2025 Microsoft Corporation
8 */
9
10 #ifndef _SECURITY_LANDLOCK_CRED_H
11 #define _SECURITY_LANDLOCK_CRED_H
12
13 #include <linux/container_of.h>
14 #include <linux/cred.h>
15 #include <linux/init.h>
16 #include <linux/rcupdate.h>
17
18 #include "access.h"
19 #include "limits.h"
20 #include "ruleset.h"
21 #include "setup.h"
22
23 /**
24 * struct landlock_cred_security - Credential security blob
25 *
26 * This structure is packed to minimize the size of struct
27 * landlock_file_security. However, it is always aligned in the LSM cred blob,
28 * see lsm_set_blob_size().
29 *
30 * When updating this, also update landlock_cred_copy() if needed.
31 */
32 struct landlock_cred_security {
33 /**
34 * @domain: Immutable ruleset enforced on a task.
35 */
36 struct landlock_ruleset *domain;
37
38 #ifdef CONFIG_AUDIT
39 /**
40 * @domain_exec: Bitmask identifying the domain layers that were enforced by
41 * the current task's executed file (i.e. no new execve(2) since
42 * landlock_restrict_self(2)).
43 */
44 u16 domain_exec;
45 /**
46 * @log_subdomains_off: Set if the domain descendants's log_status should be
47 * set to %LANDLOCK_LOG_DISABLED. This is not a landlock_hierarchy
48 * configuration because it applies to future descendant domains and it does
49 * not require a current domain.
50 */
51 u8 log_subdomains_off : 1;
52 #endif /* CONFIG_AUDIT */
53 } __packed;
54
55 #ifdef CONFIG_AUDIT
56
57 /* Makes sure all layer executions can be stored. */
58 static_assert(BITS_PER_TYPE(typeof_member(struct landlock_cred_security,
59 domain_exec)) >=
60 LANDLOCK_MAX_NUM_LAYERS);
61
62 #endif /* CONFIG_AUDIT */
63
64 static inline struct landlock_cred_security *
landlock_cred(const struct cred * cred)65 landlock_cred(const struct cred *cred)
66 {
67 return cred->security + landlock_blob_sizes.lbs_cred;
68 }
69
landlock_cred_copy(struct landlock_cred_security * dst,const struct landlock_cred_security * src)70 static inline void landlock_cred_copy(struct landlock_cred_security *dst,
71 const struct landlock_cred_security *src)
72 {
73 landlock_put_ruleset(dst->domain);
74
75 *dst = *src;
76
77 landlock_get_ruleset(src->domain);
78 }
79
landlock_get_current_domain(void)80 static inline struct landlock_ruleset *landlock_get_current_domain(void)
81 {
82 return landlock_cred(current_cred())->domain;
83 }
84
85 /*
86 * The call needs to come from an RCU read-side critical section.
87 */
88 static inline const struct landlock_ruleset *
landlock_get_task_domain(const struct task_struct * const task)89 landlock_get_task_domain(const struct task_struct *const task)
90 {
91 return landlock_cred(__task_cred(task))->domain;
92 }
93
landlocked(const struct task_struct * const task)94 static inline bool landlocked(const struct task_struct *const task)
95 {
96 bool has_dom;
97
98 if (task == current)
99 return !!landlock_get_current_domain();
100
101 rcu_read_lock();
102 has_dom = !!landlock_get_task_domain(task);
103 rcu_read_unlock();
104 return has_dom;
105 }
106
107 /**
108 * landlock_get_applicable_subject - Return the subject's Landlock credential
109 * if its enforced domain applies to (i.e.
110 * handles) at least one of the access rights
111 * specified in @masks
112 *
113 * @cred: credential
114 * @masks: access masks
115 * @handle_layer: returned youngest layer handling a subset of @masks. Not set
116 * if the function returns NULL.
117 *
118 * Return: landlock_cred(@cred) if any access rights specified in @masks is
119 * handled, or NULL otherwise.
120 */
121 static inline const struct landlock_cred_security *
landlock_get_applicable_subject(const struct cred * const cred,const struct access_masks masks,size_t * const handle_layer)122 landlock_get_applicable_subject(const struct cred *const cred,
123 const struct access_masks masks,
124 size_t *const handle_layer)
125 {
126 const union access_masks_all masks_all = {
127 .masks = masks,
128 };
129 const struct landlock_ruleset *domain;
130 ssize_t layer_level;
131
132 if (!cred)
133 return NULL;
134
135 domain = landlock_cred(cred)->domain;
136 if (!domain)
137 return NULL;
138
139 for (layer_level = domain->num_layers - 1; layer_level >= 0;
140 layer_level--) {
141 union access_masks_all layer = {
142 .masks = domain->access_masks[layer_level],
143 };
144
145 if (layer.all & masks_all.all) {
146 if (handle_layer)
147 *handle_layer = layer_level;
148
149 return landlock_cred(cred);
150 }
151 }
152
153 return NULL;
154 }
155
156 __init void landlock_add_cred_hooks(void);
157
158 #endif /* _SECURITY_LANDLOCK_CRED_H */
159