55 * Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
66 * Copyright © 2018-2020 ANSSI
77 * Copyright © 2021-2022 Microsoft Corporation
8+ * Copyright © 2022 Günther Noack <gnoack3000@gmail.com>
9+ * Copyright © 2023-2024 Google LLC
810 */
911
12+ #include <asm/ioctls.h>
1013#include <kunit/test.h>
1114#include <linux/atomic.h>
1215#include <linux/bitops.h>
1316#include <linux/bits.h>
1417#include <linux/compiler_types.h>
1518#include <linux/dcache.h>
1619#include <linux/err.h>
20+ #include <linux/falloc.h>
1721#include <linux/fs.h>
1822#include <linux/init.h>
1923#include <linux/kernel.h>
2933#include <linux/types.h>
3034#include <linux/wait_bit.h>
3135#include <linux/workqueue.h>
36+ #include <uapi/linux/fiemap.h>
3237#include <uapi/linux/landlock.h>
3338
3439#include "common.h"
@@ -84,6 +89,160 @@ static const struct landlock_object_underops landlock_fs_underops = {
8489 .release = release_inode
8590};
8691
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+
87246/* Ruleset management */
88247
89248static 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)
148307 LANDLOCK_ACCESS_FS_EXECUTE | \
149308 LANDLOCK_ACCESS_FS_WRITE_FILE | \
150309 LANDLOCK_ACCESS_FS_READ_FILE | \
151- LANDLOCK_ACCESS_FS_TRUNCATE)
310+ LANDLOCK_ACCESS_FS_TRUNCATE | \
311+ LANDLOCK_ACCESS_FS_IOCTL_DEV)
152312/* clang-format on */
153313
154314/*
@@ -1332,11 +1492,18 @@ static int hook_file_alloc_security(struct file *const file)
13321492 return 0 ;
13331493}
13341494
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+
13351502static int hook_file_open (struct file * const file )
13361503{
13371504 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 ;
13401507 const struct landlock_ruleset * const dom =
13411508 get_fs_domain (landlock_cred (file -> f_cred )-> domain );
13421509
@@ -1354,6 +1521,10 @@ static int hook_file_open(struct file *const file)
13541521 * We look up more access than what we immediately need for open(), so
13551522 * that we can later authorize operations on opened files.
13561523 */
1524+ optional_access = LANDLOCK_ACCESS_FS_TRUNCATE ;
1525+ if (is_device (file ))
1526+ optional_access |= LANDLOCK_ACCESS_FS_IOCTL_DEV ;
1527+
13571528 full_access_request = open_access_request | optional_access ;
13581529
13591530 if (is_access_to_paths_allowed (
@@ -1410,6 +1581,52 @@ static int hook_file_truncate(struct file *const file)
14101581 return - EACCES ;
14111582}
14121583
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+
14131630static struct security_hook_list landlock_hooks [] __ro_after_init = {
14141631 LSM_HOOK_INIT (inode_free_security , hook_inode_free_security ),
14151632
@@ -1432,6 +1649,8 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
14321649 LSM_HOOK_INIT (file_alloc_security , hook_file_alloc_security ),
14331650 LSM_HOOK_INIT (file_open , hook_file_open ),
14341651 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 ),
14351654};
14361655
14371656__init void landlock_add_fs_hooks (void )
0 commit comments