Re: [RFC PATCH] fs: Add vfs_masks_device_ioctl*() helpers
From: "Arnd Bergmann" <arnd@arndb.de>
Date: 2024-03-01 16:25:15
Also in:
linux-fsdevel
On Mon, Feb 19, 2024, at 19:35, Mickaël Salaün wrote:
vfs_masks_device_ioctl() and vfs_masks_device_ioctl_compat() are useful to differenciate between device driver IOCTL implementations and filesystem ones. The goal is to be able to filter well-defined IOCTLs from per-device (i.e. namespaced) IOCTLs and control such access. Add a new ioctl_compat() helper, similar to vfs_ioctl(), to wrap compat_ioctl() calls and handle error conversions.
I'm still a bit confused by what your goal is here. I see the code getting more complex but don't see the payoff in this patch.
Cc: Arnd Bergmann <arnd@arndb.de> Cc: Christian Brauner <brauner@kernel.org> Cc: Günther Noack <gnoack@google.com>
I assume the missing Signed-off-by is intentional while you are still gathering feedback?
+/*
+ * Safeguard to maintain a list of valid IOCTLs handled by
do_vfs_ioctl()
+ * instead of def_blk_fops or def_chr_fops (see init_special_inode).
+ */
+__attribute_const__ bool vfs_masked_device_ioctl(const unsigned int
cmd)
+{
+ switch (cmd) {
+ case FIOCLEX:
+ case FIONCLEX:
+ case FIONBIO:
+ case FIOASYNC:
+ case FIOQSIZE:
+ case FIFREEZE:
+ case FITHAW:
+ case FS_IOC_FIEMAP:
+ case FIGETBSZ:
+ case FICLONE:
+ case FICLONERANGE:
+ case FIDEDUPERANGE:
+ /* FIONREAD is forwarded to device implementations. */
+ case FS_IOC_GETFLAGS:
+ case FS_IOC_SETFLAGS:
+ case FS_IOC_FSGETXATTR:
+ case FS_IOC_FSSETXATTR:
+ /* file_ioctl()'s IOCTLs are forwarded to device implementations. */
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL(vfs_masked_device_ioctl);It looks like this gets added into the hot path of every ioctl command, which is not ideal, especially when this no longer gets inlined into the caller.
+ inode = file_inode(f.file);
+ is_device = S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode);
+ if (is_device && !vfs_masked_device_ioctl(cmd)) {
+ error = vfs_ioctl(f.file, cmd, arg);
+ goto out;
+ }The S_ISBLK() || S_ISCHR() check here looks like it changes behavior, at least for sockets. If that is intentional, it should probably be a separate patch with a detailed explanation.
error = do_vfs_ioctl(f.file, fd, cmd, arg);
- if (error == -ENOIOCTLCMD)
+ if (error == -ENOIOCTLCMD) {
+ WARN_ON_ONCE(is_device);
error = vfs_ioctl(f.file, cmd, arg);
+ }The WARN_ON_ONCE() looks like it can be triggered from userspace, which is generally a bad idea.
+extern __attribute_const__ bool vfs_masked_device_ioctl(const unsigned
int cmd);
+#ifdef CONFIG_COMPAT
+extern __attribute_const__ bool
+vfs_masked_device_ioctl_compat(const unsigned int cmd);
+#else /* CONFIG_COMPAT */
+static inline __attribute_const__ bool
+vfs_masked_device_ioctl_compat(const unsigned int cmd)
+{
+ return vfs_masked_device_ioctl(cmd);
+}
+#endif /* CONFIG_COMPAT */
I don't understand the purpose of the #else path here,
this should not be needed.
Arnd