summaryrefslogtreecommitdiff
path: root/security/landlock/ruleset.h
blob: b536fa0425b7a58eeb05a3acb42b5ef64d382b2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Landlock LSM - Ruleset management
 *
 * Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
 * Copyright © 2018-2020 ANSSI
 * Copyright © 2026 Cloudflare, Inc.
 */

#ifndef _SECURITY_LANDLOCK_RULESET_H
#define _SECURITY_LANDLOCK_RULESET_H

#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/refcount.h>

#include "access.h"
#include "limits.h"
#include "object.h"

/**
 * struct landlock_layer - Access rights for a given layer
 */
struct landlock_layer {
	/**
	 * @level: Position of this layer in the layer stack.  Starts from 1.
	 */
	u8 level;
	/**
	 * @flags: Bitfield for special flags attached to this rule.
	 */
	struct {
		/**
		 * @flags.quiet: Suppresses denial logs for the object covered by
		 * this rule in this domain.  For filesystem rules, this inherits
		 * down the file hierarchy.
		 */
		u8 quiet : 1;
	} flags;
	/**
	 * @access: Bitfield of allowed actions on the kernel object.  They are
	 * relative to the object type (e.g. %LANDLOCK_ACTION_FS_READ).
	 */
	access_mask_t access;
};

/**
 * union landlock_key - Key of a ruleset's red-black tree
 */
union landlock_key {
	/**
	 * @object: Pointer to identify a kernel object (e.g. an inode).
	 */
	struct landlock_object *object;
	/**
	 * @data: Raw data to identify an arbitrary 32-bit value
	 * (e.g. a TCP port).
	 */
	uintptr_t data;
};

/**
 * enum landlock_key_type - Type of &union landlock_key
 */
enum landlock_key_type {
	/**
	 * @LANDLOCK_KEY_INODE: Type of &landlock_rules.root_inode's node keys.
	 */
	LANDLOCK_KEY_INODE = 1,
	/**
	 * @LANDLOCK_KEY_NET_PORT: Type of &landlock_rules.root_net_port's node
	 * keys.
	 */
	LANDLOCK_KEY_NET_PORT,
};

/**
 * struct landlock_id - Unique rule identifier for a ruleset
 */
struct landlock_id {
	/**
	 * @key: Identifies either a kernel object (e.g. an inode) or
	 * a raw value (e.g. a TCP port).
	 */
	union landlock_key key;
	/**
	 * @type: Type of a landlock_ruleset's root tree.
	 */
	const enum landlock_key_type type;
};

/**
 * struct landlock_rule - Access rights tied to an object
 */
struct landlock_rule {
	/**
	 * @node: Node in the ruleset's red-black tree.
	 */
	struct rb_node node;
	/**
	 * @key: A union to identify either a kernel object (e.g. an inode) or
	 * a raw data value (e.g. a network socket port). This is used as a key
	 * for this ruleset element.  The pointer is set once and never
	 * modified.  It always points to an allocated object because each rule
	 * increments the refcount of its object.
	 */
	union landlock_key key;
	/**
	 * @num_layers: Number of entries in @layers.
	 */
	u32 num_layers;
	/**
	 * @layers: Stack of layers, from the latest to the newest, implemented
	 * as a flexible array member (FAM).
	 */
	struct landlock_layer layers[] __counted_by(num_layers);
};

/**
 * struct landlock_rules - Red-black tree storage for Landlock rules
 *
 * This structure holds the rule trees shared by both rulesets and domains.
 */
struct landlock_rules {
	/**
	 * @root_inode: Root of a red-black tree containing &struct
	 * landlock_rule nodes with inode object.  Immutable for domains.
	 */
	struct rb_root root_inode;

#if IS_ENABLED(CONFIG_INET)
	/**
	 * @root_net_port: Root of a red-black tree containing &struct
	 * landlock_rule nodes with network port.  Immutable for domains.
	 */
	struct rb_root root_net_port;
#endif /* IS_ENABLED(CONFIG_INET) */

	/**
	 * @num_rules: Number of non-overlapping (i.e. not for the same object)
	 * rules in this tree storage.
	 */
	u32 num_rules;
};

/**
 * struct landlock_ruleset - Landlock ruleset
 *
 * This data structure must contain unique entries, be updatable, and quick to
 * match an object.
 */
struct landlock_ruleset {
	/**
	 * @rules: Red-black tree storage for rules.
	 */
	struct landlock_rules rules;
	/**
	 * @lock: Protects against concurrent modifications of @rules, if @usage
	 * is greater than zero.
	 */
	struct mutex lock;
	/**
	 * @usage: Number of file descriptors referencing this ruleset.
	 */
	refcount_t usage;

#ifdef CONFIG_TRACEPOINTS
	/**
	 * @version: Counter incremented on each successful
	 * landlock_add_rule(2), including when it only extends an existing
	 * rule's access rights.  Used by tracepoints to correlate a domain with
	 * the exact ruleset state it was created from.  Protected by @lock.
	 */
	u32 version;
	/**
	 * @id: Unique identifier for this ruleset, used for tracing.
	 */
	u64 id;
#endif /* CONFIG_TRACEPOINTS */

	/**
	 * @quiet_masks: Stores the quiet flags for an unmerged ruleset.  For a
	 * merged domain, this is stored in each layer's struct
	 * landlock_hierarchy instead.
	 */
	struct access_masks quiet_masks;
	/**
	 * @handled_masks: Contains the subset of filesystem and network actions
	 * that are handled by this ruleset.
	 */
	struct access_masks handled_masks;
};

struct landlock_ruleset *
landlock_create_ruleset(const access_mask_t access_mask_fs,
			const access_mask_t access_mask_net,
			const access_mask_t scope_mask);

void landlock_put_ruleset(struct landlock_ruleset *const ruleset);

DEFINE_FREE(landlock_put_ruleset, struct landlock_ruleset *,
	    if (!IS_ERR_OR_NULL(_T)) landlock_put_ruleset(_T))

int landlock_insert_rule(struct landlock_ruleset *const ruleset,
			 const struct landlock_id id,
			 const access_mask_t access, const u32 flags);

int landlock_store_rule(struct landlock_rules *const rules,
			const struct landlock_id id,
			const struct landlock_layer (*layers)[],
			const size_t num_layers);

void landlock_free_rules(struct landlock_rules *const rules);

/**
 * landlock_get_rule_root - Get the root of a rule tree by key type
 *
 * @rules: The rules storage to look up.
 * @key_type: The type of key to select the tree for.
 *
 * Return: A pointer to the rb_root, or ERR_PTR(-EINVAL) on unknown type.
 */
static inline struct rb_root *
landlock_get_rule_root(struct landlock_rules *const rules,
		       const enum landlock_key_type key_type)
{
	switch (key_type) {
	case LANDLOCK_KEY_INODE:
		return &rules->root_inode;

#if IS_ENABLED(CONFIG_INET)
	case LANDLOCK_KEY_NET_PORT:
		return &rules->root_net_port;
#endif /* IS_ENABLED(CONFIG_INET) */

	default:
		WARN_ON_ONCE(1);
		return ERR_PTR(-EINVAL);
	}
}

static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
{
	if (ruleset)
		refcount_inc(&ruleset->usage);
}

#endif /* _SECURITY_LANDLOCK_RULESET_H */