[PATCH v3 2/4] ima: use fs method to read integrity data
flat view
From: Mimi Zohar <hidden>
Date: 2017-07-13 13:55:39
Also in:
linux-fsdevel
Subsystem:
btrfs file system, efi variable filesystem, ext2 file system, ext4 file system, extended verification module (evm), f2fs file system, filesystems (vfs and infrastructure), gfs2 file system, integrity measurement architecture (ima), jfs filesystem, journalling flash file system v2 (jffs2), memory management, nilfs2 filesystem, oracle cluster filesystem 2 (ocfs2), security subsystem, the rest, tmpfs (shmem filesystem), ubi file system (ubifs), xfs filesystem · Maintainers:
David Sterba, Jeremy Kerr, Ard Biesheuvel, Jan Kara, "Theodore Ts'o", Mimi Zohar, Roberto Sassu, Jaegeuk Kim, Chao Yu, Alexander Viro, Christian Brauner, Andreas Gruenbacher, Dmitry Kasatkin, Dave Kleikamp, David Woodhouse, Richard Weinberger, Andrew Morton, Ryusuke Konishi, Viacheslav Dubeyko, Mark Fasheh, Joel Becker, Joseph Qi, Paul Moore, James Morris, "Serge E. Hallyn", Linus Torvalds, Hugh Dickins, Carlos Maiolino
Revision v3 of 6 in this series.
Revisions (6)
From: Christoph Hellwig <hch@lst.de> Add a new ->integrity_read file operation to read data for integrity hash collection. This is defined to be equivalent to ->read_iter, except that it will be called with the i_rwsem held exclusively. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: Matthew Garrett <redacted> Cc: Jan Kara <jack@suse.com> Cc: "Theodore Ts'o" <tytso@mit.edu> Cc: Andreas Dilger <adilger.kernel@dilger.ca> Cc: Jaegeuk Kim <jaegeuk@kernel.org> Cc: Chao Yu <redacted> Cc: Steven Whitehouse <redacted> Cc: Bob Peterson <redacted> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Dave Kleikamp <shaggy@kernel.org> Cc: Ryusuke Konishi <redacted> Cc: Mark Fasheh <redacted> Cc: Joel Becker <jlbec@evilplan.org> Cc: Richard Weinberger <richard@nod.at> Cc: "Darrick J. Wong" <redacted> Cc: Hugh Dickins <hughd@google.com> Cc: Chris Mason <redacted> Signed-off-by: Mimi Zohar <redacted> --- Changelog v3: - define simple_read_iter_from_buffer as suggested by Al Viro - replace the existing efivarfs ->read method with ->read_iter method. - squashed other fs definitions of ->integrity_read with this patch. - Cc'ing maintainers - moved '---' divider before change log, as requested in patch review Changelog v2: - change iovec to kvec Changelog v1: - update the patch description, removing the concept that the presence of ->integrity_read indicates that the file system can support IMA. (Mimi) fs/btrfs/file.c | 1 + fs/efivarfs/file.c | 12 +++++++----- fs/ext2/file.c | 1 + fs/ext4/file.c | 1 + fs/f2fs/file.c | 1 + fs/gfs2/file.c | 2 ++ fs/jffs2/file.c | 1 + fs/jfs/file.c | 1 + fs/libfs.c | 32 ++++++++++++++++++++++++++++++++ fs/nilfs2/file.c | 1 + fs/ocfs2/file.c | 1 + fs/ramfs/file-mmu.c | 1 + fs/ramfs/file-nommu.c | 1 + fs/ubifs/file.c | 1 + fs/xfs/xfs_file.c | 21 +++++++++++++++++++++ include/linux/fs.h | 3 +++ mm/shmem.c | 1 + security/integrity/iint.c | 20 ++++++++++++++------ 18 files changed, 91 insertions(+), 11 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index da1096eb1a40..003e859b56c4 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c@@ -3087,6 +3087,7 @@ const struct file_operations btrfs_file_operations = { #endif .clone_file_range = btrfs_clone_file_range, .dedupe_file_range = btrfs_dedupe_file_range, + .integrity_read = generic_file_read_iter, }; void btrfs_auto_defrag_exit(void)
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
index 5f22e74bbade..17955a92a5b3 100644
--- a/fs/efivarfs/file.c
+++ b/fs/efivarfs/file.c@@ -64,9 +64,10 @@ static ssize_t efivarfs_file_write(struct file *file, return bytes; } -static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) +static ssize_t efivarfs_file_read_iter(struct kiocb *iocb, + struct iov_iter *iter) { + struct file *file = iocb->ki_filp; struct efivar_entry *var = file->private_data; unsigned long datasize = 0; u32 attributes;
@@ -96,8 +97,8 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, goto out_free; memcpy(data, &attributes, sizeof(attributes)); - size = simple_read_from_buffer(userbuf, count, ppos, - data, datasize + sizeof(attributes)); + size = simple_read_iter_from_buffer(iocb, iter, data, + datasize + sizeof(attributes)); out_free: kfree(data);
@@ -174,8 +175,9 @@ efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) const struct file_operations efivarfs_file_operations = { .open = simple_open, - .read = efivarfs_file_read, + .read_iter = efivarfs_file_read_iter, .write = efivarfs_file_write, .llseek = no_llseek, .unlocked_ioctl = efivarfs_file_ioctl, + .integrity_read = efivarfs_file_read_iter, };
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index b21891a6bfca..d57c4259945d 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c@@ -219,6 +219,7 @@ const struct file_operations ext2_file_operations = { .get_unmapped_area = thp_get_unmapped_area, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, + .integrity_read = generic_file_read_iter, }; const struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 831fd6beebf0..e7b2bd43cdc4 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c@@ -753,6 +753,7 @@ const struct file_operations ext4_file_operations = { .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .fallocate = ext4_fallocate, + .integrity_read = ext4_file_read_iter, }; const struct inode_operations ext4_file_inode_operations = {
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 61af721329fa..e93fdeb3eba4 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c@@ -2406,4 +2406,5 @@ const struct file_operations f2fs_file_operations = { #endif .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, + .integrity_read = generic_file_read_iter, };
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index c2062a108d19..9b49d09ba180 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c@@ -1124,6 +1124,7 @@ const struct file_operations gfs2_file_fops = { .splice_write = gfs2_file_splice_write, .setlease = simple_nosetlease, .fallocate = gfs2_fallocate, + .integrity_read = generic_file_read_iter, }; const struct file_operations gfs2_dir_fops = {
@@ -1152,6 +1153,7 @@ const struct file_operations gfs2_file_fops_nolock = { .splice_write = gfs2_file_splice_write, .setlease = generic_setlease, .fallocate = gfs2_fallocate, + .integrity_read = generic_file_read_iter, }; const struct file_operations gfs2_dir_fops_nolock = {
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index c12476e309c6..5a63034cccf5 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c@@ -57,6 +57,7 @@ const struct file_operations jffs2_file_operations = .mmap = generic_file_readonly_mmap, .fsync = jffs2_fsync, .splice_read = generic_file_splice_read, + .integrity_read = generic_file_read_iter, }; /* jffs2_file_inode_operations */
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 739492c7a3fd..423512a810e4 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c@@ -162,4 +162,5 @@ const struct file_operations jfs_file_operations = { #ifdef CONFIG_COMPAT .compat_ioctl = jfs_compat_ioctl, #endif + .integrity_read = generic_file_read_iter, };
diff --git a/fs/libfs.c b/fs/libfs.c
index a04395334bb1..e1b4f8695013 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c@@ -16,6 +16,7 @@ #include <linux/exportfs.h> #include <linux/writeback.h> #include <linux/buffer_head.h> /* sync_mapping_buffers */ +#include <linux/uio.h> #include <linux/uaccess.h>
@@ -676,6 +677,37 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, EXPORT_SYMBOL(simple_write_to_buffer); /** + * simple_read_iter_from_buffer - copy data from the buffer to user space + * @iocb: struct containing the file, the current position and other info + * @to: the user space buffer to read to + * @from: the buffer to read from + * @available: the size of the buffer + * + * The simple_read_iter_from_buffer() function reads up to @available bytes + * from the current buffer into the user space buffer. + * + * On success, the current buffer offset is advanced by the number of bytes + * read, or a negative value is returned on error. + **/ +ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, struct iov_iter *to, + const void *from, size_t available) +{ + loff_t pos = iocb->ki_pos; + size_t ret; + + if (pos < 0) + return -EINVAL; + if (pos >= available) + return 0; + ret = copy_to_iter(from + pos, available - pos, to); + if (!ret && iov_iter_count(to)) + return -EFAULT; + iocb->ki_pos = pos + ret; + return ret; +} +EXPORT_SYMBOL(simple_read_iter_from_buffer); + +/** * memory_read_from_buffer - copy data from the buffer * @to: the kernel space buffer to read to * @count: the maximum number of bytes to read
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
index c5fa3dee72fc..55e058ac487f 100644
--- a/fs/nilfs2/file.c
+++ b/fs/nilfs2/file.c@@ -150,6 +150,7 @@ const struct file_operations nilfs_file_operations = { /* .release = nilfs_release_file, */ .fsync = nilfs_sync_file, .splice_read = generic_file_splice_read, + .integrity_read = generic_file_read_iter, }; const struct inode_operations nilfs_file_inode_operations = {
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index bfeb647459d9..2832a7c92acd 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c@@ -2536,6 +2536,7 @@ const struct file_operations ocfs2_fops = { .fallocate = ocfs2_fallocate, .clone_file_range = ocfs2_file_clone_range, .dedupe_file_range = ocfs2_file_dedupe_range, + .integrity_read = ocfs2_file_read_iter, }; const struct file_operations ocfs2_dops = {
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 12af0490322f..4f24d1b589b1 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c@@ -47,6 +47,7 @@ const struct file_operations ramfs_file_operations = { .splice_write = iter_file_splice_write, .llseek = generic_file_llseek, .get_unmapped_area = ramfs_mmu_get_unmapped_area, + .integrity_read = generic_file_read_iter, }; const struct inode_operations ramfs_file_inode_operations = {
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 2ef7ce75c062..5ee704fa84e0 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c@@ -50,6 +50,7 @@ const struct file_operations ramfs_file_operations = { .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .llseek = generic_file_llseek, + .integrity_read = generic_file_read_iter, }; const struct inode_operations ramfs_file_inode_operations = {
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 2cda3d67e2d0..eeb4e872e47a 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c@@ -1754,4 +1754,5 @@ const struct file_operations ubifs_file_operations = { #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif + .integrity_read = generic_file_read_iter, };
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 35703a801372..3d6ace2a79bc 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c@@ -288,6 +288,26 @@ xfs_file_read_iter( return ret; } +static ssize_t +xfs_integrity_read( + struct kiocb *iocb, + struct iov_iter *to) +{ + struct inode *inode = file_inode(iocb->ki_filp); + struct xfs_mount *mp = XFS_I(inode)->i_mount; + + lockdep_assert_held(&inode->i_rwsem); + + XFS_STATS_INC(mp, xs_read_calls); + + if (XFS_FORCED_SHUTDOWN(mp)) + return -EIO; + + if (IS_DAX(inode)) + return dax_iomap_rw(iocb, to, &xfs_iomap_ops); + return generic_file_read_iter(iocb, to); +} + /* * Zero any on disk space between the current EOF and the new, larger EOF. *
@@ -1534,6 +1554,7 @@ const struct file_operations xfs_file_operations = { .fallocate = xfs_file_fallocate, .clone_file_range = xfs_file_clone_range, .dedupe_file_range = xfs_file_dedupe_range, + .integrity_read = xfs_integrity_read, }; const struct file_operations xfs_dir_file_operations = {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 803e5a9b2654..d85d2c43afd9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h@@ -1690,6 +1690,7 @@ struct file_operations { u64); ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *, u64); + ssize_t (*integrity_read)(struct kiocb *, struct iov_iter *); }; struct inode_operations {
@@ -3011,6 +3012,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count); extern ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos, const void *from, size_t available); +extern ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, + struct iov_iter *to, const void *from, size_t available); extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, const void __user *from, size_t count);
diff --git a/mm/shmem.c b/mm/shmem.c
index e67d6ba4e98e..16958b20946f 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c@@ -3846,6 +3846,7 @@ static const struct file_operations shmem_file_operations = { .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .fallocate = shmem_fallocate, + .integrity_read = shmem_file_read_iter, #endif };
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 6fc888ca468e..df04f35a1d40 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c@@ -21,6 +21,7 @@ #include <linux/rbtree.h> #include <linux/file.h> #include <linux/uaccess.h> +#include <linux/uio.h> #include "integrity.h" static struct rb_root integrity_iint_tree = RB_ROOT;
@@ -184,18 +185,25 @@ security_initcall(integrity_iintcache_init); int integrity_kernel_read(struct file *file, loff_t offset, void *addr, unsigned long count) { - mm_segment_t old_fs; - char __user *buf = (char __user *)addr; + struct inode *inode = file_inode(file); + struct kvec iov = { .iov_base = addr, .iov_len = count }; + struct kiocb kiocb; + struct iov_iter iter; ssize_t ret; + lockdep_assert_held(&inode->i_rwsem); + if (!(file->f_mode & FMODE_READ)) return -EBADF; + if (!file->f_op->integrity_read) + return -EBADF; - old_fs = get_fs(); - set_fs(get_ds()); - ret = __vfs_read(file, buf, count, &offset); - set_fs(old_fs); + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = offset; + iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, count); + ret = file->f_op->integrity_read(&kiocb, &iter); + BUG_ON(ret == -EIOCBQUEUED); return ret; }
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html