5
5
* Copyright © 2016-2020 Mickaël Salaün <[email protected] >
6
6
* Copyright © 2018-2020 ANSSI
7
7
* Copyright © 2021-2022 Microsoft Corporation
8
+ * Copyright © 2022 Günther Noack <[email protected] >
9
+ * Copyright © 2023-2024 Google LLC
8
10
*/
9
11
12
+ #include <asm/ioctls.h>
10
13
#include <kunit/test.h>
11
14
#include <linux/atomic.h>
12
15
#include <linux/bitops.h>
13
16
#include <linux/bits.h>
14
17
#include <linux/compiler_types.h>
15
18
#include <linux/dcache.h>
16
19
#include <linux/err.h>
20
+ #include <linux/falloc.h>
17
21
#include <linux/fs.h>
18
22
#include <linux/init.h>
19
23
#include <linux/kernel.h>
29
33
#include <linux/types.h>
30
34
#include <linux/wait_bit.h>
31
35
#include <linux/workqueue.h>
36
+ #include <uapi/linux/fiemap.h>
32
37
#include <uapi/linux/landlock.h>
33
38
34
39
#include "common.h"
@@ -84,6 +89,160 @@ static const struct landlock_object_underops landlock_fs_underops = {
84
89
.release = release_inode
85
90
};
86
91
92
+ /* IOCTL helpers */
93
+
94
+ /**
95
+ * is_masked_device_ioctl - Determine whether an IOCTL command is always
96
+ * permitted with Landlock for device files. These commands can not be
97
+ * restricted on device files by enforcing a Landlock policy.
98
+ *
99
+ * @cmd: The IOCTL command that is supposed to be run.
100
+ *
101
+ * By default, any IOCTL on a device file requires the
102
+ * LANDLOCK_ACCESS_FS_IOCTL_DEV right. However, we blanket-permit some
103
+ * commands, if:
104
+ *
105
+ * 1. The command is implemented in fs/ioctl.c's do_vfs_ioctl(),
106
+ * not in f_ops->unlocked_ioctl() or f_ops->compat_ioctl().
107
+ *
108
+ * 2. The command is harmless when invoked on devices.
109
+ *
110
+ * We also permit commands that do not make sense for devices, but where the
111
+ * do_vfs_ioctl() implementation returns a more conventional error code.
112
+ *
113
+ * Any new IOCTL commands that are implemented in fs/ioctl.c's do_vfs_ioctl()
114
+ * should be considered for inclusion here.
115
+ *
116
+ * Returns: true if the IOCTL @cmd can not be restricted with Landlock for
117
+ * device files.
118
+ */
119
+ static __attribute_const__ bool is_masked_device_ioctl (const unsigned int cmd )
120
+ {
121
+ switch (cmd ) {
122
+ /*
123
+ * FIOCLEX, FIONCLEX, FIONBIO and FIOASYNC manipulate the FD's
124
+ * close-on-exec and the file's buffered-IO and async flags. These
125
+ * operations are also available through fcntl(2), and are
126
+ * unconditionally permitted in Landlock.
127
+ */
128
+ case FIOCLEX :
129
+ case FIONCLEX :
130
+ case FIONBIO :
131
+ case FIOASYNC :
132
+ /*
133
+ * FIOQSIZE queries the size of a regular file, directory, or link.
134
+ *
135
+ * We still permit it, because it always returns -ENOTTY for
136
+ * other file types.
137
+ */
138
+ case FIOQSIZE :
139
+ /*
140
+ * FIFREEZE and FITHAW freeze and thaw the file system which the
141
+ * given file belongs to. Requires CAP_SYS_ADMIN.
142
+ *
143
+ * These commands operate on the file system's superblock rather
144
+ * than on the file itself. The same operations can also be
145
+ * done through any other file or directory on the same file
146
+ * system, so it is safe to permit these.
147
+ */
148
+ case FIFREEZE :
149
+ case FITHAW :
150
+ /*
151
+ * FS_IOC_FIEMAP queries information about the allocation of
152
+ * blocks within a file.
153
+ *
154
+ * This IOCTL command only makes sense for regular files and is
155
+ * not implemented by devices. It is harmless to permit.
156
+ */
157
+ case FS_IOC_FIEMAP :
158
+ /*
159
+ * FIGETBSZ queries the file system's block size for a file or
160
+ * directory.
161
+ *
162
+ * This command operates on the file system's superblock rather
163
+ * than on the file itself. The same operation can also be done
164
+ * through any other file or directory on the same file system,
165
+ * so it is safe to permit it.
166
+ */
167
+ case FIGETBSZ :
168
+ /*
169
+ * FICLONE, FICLONERANGE and FIDEDUPERANGE make files share
170
+ * their underlying storage ("reflink") between source and
171
+ * destination FDs, on file systems which support that.
172
+ *
173
+ * These IOCTL commands only apply to regular files
174
+ * and are harmless to permit for device files.
175
+ */
176
+ case FICLONE :
177
+ case FICLONERANGE :
178
+ case FIDEDUPERANGE :
179
+ /*
180
+ * FS_IOC_GETFSUUID and FS_IOC_GETFSSYSFSPATH both operate on
181
+ * the file system superblock, not on the specific file, so
182
+ * these operations are available through any other file on the
183
+ * same file system as well.
184
+ */
185
+ case FS_IOC_GETFSUUID :
186
+ case FS_IOC_GETFSSYSFSPATH :
187
+ return true;
188
+
189
+ /*
190
+ * FIONREAD, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_IOC_FSGETXATTR and
191
+ * FS_IOC_FSSETXATTR are forwarded to device implementations.
192
+ */
193
+
194
+ /*
195
+ * file_ioctl() commands (FIBMAP, FS_IOC_RESVSP, FS_IOC_RESVSP64,
196
+ * FS_IOC_UNRESVSP, FS_IOC_UNRESVSP64 and FS_IOC_ZERO_RANGE) are
197
+ * forwarded to device implementations, so not permitted.
198
+ */
199
+
200
+ /* Other commands are guarded by the access right. */
201
+ default :
202
+ return false;
203
+ }
204
+ }
205
+
206
+ /*
207
+ * is_masked_device_ioctl_compat - same as the helper above, but checking the
208
+ * "compat" IOCTL commands.
209
+ *
210
+ * The IOCTL commands with special handling in compat-mode should behave the
211
+ * same as their non-compat counterparts.
212
+ */
213
+ static __attribute_const__ bool
214
+ is_masked_device_ioctl_compat (const unsigned int cmd )
215
+ {
216
+ switch (cmd ) {
217
+ /* FICLONE is permitted, same as in the non-compat variant. */
218
+ case FICLONE :
219
+ return true;
220
+
221
+ #if defined(CONFIG_X86_64 )
222
+ /*
223
+ * FS_IOC_RESVSP_32, FS_IOC_RESVSP64_32, FS_IOC_UNRESVSP_32,
224
+ * FS_IOC_UNRESVSP64_32, FS_IOC_ZERO_RANGE_32: not blanket-permitted,
225
+ * for consistency with their non-compat variants.
226
+ */
227
+ case FS_IOC_RESVSP_32 :
228
+ case FS_IOC_RESVSP64_32 :
229
+ case FS_IOC_UNRESVSP_32 :
230
+ case FS_IOC_UNRESVSP64_32 :
231
+ case FS_IOC_ZERO_RANGE_32 :
232
+ #endif
233
+
234
+ /*
235
+ * FS_IOC32_GETFLAGS, FS_IOC32_SETFLAGS are forwarded to their device
236
+ * implementations.
237
+ */
238
+ case FS_IOC32_GETFLAGS :
239
+ case FS_IOC32_SETFLAGS :
240
+ return false;
241
+ default :
242
+ return is_masked_device_ioctl (cmd );
243
+ }
244
+ }
245
+
87
246
/* Ruleset management */
88
247
89
248
static struct landlock_object * get_inode_object (struct inode * const inode )
@@ -148,7 +307,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
148
307
LANDLOCK_ACCESS_FS_EXECUTE | \
149
308
LANDLOCK_ACCESS_FS_WRITE_FILE | \
150
309
LANDLOCK_ACCESS_FS_READ_FILE | \
151
- LANDLOCK_ACCESS_FS_TRUNCATE)
310
+ LANDLOCK_ACCESS_FS_TRUNCATE | \
311
+ LANDLOCK_ACCESS_FS_IOCTL_DEV)
152
312
/* clang-format on */
153
313
154
314
/*
@@ -1332,11 +1492,18 @@ static int hook_file_alloc_security(struct file *const file)
1332
1492
return 0 ;
1333
1493
}
1334
1494
1495
+ static bool is_device (const struct file * const file )
1496
+ {
1497
+ const struct inode * inode = file_inode (file );
1498
+
1499
+ return S_ISBLK (inode -> i_mode ) || S_ISCHR (inode -> i_mode );
1500
+ }
1501
+
1335
1502
static int hook_file_open (struct file * const file )
1336
1503
{
1337
1504
layer_mask_t layer_masks [LANDLOCK_NUM_ACCESS_FS ] = {};
1338
- access_mask_t open_access_request , full_access_request , allowed_access ;
1339
- const access_mask_t optional_access = LANDLOCK_ACCESS_FS_TRUNCATE ;
1505
+ access_mask_t open_access_request , full_access_request , allowed_access ,
1506
+ optional_access ;
1340
1507
const struct landlock_ruleset * const dom =
1341
1508
get_fs_domain (landlock_cred (file -> f_cred )-> domain );
1342
1509
@@ -1354,6 +1521,10 @@ static int hook_file_open(struct file *const file)
1354
1521
* We look up more access than what we immediately need for open(), so
1355
1522
* that we can later authorize operations on opened files.
1356
1523
*/
1524
+ optional_access = LANDLOCK_ACCESS_FS_TRUNCATE ;
1525
+ if (is_device (file ))
1526
+ optional_access |= LANDLOCK_ACCESS_FS_IOCTL_DEV ;
1527
+
1357
1528
full_access_request = open_access_request | optional_access ;
1358
1529
1359
1530
if (is_access_to_paths_allowed (
@@ -1410,6 +1581,52 @@ static int hook_file_truncate(struct file *const file)
1410
1581
return - EACCES ;
1411
1582
}
1412
1583
1584
+ static int hook_file_ioctl (struct file * file , unsigned int cmd ,
1585
+ unsigned long arg )
1586
+ {
1587
+ access_mask_t allowed_access = landlock_file (file )-> allowed_access ;
1588
+
1589
+ /*
1590
+ * It is the access rights at the time of opening the file which
1591
+ * determine whether IOCTL can be used on the opened file later.
1592
+ *
1593
+ * The access right is attached to the opened file in hook_file_open().
1594
+ */
1595
+ if (allowed_access & LANDLOCK_ACCESS_FS_IOCTL_DEV )
1596
+ return 0 ;
1597
+
1598
+ if (!is_device (file ))
1599
+ return 0 ;
1600
+
1601
+ if (is_masked_device_ioctl (cmd ))
1602
+ return 0 ;
1603
+
1604
+ return - EACCES ;
1605
+ }
1606
+
1607
+ static int hook_file_ioctl_compat (struct file * file , unsigned int cmd ,
1608
+ unsigned long arg )
1609
+ {
1610
+ access_mask_t allowed_access = landlock_file (file )-> allowed_access ;
1611
+
1612
+ /*
1613
+ * It is the access rights at the time of opening the file which
1614
+ * determine whether IOCTL can be used on the opened file later.
1615
+ *
1616
+ * The access right is attached to the opened file in hook_file_open().
1617
+ */
1618
+ if (allowed_access & LANDLOCK_ACCESS_FS_IOCTL_DEV )
1619
+ return 0 ;
1620
+
1621
+ if (!is_device (file ))
1622
+ return 0 ;
1623
+
1624
+ if (is_masked_device_ioctl_compat (cmd ))
1625
+ return 0 ;
1626
+
1627
+ return - EACCES ;
1628
+ }
1629
+
1413
1630
static struct security_hook_list landlock_hooks [] __ro_after_init = {
1414
1631
LSM_HOOK_INIT (inode_free_security , hook_inode_free_security ),
1415
1632
@@ -1432,6 +1649,8 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
1432
1649
LSM_HOOK_INIT (file_alloc_security , hook_file_alloc_security ),
1433
1650
LSM_HOOK_INIT (file_open , hook_file_open ),
1434
1651
LSM_HOOK_INIT (file_truncate , hook_file_truncate ),
1652
+ LSM_HOOK_INIT (file_ioctl , hook_file_ioctl ),
1653
+ LSM_HOOK_INIT (file_ioctl_compat , hook_file_ioctl_compat ),
1435
1654
};
1436
1655
1437
1656
__init void landlock_add_fs_hooks (void )
0 commit comments