77
88#include <kunit/test.h>
99#include <linux/audit.h>
10+ #include <linux/bitops.h>
1011#include <linux/lsm_audit.h>
1112#include <linux/pid.h>
13+ #include <uapi/linux/landlock.h>
1214
1315#include "audit.h"
16+ #include "common.h"
1417#include "cred.h"
1518#include "domain.h"
1619#include "limits.h"
1720#include "ruleset.h"
1821
19- static const char * get_blocker (const enum landlock_request_type type )
22+ static const char * const fs_access_strings [] = {
23+ [BIT_INDEX (LANDLOCK_ACCESS_FS_EXECUTE )] = "fs.execute" ,
24+ [BIT_INDEX (LANDLOCK_ACCESS_FS_WRITE_FILE )] = "fs.write_file" ,
25+ [BIT_INDEX (LANDLOCK_ACCESS_FS_READ_FILE )] = "fs.read_file" ,
26+ [BIT_INDEX (LANDLOCK_ACCESS_FS_READ_DIR )] = "fs.read_dir" ,
27+ [BIT_INDEX (LANDLOCK_ACCESS_FS_REMOVE_DIR )] = "fs.remove_dir" ,
28+ [BIT_INDEX (LANDLOCK_ACCESS_FS_REMOVE_FILE )] = "fs.remove_file" ,
29+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_CHAR )] = "fs.make_char" ,
30+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_DIR )] = "fs.make_dir" ,
31+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_REG )] = "fs.make_reg" ,
32+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_SOCK )] = "fs.make_sock" ,
33+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_FIFO )] = "fs.make_fifo" ,
34+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_BLOCK )] = "fs.make_block" ,
35+ [BIT_INDEX (LANDLOCK_ACCESS_FS_MAKE_SYM )] = "fs.make_sym" ,
36+ [BIT_INDEX (LANDLOCK_ACCESS_FS_REFER )] = "fs.refer" ,
37+ [BIT_INDEX (LANDLOCK_ACCESS_FS_TRUNCATE )] = "fs.truncate" ,
38+ [BIT_INDEX (LANDLOCK_ACCESS_FS_IOCTL_DEV )] = "fs.ioctl_dev" ,
39+ };
40+
41+ static_assert (ARRAY_SIZE (fs_access_strings ) == LANDLOCK_NUM_ACCESS_FS );
42+
43+ static __attribute_const__ const char *
44+ get_blocker (const enum landlock_request_type type ,
45+ const unsigned long access_bit )
2046{
2147 switch (type ) {
2248 case LANDLOCK_REQUEST_PTRACE :
49+ WARN_ON_ONCE (access_bit != -1 );
2350 return "ptrace" ;
2451
2552 case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY :
53+ WARN_ON_ONCE (access_bit != -1 );
2654 return "fs.change_topology" ;
55+
56+ case LANDLOCK_REQUEST_FS_ACCESS :
57+ if (WARN_ON_ONCE (access_bit >= ARRAY_SIZE (fs_access_strings )))
58+ return "unknown" ;
59+ return fs_access_strings [access_bit ];
2760 }
2861
2962 WARN_ON_ONCE (1 );
3063 return "unknown" ;
3164}
3265
3366static void log_blockers (struct audit_buffer * const ab ,
34- const enum landlock_request_type type )
67+ const enum landlock_request_type type ,
68+ const access_mask_t access )
3569{
36- audit_log_format (ab , "%s" , get_blocker (type ));
70+ const unsigned long access_mask = access ;
71+ unsigned long access_bit ;
72+ bool is_first = true;
73+
74+ for_each_set_bit (access_bit , & access_mask , BITS_PER_TYPE (access )) {
75+ audit_log_format (ab , "%s%s" , is_first ? "" : "," ,
76+ get_blocker (type , access_bit ));
77+ is_first = false;
78+ }
79+ if (is_first )
80+ audit_log_format (ab , "%s" , get_blocker (type , -1 ));
3781}
3882
3983static void log_domain (struct landlock_hierarchy * const hierarchy )
@@ -115,12 +159,113 @@ static void test_get_hierarchy(struct kunit *const test)
115159
116160#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
117161
162+ static size_t get_denied_layer (const struct landlock_ruleset * const domain ,
163+ access_mask_t * const access_request ,
164+ const layer_mask_t (* const layer_masks )[],
165+ const size_t layer_masks_size )
166+ {
167+ const unsigned long access_req = * access_request ;
168+ unsigned long access_bit ;
169+ access_mask_t missing = 0 ;
170+ long youngest_layer = -1 ;
171+
172+ for_each_set_bit (access_bit , & access_req , layer_masks_size ) {
173+ const access_mask_t mask = (* layer_masks )[access_bit ];
174+ long layer ;
175+
176+ if (!mask )
177+ continue ;
178+
179+ /* __fls(1) == 0 */
180+ layer = __fls (mask );
181+ if (layer > youngest_layer ) {
182+ youngest_layer = layer ;
183+ missing = BIT (access_bit );
184+ } else if (layer == youngest_layer ) {
185+ missing |= BIT (access_bit );
186+ }
187+ }
188+
189+ * access_request = missing ;
190+ if (youngest_layer == -1 )
191+ return domain -> num_layers - 1 ;
192+
193+ return youngest_layer ;
194+ }
195+
196+ #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
197+
198+ static void test_get_denied_layer (struct kunit * const test )
199+ {
200+ const struct landlock_ruleset dom = {
201+ .num_layers = 5 ,
202+ };
203+ const layer_mask_t layer_masks [LANDLOCK_NUM_ACCESS_FS ] = {
204+ [BIT_INDEX (LANDLOCK_ACCESS_FS_EXECUTE )] = BIT (0 ),
205+ [BIT_INDEX (LANDLOCK_ACCESS_FS_READ_FILE )] = BIT (1 ),
206+ [BIT_INDEX (LANDLOCK_ACCESS_FS_READ_DIR )] = BIT (1 ) | BIT (0 ),
207+ [BIT_INDEX (LANDLOCK_ACCESS_FS_REMOVE_DIR )] = BIT (2 ),
208+ };
209+ access_mask_t access ;
210+
211+ access = LANDLOCK_ACCESS_FS_EXECUTE ;
212+ KUNIT_EXPECT_EQ (test , 0 ,
213+ get_denied_layer (& dom , & access , & layer_masks ,
214+ sizeof (layer_masks )));
215+ KUNIT_EXPECT_EQ (test , access , LANDLOCK_ACCESS_FS_EXECUTE );
216+
217+ access = LANDLOCK_ACCESS_FS_READ_FILE ;
218+ KUNIT_EXPECT_EQ (test , 1 ,
219+ get_denied_layer (& dom , & access , & layer_masks ,
220+ sizeof (layer_masks )));
221+ KUNIT_EXPECT_EQ (test , access , LANDLOCK_ACCESS_FS_READ_FILE );
222+
223+ access = LANDLOCK_ACCESS_FS_READ_DIR ;
224+ KUNIT_EXPECT_EQ (test , 1 ,
225+ get_denied_layer (& dom , & access , & layer_masks ,
226+ sizeof (layer_masks )));
227+ KUNIT_EXPECT_EQ (test , access , LANDLOCK_ACCESS_FS_READ_DIR );
228+
229+ access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR ;
230+ KUNIT_EXPECT_EQ (test , 1 ,
231+ get_denied_layer (& dom , & access , & layer_masks ,
232+ sizeof (layer_masks )));
233+ KUNIT_EXPECT_EQ (test , access ,
234+ LANDLOCK_ACCESS_FS_READ_FILE |
235+ LANDLOCK_ACCESS_FS_READ_DIR );
236+
237+ access = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_DIR ;
238+ KUNIT_EXPECT_EQ (test , 1 ,
239+ get_denied_layer (& dom , & access , & layer_masks ,
240+ sizeof (layer_masks )));
241+ KUNIT_EXPECT_EQ (test , access , LANDLOCK_ACCESS_FS_READ_DIR );
242+
243+ access = LANDLOCK_ACCESS_FS_WRITE_FILE ;
244+ KUNIT_EXPECT_EQ (test , 4 ,
245+ get_denied_layer (& dom , & access , & layer_masks ,
246+ sizeof (layer_masks )));
247+ KUNIT_EXPECT_EQ (test , access , 0 );
248+ }
249+
250+ #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
251+
118252static bool is_valid_request (const struct landlock_request * const request )
119253{
120254 if (WARN_ON_ONCE (request -> layer_plus_one > LANDLOCK_MAX_NUM_LAYERS ))
121255 return false;
122256
123- if (WARN_ON_ONCE (!request -> layer_plus_one ))
257+ if (WARN_ON_ONCE (!(!!request -> layer_plus_one ^ !!request -> access )))
258+ return false;
259+
260+ if (request -> access ) {
261+ if (WARN_ON_ONCE (!request -> layer_masks ))
262+ return false;
263+ } else {
264+ if (WARN_ON_ONCE (request -> layer_masks ))
265+ return false;
266+ }
267+
268+ if (WARN_ON_ONCE (!!request -> layer_masks ^ !!request -> layer_masks_size ))
124269 return false;
125270
126271 return true;
@@ -138,6 +283,7 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
138283 struct audit_buffer * ab ;
139284 struct landlock_hierarchy * youngest_denied ;
140285 size_t youngest_layer ;
286+ access_mask_t missing ;
141287
142288 if (WARN_ON_ONCE (!subject || !subject -> domain ||
143289 !subject -> domain -> hierarchy || !request ))
@@ -146,8 +292,25 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
146292 if (!is_valid_request (request ))
147293 return ;
148294
149- youngest_layer = request -> layer_plus_one - 1 ;
150- youngest_denied = get_hierarchy (subject -> domain , youngest_layer );
295+ missing = request -> access ;
296+ if (missing ) {
297+ /* Gets the nearest domain that denies the request. */
298+ if (request -> layer_masks ) {
299+ youngest_layer = get_denied_layer (
300+ subject -> domain , & missing , request -> layer_masks ,
301+ request -> layer_masks_size );
302+ } else {
303+ /* This will change with the next commit. */
304+ WARN_ON_ONCE (1 );
305+ youngest_layer = subject -> domain -> num_layers ;
306+ }
307+ youngest_denied =
308+ get_hierarchy (subject -> domain , youngest_layer );
309+ } else {
310+ youngest_layer = request -> layer_plus_one - 1 ;
311+ youngest_denied =
312+ get_hierarchy (subject -> domain , youngest_layer );
313+ }
151314
152315 /*
153316 * Consistently keeps track of the number of denied access requests
@@ -171,7 +334,7 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
171334 return ;
172335
173336 audit_log_format (ab , "domain=%llx blockers=" , youngest_denied -> id );
174- log_blockers (ab , request -> type );
337+ log_blockers (ab , request -> type , missing );
175338 audit_log_lsm_data (ab , & request -> audit );
176339 audit_log_end (ab );
177340
@@ -223,6 +386,7 @@ void landlock_log_drop_domain(const struct landlock_hierarchy *const hierarchy)
223386static struct kunit_case test_cases [] = {
224387 /* clang-format off */
225388 KUNIT_CASE (test_get_hierarchy ),
389+ KUNIT_CASE (test_get_denied_layer ),
226390 {}
227391 /* clang-format on */
228392};
0 commit comments