All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/5] define new fs integrity_read method
@ 2017-07-26 13:22 ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: Mimi Zohar, James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module

With the introduction of IMA-appraisal and the need to write file
hashes as security xattrs, IMA needed to take the global i_mutex
lock.  process_measurement() took the iint->mutex first and then
the i_mutex, while setxattr, chmod and chown took the locks in
reverse order.  To resolve this potential deadlock, the iint->mutex
was removed.

Some filesystems have recently replaced their filesystem dependent
lock with the global i_rwsem (formerly the i_mutex) to read a file.
As a result, when IMA attempts to calculate the file hash, reading
the file attempts to take the i_rwsem again.

To resolve this locking problem, this patch set introduces a new
->integrity_read file operation method.  Until all filesystems
define the new ->integrity_read method, files that were previously
measured might not be currently measured and files that were
previously appraised might fail to be appraised properly.

Version 2 of this patch set, introduced measurement entries and
IMA-audit messages containing file hash values containing 0's,
instead of the actual file hash, for files which the file hash
could not be calculated.  Like for any other file signature
verification error, file access/execute permission will be denied,
for files in policy that the file hash could not be calculated.

To override the IMA policy, allowing unverified code to be
accessed/executed on filesystems not supported by IMA, version 2 of
this patch set defined a new policy "action" named "dont_failsafe"
and a new builtin policy named "fs_unsafe", which can be specified
on the boot command line.

The new ->integrity_read method supports opening files with O_DIRECT
on block devices that support direct IO and are mounted with the
"-o dax" option.  Version 4 of this patch set removes the
"permit_direction" IMA policy option, which is no longer necessary.

Change log v4:
- define ext2/4 specific ->integrity_read functions based Jan Kara's
review.
- properly fail file open with O_DIRECT on filesystems not mounted
with "-o dax".
- remove the "permit_directio" IMA policy option.

Change log v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.
- include dont_failsafe rule when displaying policy.
- fail attempt to add dont_failsafe rule when appending to the policy.
- moved '---' divider before change log, as requested in review.

Mimi

Christoph Hellwig (1):
  ima: use fs method to read integrity data

Mimi Zohar (4):
  ima: always measure and audit files in policy
  ima: define "dont_failsafe" policy action rule
  ima: define "fs_unsafe" builtin policy
  ima: remove permit_directio policy option

 Documentation/ABI/testing/ima_policy            |  5 ++-
 Documentation/admin-guide/kernel-parameters.txt |  8 +++-
 fs/btrfs/file.c                                 |  1 +
 fs/efivarfs/file.c                              | 12 +++---
 fs/ext2/file.c                                  | 17 ++++++++
 fs/ext4/file.c                                  | 23 +++++++++++
 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 +++++++---
 security/integrity/ima/ima.h                    |  1 +
 security/integrity/ima/ima_api.c                | 52 ++++++++++++++-----------
 security/integrity/ima/ima_main.c               | 18 ++++++---
 security/integrity/ima/ima_policy.c             | 49 +++++++++++++++++++----
 security/integrity/integrity.h                  |  1 -
 25 files changed, 222 insertions(+), 52 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 0/5] define new fs integrity_read method
@ 2017-07-26 13:22 ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: linux-security-module

With the introduction of IMA-appraisal and the need to write file
hashes as security xattrs, IMA needed to take the global i_mutex
lock.  process_measurement() took the iint->mutex first and then
the i_mutex, while setxattr, chmod and chown took the locks in
reverse order.  To resolve this potential deadlock, the iint->mutex
was removed.

Some filesystems have recently replaced their filesystem dependent
lock with the global i_rwsem (formerly the i_mutex) to read a file.
As a result, when IMA attempts to calculate the file hash, reading
the file attempts to take the i_rwsem again.

To resolve this locking problem, this patch set introduces a new
->integrity_read file operation method.  Until all filesystems
define the new ->integrity_read method, files that were previously
measured might not be currently measured and files that were
previously appraised might fail to be appraised properly.

Version 2 of this patch set, introduced measurement entries and
IMA-audit messages containing file hash values containing 0's,
instead of the actual file hash, for files which the file hash
could not be calculated.  Like for any other file signature
verification error, file access/execute permission will be denied,
for files in policy that the file hash could not be calculated.

To override the IMA policy, allowing unverified code to be
accessed/executed on filesystems not supported by IMA, version 2 of
this patch set defined a new policy "action" named "dont_failsafe"
and a new builtin policy named "fs_unsafe", which can be specified
on the boot command line.

The new ->integrity_read method supports opening files with O_DIRECT
on block devices that support direct IO and are mounted with the
"-o dax" option.  Version 4 of this patch set removes the
"permit_direction" IMA policy option, which is no longer necessary.

Change log v4:
- define ext2/4 specific ->integrity_read functions based Jan Kara's
review.
- properly fail file open with O_DIRECT on filesystems not mounted
with "-o dax".
- remove the "permit_directio" IMA policy option.

Change log v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.
- include dont_failsafe rule when displaying policy.
- fail attempt to add dont_failsafe rule when appending to the policy.
- moved '---' divider before change log, as requested in review.

Mimi

Christoph Hellwig (1):
  ima: use fs method to read integrity data

Mimi Zohar (4):
  ima: always measure and audit files in policy
  ima: define "dont_failsafe" policy action rule
  ima: define "fs_unsafe" builtin policy
  ima: remove permit_directio policy option

 Documentation/ABI/testing/ima_policy            |  5 ++-
 Documentation/admin-guide/kernel-parameters.txt |  8 +++-
 fs/btrfs/file.c                                 |  1 +
 fs/efivarfs/file.c                              | 12 +++---
 fs/ext2/file.c                                  | 17 ++++++++
 fs/ext4/file.c                                  | 23 +++++++++++
 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 +++++++---
 security/integrity/ima/ima.h                    |  1 +
 security/integrity/ima/ima_api.c                | 52 ++++++++++++++-----------
 security/integrity/ima/ima_main.c               | 18 ++++++---
 security/integrity/ima/ima_policy.c             | 49 +++++++++++++++++++----
 security/integrity/integrity.h                  |  1 -
 25 files changed, 222 insertions(+), 52 deletions(-)

-- 
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 1/5] ima: always measure and audit files in policy
  2017-07-26 13:22 ` Mimi Zohar
@ 2017-07-26 13:22   ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: Mimi Zohar, James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module

All files matching a "measure" rule must be included in the IMA
measurement list, even when the file hash cannot be calculated.
Similarly, all files matching an "audit" rule must be audited, even when
the file hash can not be calculated.

The file data hash field contained in the IMA measurement list template
data will contain 0's instead of the actual file hash digest.

Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v4:
- Based on both -EBADF and -EINVAL
- clean up ima_collect_measurement()

 security/integrity/ima/ima_api.c  | 58 +++++++++++++++++++++++----------------
 security/integrity/ima/ima_main.c |  4 +--
 2 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index c2edba8de35e..bbf3ba8bbb09 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -199,37 +199,49 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 	struct inode *inode = file_inode(file);
 	const char *filename = file->f_path.dentry->d_name.name;
 	int result = 0;
+	int length;
+	void *tmpbuf;
+	u64 i_version;
 	struct {
 		struct ima_digest_data hdr;
 		char digest[IMA_MAX_DIGEST_SIZE];
 	} hash;
 
-	if (!(iint->flags & IMA_COLLECTED)) {
-		u64 i_version = file_inode(file)->i_version;
+	if (iint->flags & IMA_COLLECTED)
+		goto out;
 
-		if (file->f_flags & O_DIRECT) {
-			audit_cause = "failed(directio)";
-			result = -EACCES;
-			goto out;
-		}
+	if (file->f_flags & O_DIRECT) {
+		audit_cause = "failed(directio)";
+		result = -EACCES;
+		goto out;
+	}
 
-		hash.hdr.algo = algo;
-
-		result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
-			ima_calc_buffer_hash(buf, size, &hash.hdr);
-		if (!result) {
-			int length = sizeof(hash.hdr) + hash.hdr.length;
-			void *tmpbuf = krealloc(iint->ima_hash, length,
-						GFP_NOFS);
-			if (tmpbuf) {
-				iint->ima_hash = tmpbuf;
-				memcpy(iint->ima_hash, &hash, length);
-				iint->version = i_version;
-				iint->flags |= IMA_COLLECTED;
-			} else
-				result = -ENOMEM;
-		}
+	i_version = file_inode(file)->i_version;
+	hash.hdr.algo = algo;
+
+	/* Initialize hash digest to 0's in case of failure */
+	memset(&hash.digest, 0, sizeof(hash.digest));
+
+	result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
+		ima_calc_buffer_hash(buf, size, &hash.hdr);
+
+	if (result && result != -EBADF && result != -EINVAL)
+		goto out;
+
+	length = sizeof(hash.hdr) + hash.hdr.length;
+	tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
+	if (!tmpbuf) {
+		result = -ENOMEM;
+		goto out;
 	}
+
+	iint->ima_hash = tmpbuf;
+	memcpy(iint->ima_hash, &hash, length);
+	iint->version = i_version;
+
+	/* Possibly temporary failure due to type of read (eg. DAX, O_DIRECT) */
+	if (result != -EBADF && result != -EINVAL)
+		iint->flags |= IMA_COLLECTED;
 out:
 	if (result)
 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2aebb7984437..3941371402ff 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -235,7 +235,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
 
 	rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
-	if (rc != 0) {
+	if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
 		if (file->f_flags & O_DIRECT)
 			rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
 		goto out_digsig;
@@ -247,7 +247,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 	if (action & IMA_MEASURE)
 		ima_store_measurement(iint, file, pathname,
 				      xattr_value, xattr_len, pcr);
-	if (action & IMA_APPRAISE_SUBMASK)
+	if ((rc == 0) && (action & IMA_APPRAISE_SUBMASK))
 		rc = ima_appraise_measurement(func, iint, file, pathname,
 					      xattr_value, xattr_len, opened);
 	if (action & IMA_AUDIT)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 1/5] ima: always measure and audit files in policy
@ 2017-07-26 13:22   ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: linux-security-module

All files matching a "measure" rule must be included in the IMA
measurement list, even when the file hash cannot be calculated.
Similarly, all files matching an "audit" rule must be audited, even when
the file hash can not be calculated.

The file data hash field contained in the IMA measurement list template
data will contain 0's instead of the actual file hash digest.

Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v4:
- Based on both -EBADF and -EINVAL
- clean up ima_collect_measurement()

 security/integrity/ima/ima_api.c  | 58 +++++++++++++++++++++++----------------
 security/integrity/ima/ima_main.c |  4 +--
 2 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index c2edba8de35e..bbf3ba8bbb09 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -199,37 +199,49 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 	struct inode *inode = file_inode(file);
 	const char *filename = file->f_path.dentry->d_name.name;
 	int result = 0;
+	int length;
+	void *tmpbuf;
+	u64 i_version;
 	struct {
 		struct ima_digest_data hdr;
 		char digest[IMA_MAX_DIGEST_SIZE];
 	} hash;
 
-	if (!(iint->flags & IMA_COLLECTED)) {
-		u64 i_version = file_inode(file)->i_version;
+	if (iint->flags & IMA_COLLECTED)
+		goto out;
 
-		if (file->f_flags & O_DIRECT) {
-			audit_cause = "failed(directio)";
-			result = -EACCES;
-			goto out;
-		}
+	if (file->f_flags & O_DIRECT) {
+		audit_cause = "failed(directio)";
+		result = -EACCES;
+		goto out;
+	}
 
-		hash.hdr.algo = algo;
-
-		result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
-			ima_calc_buffer_hash(buf, size, &hash.hdr);
-		if (!result) {
-			int length = sizeof(hash.hdr) + hash.hdr.length;
-			void *tmpbuf = krealloc(iint->ima_hash, length,
-						GFP_NOFS);
-			if (tmpbuf) {
-				iint->ima_hash = tmpbuf;
-				memcpy(iint->ima_hash, &hash, length);
-				iint->version = i_version;
-				iint->flags |= IMA_COLLECTED;
-			} else
-				result = -ENOMEM;
-		}
+	i_version = file_inode(file)->i_version;
+	hash.hdr.algo = algo;
+
+	/* Initialize hash digest to 0's in case of failure */
+	memset(&hash.digest, 0, sizeof(hash.digest));
+
+	result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
+		ima_calc_buffer_hash(buf, size, &hash.hdr);
+
+	if (result && result != -EBADF && result != -EINVAL)
+		goto out;
+
+	length = sizeof(hash.hdr) + hash.hdr.length;
+	tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
+	if (!tmpbuf) {
+		result = -ENOMEM;
+		goto out;
 	}
+
+	iint->ima_hash = tmpbuf;
+	memcpy(iint->ima_hash, &hash, length);
+	iint->version = i_version;
+
+	/* Possibly temporary failure due to type of read (eg. DAX, O_DIRECT) */
+	if (result != -EBADF && result != -EINVAL)
+		iint->flags |= IMA_COLLECTED;
 out:
 	if (result)
 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2aebb7984437..3941371402ff 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -235,7 +235,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
 
 	rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
-	if (rc != 0) {
+	if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
 		if (file->f_flags & O_DIRECT)
 			rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
 		goto out_digsig;
@@ -247,7 +247,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 	if (action & IMA_MEASURE)
 		ima_store_measurement(iint, file, pathname,
 				      xattr_value, xattr_len, pcr);
-	if (action & IMA_APPRAISE_SUBMASK)
+	if ((rc == 0) && (action & IMA_APPRAISE_SUBMASK))
 		rc = ima_appraise_measurement(func, iint, file, pathname,
 					      xattr_value, xattr_len, opened);
 	if (action & IMA_AUDIT)
-- 
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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
  2017-07-26 13:22 ` Mimi Zohar
@ 2017-07-26 13:22   ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module, Matthew Garrett, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, Chao Yu,
	Steven Whitehouse, Bob Peterson, David Woodhouse, Dave Kleikamp,
	Ryusuke Konishi, Mark Fasheh, Joel Becker, Richard Weinberger,
	Darrick J. Wong, Hugh Dickins, Chris Mason, Mimi Zohar

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 <matthew.garrett@nebula.com>
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 <yuchao0@huawei.com>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Bob Peterson <rpeterso@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Mark Fasheh <mfasheh@versity.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Chris Mason <clm@fb.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

Changelog v4:
- define ext2/4 specific ->integrity_read functions.
- properly fail file open with O_DIRECT on filesystem not mounted
with "-o dax".

---
Changelog v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.

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            | 17 +++++++++++++++++
 fs/ext4/file.c            | 23 +++++++++++++++++++++++
 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, 129 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 9e75d8a39aac..2542dc66c85c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+
+	lockdep_assert_held(&inode->i_rwsem);
+#ifdef CONFIG_FS_DAX
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+	if (IS_DAX(iocb->ki_filp->f_mapping->host))
+		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
+#endif
+	return generic_file_read_iter(iocb, to);
+}
+
 static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 #ifdef CONFIG_FS_DAX
@@ -216,6 +232,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	= ext2_file_integrity_read_iter,
 };
 
 const struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 58294c9a7e1d..cb423fff935f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+	int o_direct = iocb->ki_flags & IOCB_DIRECT;
+
+	lockdep_assert_held(&inode->i_rwsem);
+	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+		return -EIO;
+
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+#ifdef CONFIG_FS_DAX
+	if (IS_DAX(inode))
+		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
+#endif
+	if (o_direct)
+		return -EINVAL;
+	return generic_file_read_iter(iocb, to);
+}
+
 /*
  * Called when an inode is released. Note that this is different
  * from ext4_file_open: open gets called at every open, but release
@@ -747,6 +769,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_integrity_read_iter,
 };
 
 const struct inode_operations ext4_file_inode_operations = {
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 2706130c261b..82ea81da0b2d 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -292,6 +292,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.
  *
@@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1699,6 +1699,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 *);
 } __randomize_layout;
 
 struct inode_operations {
@@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3849,6 +3849,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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
@ 2017-07-26 13:22   ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: linux-security-module

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 <matthew.garrett@nebula.com>
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 <yuchao0@huawei.com>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Bob Peterson <rpeterso@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Mark Fasheh <mfasheh@versity.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Chris Mason <clm@fb.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

Changelog v4:
- define ext2/4 specific ->integrity_read functions.
- properly fail file open with O_DIRECT on filesystem not mounted
with "-o dax".

---
Changelog v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.

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            | 17 +++++++++++++++++
 fs/ext4/file.c            | 23 +++++++++++++++++++++++
 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, 129 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 9e75d8a39aac..2542dc66c85c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+
+	lockdep_assert_held(&inode->i_rwsem);
+#ifdef CONFIG_FS_DAX
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+	if (IS_DAX(iocb->ki_filp->f_mapping->host))
+		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
+#endif
+	return generic_file_read_iter(iocb, to);
+}
+
 static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 #ifdef CONFIG_FS_DAX
@@ -216,6 +232,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	= ext2_file_integrity_read_iter,
 };
 
 const struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 58294c9a7e1d..cb423fff935f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+	int o_direct = iocb->ki_flags & IOCB_DIRECT;
+
+	lockdep_assert_held(&inode->i_rwsem);
+	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+		return -EIO;
+
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+#ifdef CONFIG_FS_DAX
+	if (IS_DAX(inode))
+		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
+#endif
+	if (o_direct)
+		return -EINVAL;
+	return generic_file_read_iter(iocb, to);
+}
+
 /*
  * Called when an inode is released. Note that this is different
  * from ext4_file_open: open gets called at every open, but release
@@ -747,6 +769,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_integrity_read_iter,
 };
 
 const struct inode_operations ext4_file_inode_operations = {
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 2706130c261b..82ea81da0b2d 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -292,6 +292,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.
  *
@@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1699,6 +1699,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 *);
 } __randomize_layout;
 
 struct inode_operations {
@@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3849,6 +3849,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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule
  2017-07-26 13:22 ` Mimi Zohar
@ 2017-07-26 13:22   ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: Mimi Zohar, James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module

Permit normally denied access/execute permission for files in policy
on IMA unsupported filesystems.  This patch defines the "dont_failsafe"
policy action rule.

Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v3:
- include dont_failsafe rule when displaying policy
- fail attempt to add dont_failsafe rule when appending to the policy

 Documentation/ABI/testing/ima_policy |  3 ++-
 security/integrity/ima/ima.h         |  1 +
 security/integrity/ima/ima_main.c    | 11 ++++++++++-
 security/integrity/ima/ima_policy.c  | 29 ++++++++++++++++++++++++++++-
 4 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index e76432b9954d..f271207743e5 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -17,7 +17,8 @@ Description:
 
 		rule format: action [condition ...]
 
-		action: measure | dont_measure | appraise | dont_appraise | audit
+		action: measure | dont_meaure | appraise | dont_appraise |
+			audit | dont_failsafe
 		condition:= base | lsm  [option]
 			base:	[[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
 				[euid=] [fowner=]]
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d52b487ad259..c5f34f7c5b0f 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -224,6 +224,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
 void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
 void ima_policy_stop(struct seq_file *m, void *v);
 int ima_policy_show(struct seq_file *m, void *v);
+void set_failsafe(bool flag);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE	0x01
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 3941371402ff..664edab0f758 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -38,6 +38,11 @@ int ima_appraise;
 int ima_hash_algo = HASH_ALGO_SHA1;
 static int hash_setup_done;
 
+static bool ima_failsafe = 1;
+void set_failsafe(bool flag) {
+	ima_failsafe = flag;
+}
+
 static int __init hash_setup(char *str)
 {
 	struct ima_template_desc *template_desc = ima_template_desc_current();
@@ -263,8 +268,12 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 		__putname(pathbuf);
 out:
 	inode_unlock(inode);
-	if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
+	if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) {
+		if (!ima_failsafe && rc == -EBADF)
+			return 0;
+
 		return -EACCES;
+	}
 	return 0;
 }
 
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 95209a5f8595..43b85a4fb8e8 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -40,12 +40,14 @@
 #define APPRAISE	0x0004	/* same as IMA_APPRAISE */
 #define DONT_APPRAISE	0x0008
 #define AUDIT		0x0040
+#define DONT_FAILSAFE	0x0400
 
 #define INVALID_PCR(a) (((a) < 0) || \
 	(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
 
 int ima_policy_flag;
 static int temp_ima_appraise;
+static bool temp_failsafe = 1;
 
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
@@ -513,6 +515,9 @@ void ima_update_policy(void)
 	if (ima_rules != policy) {
 		ima_policy_flag = 0;
 		ima_rules = policy;
+
+		/* Only update on initial policy replacement, not append */
+		set_failsafe(temp_failsafe);
 	}
 	ima_update_policy_flag();
 }
@@ -529,7 +534,7 @@ enum {
 	Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
 	Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
 	Opt_appraise_type, Opt_permit_directio,
-	Opt_pcr
+	Opt_pcr, Opt_dont_failsafe
 };
 
 static match_table_t policy_tokens = {
@@ -560,6 +565,7 @@ static match_table_t policy_tokens = {
 	{Opt_appraise_type, "appraise_type=%s"},
 	{Opt_permit_directio, "permit_directio"},
 	{Opt_pcr, "pcr=%s"},
+	{Opt_dont_failsafe, "dont_failsafe"},
 	{Opt_err, NULL}
 };
 
@@ -630,6 +636,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 		if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
 			continue;
 		token = match_token(p, policy_tokens, args);
+		if (entry->action == DONT_FAILSAFE) {
+			/* no args permitted, force invalid rule */
+			token = Opt_dont_failsafe;
+		}
+
 		switch (token) {
 		case Opt_measure:
 			ima_log_string(ab, "action", "measure");
@@ -671,6 +682,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 
 			entry->action = AUDIT;
 			break;
+		case Opt_dont_failsafe:
+			ima_log_string(ab, "action", "dont_failsafe");
+
+			if (entry->action != UNKNOWN)
+				result = -EINVAL;
+
+			/* Permit on initial policy replacement only */
+			if (ima_rules != &ima_policy_rules)
+				temp_failsafe = 0;
+			else
+				result = -EINVAL;
+			entry->action = DONT_FAILSAFE;
+			break;
 		case Opt_func:
 			ima_log_string(ab, "func", args[0].from);
 
@@ -949,6 +973,7 @@ void ima_delete_rules(void)
 	int i;
 
 	temp_ima_appraise = 0;
+	temp_failsafe = 1;
 	list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
 		for (i = 0; i < MAX_LSM_RULES; i++)
 			kfree(entry->lsm[i].args_p);
@@ -1040,6 +1065,8 @@ int ima_policy_show(struct seq_file *m, void *v)
 		seq_puts(m, pt(Opt_dont_appraise));
 	if (entry->action & AUDIT)
 		seq_puts(m, pt(Opt_audit));
+	if (entry->action & DONT_FAILSAFE)
+		seq_puts(m, pt(Opt_dont_failsafe));
 
 	seq_puts(m, " ");
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule
@ 2017-07-26 13:22   ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: linux-security-module

Permit normally denied access/execute permission for files in policy
on IMA unsupported filesystems.  This patch defines the "dont_failsafe"
policy action rule.

Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v3:
- include dont_failsafe rule when displaying policy
- fail attempt to add dont_failsafe rule when appending to the policy

 Documentation/ABI/testing/ima_policy |  3 ++-
 security/integrity/ima/ima.h         |  1 +
 security/integrity/ima/ima_main.c    | 11 ++++++++++-
 security/integrity/ima/ima_policy.c  | 29 ++++++++++++++++++++++++++++-
 4 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index e76432b9954d..f271207743e5 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -17,7 +17,8 @@ Description:
 
 		rule format: action [condition ...]
 
-		action: measure | dont_measure | appraise | dont_appraise | audit
+		action: measure | dont_meaure | appraise | dont_appraise |
+			audit | dont_failsafe
 		condition:= base | lsm  [option]
 			base:	[[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
 				[euid=] [fowner=]]
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d52b487ad259..c5f34f7c5b0f 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -224,6 +224,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
 void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
 void ima_policy_stop(struct seq_file *m, void *v);
 int ima_policy_show(struct seq_file *m, void *v);
+void set_failsafe(bool flag);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE	0x01
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 3941371402ff..664edab0f758 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -38,6 +38,11 @@ int ima_appraise;
 int ima_hash_algo = HASH_ALGO_SHA1;
 static int hash_setup_done;
 
+static bool ima_failsafe = 1;
+void set_failsafe(bool flag) {
+	ima_failsafe = flag;
+}
+
 static int __init hash_setup(char *str)
 {
 	struct ima_template_desc *template_desc = ima_template_desc_current();
@@ -263,8 +268,12 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 		__putname(pathbuf);
 out:
 	inode_unlock(inode);
-	if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
+	if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) {
+		if (!ima_failsafe && rc == -EBADF)
+			return 0;
+
 		return -EACCES;
+	}
 	return 0;
 }
 
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 95209a5f8595..43b85a4fb8e8 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -40,12 +40,14 @@
 #define APPRAISE	0x0004	/* same as IMA_APPRAISE */
 #define DONT_APPRAISE	0x0008
 #define AUDIT		0x0040
+#define DONT_FAILSAFE	0x0400
 
 #define INVALID_PCR(a) (((a) < 0) || \
 	(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
 
 int ima_policy_flag;
 static int temp_ima_appraise;
+static bool temp_failsafe = 1;
 
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
@@ -513,6 +515,9 @@ void ima_update_policy(void)
 	if (ima_rules != policy) {
 		ima_policy_flag = 0;
 		ima_rules = policy;
+
+		/* Only update on initial policy replacement, not append */
+		set_failsafe(temp_failsafe);
 	}
 	ima_update_policy_flag();
 }
@@ -529,7 +534,7 @@ enum {
 	Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
 	Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
 	Opt_appraise_type, Opt_permit_directio,
-	Opt_pcr
+	Opt_pcr, Opt_dont_failsafe
 };
 
 static match_table_t policy_tokens = {
@@ -560,6 +565,7 @@ static match_table_t policy_tokens = {
 	{Opt_appraise_type, "appraise_type=%s"},
 	{Opt_permit_directio, "permit_directio"},
 	{Opt_pcr, "pcr=%s"},
+	{Opt_dont_failsafe, "dont_failsafe"},
 	{Opt_err, NULL}
 };
 
@@ -630,6 +636,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 		if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
 			continue;
 		token = match_token(p, policy_tokens, args);
+		if (entry->action == DONT_FAILSAFE) {
+			/* no args permitted, force invalid rule */
+			token = Opt_dont_failsafe;
+		}
+
 		switch (token) {
 		case Opt_measure:
 			ima_log_string(ab, "action", "measure");
@@ -671,6 +682,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 
 			entry->action = AUDIT;
 			break;
+		case Opt_dont_failsafe:
+			ima_log_string(ab, "action", "dont_failsafe");
+
+			if (entry->action != UNKNOWN)
+				result = -EINVAL;
+
+			/* Permit on initial policy replacement only */
+			if (ima_rules != &ima_policy_rules)
+				temp_failsafe = 0;
+			else
+				result = -EINVAL;
+			entry->action = DONT_FAILSAFE;
+			break;
 		case Opt_func:
 			ima_log_string(ab, "func", args[0].from);
 
@@ -949,6 +973,7 @@ void ima_delete_rules(void)
 	int i;
 
 	temp_ima_appraise = 0;
+	temp_failsafe = 1;
 	list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
 		for (i = 0; i < MAX_LSM_RULES; i++)
 			kfree(entry->lsm[i].args_p);
@@ -1040,6 +1065,8 @@ int ima_policy_show(struct seq_file *m, void *v)
 		seq_puts(m, pt(Opt_dont_appraise));
 	if (entry->action & AUDIT)
 		seq_puts(m, pt(Opt_audit));
+	if (entry->action & DONT_FAILSAFE)
+		seq_puts(m, pt(Opt_dont_failsafe));
 
 	seq_puts(m, " ");
 
-- 
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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 4/5] ima: define "fs_unsafe" builtin policy
  2017-07-26 13:22 ` Mimi Zohar
@ 2017-07-26 13:22   ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: Mimi Zohar, James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module

Permit normally denied access/execute permission for files in policy
on IMA unsupported filesystems.  This patch defines "fs_unsafe", a
builtin policy.

Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v3:
- include dont_failsafe rule when displaying policy

 Documentation/admin-guide/kernel-parameters.txt |  8 +++++++-
 security/integrity/ima/ima_policy.c             | 12 ++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index d9c171ce4190..4e303be83df6 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1502,7 +1502,7 @@
 
 	ima_policy=	[IMA]
 			The builtin policies to load during IMA setup.
-			Format: "tcb | appraise_tcb | secure_boot"
+			Format: "tcb | appraise_tcb | secure_boot | fs_unsafe"
 
 			The "tcb" policy measures all programs exec'd, files
 			mmap'd for exec, and all files opened with the read
@@ -1517,6 +1517,12 @@
 			of files (eg. kexec kernel image, kernel modules,
 			firmware, policy, etc) based on file signatures.
 
+			The "fs_unsafe" policy permits normally denied
+			access/execute permission for files in policy on IMA
+			unsupported filesystems.  Note this option, as the
+			name implies, is not safe and not recommended for
+			any environments other than testing.
+
 	ima_tcb		[IMA] Deprecated.  Use ima_policy= instead.
 			Load a policy which meets the needs of the Trusted
 			Computing Base.  This means IMA will measure all
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 43b85a4fb8e8..cddd9dfb01e1 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -169,6 +169,10 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
 	 .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
 };
 
+static struct ima_rule_entry dont_failsafe_rules[] __ro_after_init = {
+	{.action = DONT_FAILSAFE}
+};
+
 static LIST_HEAD(ima_default_rules);
 static LIST_HEAD(ima_policy_rules);
 static LIST_HEAD(ima_temp_rules);
@@ -188,6 +192,7 @@ __setup("ima_tcb", default_measure_policy_setup);
 
 static bool ima_use_appraise_tcb __initdata;
 static bool ima_use_secure_boot __initdata;
+static bool ima_use_dont_failsafe __initdata;
 static int __init policy_setup(char *str)
 {
 	char *p;
@@ -201,6 +206,10 @@ static int __init policy_setup(char *str)
 			ima_use_appraise_tcb = 1;
 		else if (strcmp(p, "secure_boot") == 0)
 			ima_use_secure_boot = 1;
+		else if (strcmp(p, "fs_unsafe") == 0) {
+			ima_use_dont_failsafe = 1;
+			set_failsafe(0);
+		}
 	}
 
 	return 1;
@@ -470,6 +479,9 @@ void __init ima_init_policy(void)
 			temp_ima_appraise |= IMA_APPRAISE_POLICY;
 	}
 
+	if (ima_use_dont_failsafe)
+		list_add_tail(&dont_failsafe_rules[0].list, &ima_default_rules);
+
 	ima_rules = &ima_default_rules;
 	ima_update_policy_flag();
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 4/5] ima: define "fs_unsafe" builtin policy
@ 2017-07-26 13:22   ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: linux-security-module

Permit normally denied access/execute permission for files in policy
on IMA unsupported filesystems.  This patch defines "fs_unsafe", a
builtin policy.

Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v3:
- include dont_failsafe rule when displaying policy

 Documentation/admin-guide/kernel-parameters.txt |  8 +++++++-
 security/integrity/ima/ima_policy.c             | 12 ++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index d9c171ce4190..4e303be83df6 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1502,7 +1502,7 @@
 
 	ima_policy=	[IMA]
 			The builtin policies to load during IMA setup.
-			Format: "tcb | appraise_tcb | secure_boot"
+			Format: "tcb | appraise_tcb | secure_boot | fs_unsafe"
 
 			The "tcb" policy measures all programs exec'd, files
 			mmap'd for exec, and all files opened with the read
@@ -1517,6 +1517,12 @@
 			of files (eg. kexec kernel image, kernel modules,
 			firmware, policy, etc) based on file signatures.
 
+			The "fs_unsafe" policy permits normally denied
+			access/execute permission for files in policy on IMA
+			unsupported filesystems.  Note this option, as the
+			name implies, is not safe and not recommended for
+			any environments other than testing.
+
 	ima_tcb		[IMA] Deprecated.  Use ima_policy= instead.
 			Load a policy which meets the needs of the Trusted
 			Computing Base.  This means IMA will measure all
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 43b85a4fb8e8..cddd9dfb01e1 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -169,6 +169,10 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
 	 .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
 };
 
+static struct ima_rule_entry dont_failsafe_rules[] __ro_after_init = {
+	{.action = DONT_FAILSAFE}
+};
+
 static LIST_HEAD(ima_default_rules);
 static LIST_HEAD(ima_policy_rules);
 static LIST_HEAD(ima_temp_rules);
@@ -188,6 +192,7 @@ __setup("ima_tcb", default_measure_policy_setup);
 
 static bool ima_use_appraise_tcb __initdata;
 static bool ima_use_secure_boot __initdata;
+static bool ima_use_dont_failsafe __initdata;
 static int __init policy_setup(char *str)
 {
 	char *p;
@@ -201,6 +206,10 @@ static int __init policy_setup(char *str)
 			ima_use_appraise_tcb = 1;
 		else if (strcmp(p, "secure_boot") == 0)
 			ima_use_secure_boot = 1;
+		else if (strcmp(p, "fs_unsafe") == 0) {
+			ima_use_dont_failsafe = 1;
+			set_failsafe(0);
+		}
 	}
 
 	return 1;
@@ -470,6 +479,9 @@ void __init ima_init_policy(void)
 			temp_ima_appraise |= IMA_APPRAISE_POLICY;
 	}
 
+	if (ima_use_dont_failsafe)
+		list_add_tail(&dont_failsafe_rules[0].list, &ima_default_rules);
+
 	ima_rules = &ima_default_rules;
 	ima_update_policy_flag();
 }
-- 
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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 5/5] ima: remove permit_directio policy option
  2017-07-26 13:22 ` Mimi Zohar
@ 2017-07-26 13:22   ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: Mimi Zohar, James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module

With the new ->integrity_read file_operations method support, files
opened with the O_DIRECT flag should work properly.  This patch
reverts commit f9b2a735bddd "ima: audit log files opened with O_DIRECT
flag".

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
---
 Documentation/ABI/testing/ima_policy | 2 +-
 security/integrity/ima/ima_api.c     | 6 ------
 security/integrity/ima/ima_main.c    | 5 +----
 security/integrity/ima/ima_policy.c  | 8 +-------
 security/integrity/integrity.h       | 1 -
 5 files changed, 3 insertions(+), 19 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index f271207743e5..441a78e7b87e 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -24,7 +24,7 @@ Description:
 				[euid=] [fowner=]]
 			lsm:	[[subj_user=] [subj_role=] [subj_type=]
 				 [obj_user=] [obj_role=] [obj_type=]]
-			option:	[[appraise_type=]] [permit_directio]
+			option:	[[appraise_type=]]
 
 		base: 	func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
 				[FIRMWARE_CHECK]
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index bbf3ba8bbb09..7bc8e76c06f5 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -210,12 +210,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 	if (iint->flags & IMA_COLLECTED)
 		goto out;
 
-	if (file->f_flags & O_DIRECT) {
-		audit_cause = "failed(directio)";
-		result = -EACCES;
-		goto out;
-	}
-
 	i_version = file_inode(file)->i_version;
 	hash.hdr.algo = algo;
 
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 664edab0f758..9b8ede84337f 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -240,11 +240,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
 
 	rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
-	if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
-		if (file->f_flags & O_DIRECT)
-			rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
+	if (rc != 0 && rc != -EBADF && rc != -EINVAL)
 		goto out_digsig;
-	}
 
 	if (!pathbuf)	/* ima_rdwr_violation possibly pre-fetched */
 		pathname = ima_d_path(&file->f_path, &pathbuf, filename);
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index cddd9dfb01e1..3b54fb32e837 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -545,7 +545,7 @@ enum {
 	Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
 	Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
 	Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
-	Opt_appraise_type, Opt_permit_directio,
+	Opt_appraise_type,
 	Opt_pcr, Opt_dont_failsafe
 };
 
@@ -575,7 +575,6 @@ static match_table_t policy_tokens = {
 	{Opt_euid_lt, "euid<%s"},
 	{Opt_fowner_lt, "fowner<%s"},
 	{Opt_appraise_type, "appraise_type=%s"},
-	{Opt_permit_directio, "permit_directio"},
 	{Opt_pcr, "pcr=%s"},
 	{Opt_dont_failsafe, "dont_failsafe"},
 	{Opt_err, NULL}
@@ -892,9 +891,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 			else
 				result = -EINVAL;
 			break;
-		case Opt_permit_directio:
-			entry->flags |= IMA_PERMIT_DIRECTIO;
-			break;
 		case Opt_pcr:
 			if (entry->action != MEASURE) {
 				result = -EINVAL;
@@ -1179,8 +1175,6 @@ int ima_policy_show(struct seq_file *m, void *v)
 	}
 	if (entry->flags & IMA_DIGSIG_REQUIRED)
 		seq_puts(m, "appraise_type=imasig ");
-	if (entry->flags & IMA_PERMIT_DIRECTIO)
-		seq_puts(m, "permit_directio ");
 	rcu_read_unlock();
 	seq_puts(m, "\n");
 	return 0;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index a53e7e4ab06c..790f07e515a7 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -31,7 +31,6 @@
 #define IMA_ACTION_RULE_FLAGS	0x06000000
 #define IMA_DIGSIG		0x01000000
 #define IMA_DIGSIG_REQUIRED	0x02000000
-#define IMA_PERMIT_DIRECTIO	0x04000000
 #define IMA_NEW_FILE		0x08000000
 
 #define IMA_DO_MASK		(IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 5/5] ima: remove permit_directio policy option
@ 2017-07-26 13:22   ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-26 13:22 UTC (permalink / raw)
  To: linux-security-module

With the new ->integrity_read file_operations method support, files
opened with the O_DIRECT flag should work properly.  This patch
reverts commit f9b2a735bddd "ima: audit log files opened with O_DIRECT
flag".

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
---
 Documentation/ABI/testing/ima_policy | 2 +-
 security/integrity/ima/ima_api.c     | 6 ------
 security/integrity/ima/ima_main.c    | 5 +----
 security/integrity/ima/ima_policy.c  | 8 +-------
 security/integrity/integrity.h       | 1 -
 5 files changed, 3 insertions(+), 19 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index f271207743e5..441a78e7b87e 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -24,7 +24,7 @@ Description:
 				[euid=] [fowner=]]
 			lsm:	[[subj_user=] [subj_role=] [subj_type=]
 				 [obj_user=] [obj_role=] [obj_type=]]
-			option:	[[appraise_type=]] [permit_directio]
+			option:	[[appraise_type=]]
 
 		base: 	func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
 				[FIRMWARE_CHECK]
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index bbf3ba8bbb09..7bc8e76c06f5 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -210,12 +210,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 	if (iint->flags & IMA_COLLECTED)
 		goto out;
 
-	if (file->f_flags & O_DIRECT) {
-		audit_cause = "failed(directio)";
-		result = -EACCES;
-		goto out;
-	}
-
 	i_version = file_inode(file)->i_version;
 	hash.hdr.algo = algo;
 
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 664edab0f758..9b8ede84337f 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -240,11 +240,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
 
 	rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
-	if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
-		if (file->f_flags & O_DIRECT)
-			rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
+	if (rc != 0 && rc != -EBADF && rc != -EINVAL)
 		goto out_digsig;
-	}
 
 	if (!pathbuf)	/* ima_rdwr_violation possibly pre-fetched */
 		pathname = ima_d_path(&file->f_path, &pathbuf, filename);
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index cddd9dfb01e1..3b54fb32e837 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -545,7 +545,7 @@ enum {
 	Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
 	Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
 	Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
-	Opt_appraise_type, Opt_permit_directio,
+	Opt_appraise_type,
 	Opt_pcr, Opt_dont_failsafe
 };
 
@@ -575,7 +575,6 @@ static match_table_t policy_tokens = {
 	{Opt_euid_lt, "euid<%s"},
 	{Opt_fowner_lt, "fowner<%s"},
 	{Opt_appraise_type, "appraise_type=%s"},
-	{Opt_permit_directio, "permit_directio"},
 	{Opt_pcr, "pcr=%s"},
 	{Opt_dont_failsafe, "dont_failsafe"},
 	{Opt_err, NULL}
@@ -892,9 +891,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 			else
 				result = -EINVAL;
 			break;
-		case Opt_permit_directio:
-			entry->flags |= IMA_PERMIT_DIRECTIO;
-			break;
 		case Opt_pcr:
 			if (entry->action != MEASURE) {
 				result = -EINVAL;
@@ -1179,8 +1175,6 @@ int ima_policy_show(struct seq_file *m, void *v)
 	}
 	if (entry->flags & IMA_DIGSIG_REQUIRED)
 		seq_puts(m, "appraise_type=imasig ");
-	if (entry->flags & IMA_PERMIT_DIRECTIO)
-		seq_puts(m, "permit_directio ");
 	rcu_read_unlock();
 	seq_puts(m, "\n");
 	return 0;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index a53e7e4ab06c..790f07e515a7 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -31,7 +31,6 @@
 #define IMA_ACTION_RULE_FLAGS	0x06000000
 #define IMA_DIGSIG		0x01000000
 #define IMA_DIGSIG_REQUIRED	0x02000000
-#define IMA_PERMIT_DIRECTIO	0x04000000
 #define IMA_NEW_FILE		0x08000000
 
 #define IMA_DO_MASK		(IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
-- 
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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-07-31  7:01     ` Jan Kara
  -1 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-07-31  7:01 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> 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.

The patch looks mostly good to me. Just one question: How did you select
filesystems that implement .integrity_read method? And I still maintain
that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
unless you either make sure they are mounted in local-only mode or figure
out how to deal with proper cluster locking.

								Honza
 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> Cc: Matthew Garrett <matthew.garrett@nebula.com>
> 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 <yuchao0@huawei.com>
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: Bob Peterson <rpeterso@redhat.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dave Kleikamp <shaggy@kernel.org>
> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> Cc: Mark Fasheh <mfasheh@versity.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Chris Mason <clm@fb.com>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> 
> Changelog v4:
> - define ext2/4 specific ->integrity_read functions.
> - properly fail file open with O_DIRECT on filesystem not mounted
> with "-o dax".
> 
> ---
> Changelog v3:
> - define simple_read_iter_from_buffer
> - replace the existing efivarfs ->read method with ->read_iter method.
> - squashed other fs definitions of ->integrity_read with this patch.
> 
> 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            | 17 +++++++++++++++++
>  fs/ext4/file.c            | 23 +++++++++++++++++++++++
>  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, 129 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index 9e75d8a39aac..2542dc66c85c 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> --- a/fs/ext2/file.c
> +++ b/fs/ext2/file.c
> @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  	return generic_file_read_iter(iocb, to);
>  }
>  
> +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> +					     struct iov_iter *to)
> +{
> +	struct inode *inode = file_inode(iocb->ki_filp);
> +
> +	lockdep_assert_held(&inode->i_rwsem);
> +#ifdef CONFIG_FS_DAX
> +	if (!iov_iter_count(to))
> +		return 0; /* skip atime */
> +
> +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> +#endif
> +	return generic_file_read_iter(iocb, to);
> +}
> +
>  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  {
>  #ifdef CONFIG_FS_DAX
> @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
>  };
>  
>  const struct inode_operations ext2_file_inode_operations = {
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 58294c9a7e1d..cb423fff935f 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  	return generic_file_read_iter(iocb, to);
>  }
>  
> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> +					     struct iov_iter *to)
> +{
> +	struct inode *inode = file_inode(iocb->ki_filp);
> +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> +	lockdep_assert_held(&inode->i_rwsem);
> +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> +		return -EIO;
> +
> +	if (!iov_iter_count(to))
> +		return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> +	if (IS_DAX(inode))
> +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> +	if (o_direct)
> +		return -EINVAL;
> +	return generic_file_read_iter(iocb, to);
> +}
> +
>  /*
>   * Called when an inode is released. Note that this is different
>   * from ext4_file_open: open gets called at every open, but release
> @@ -747,6 +769,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_integrity_read_iter,
>  };
>  
>  const struct inode_operations ext4_file_inode_operations = {
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 2706130c261b..82ea81da0b2d 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -292,6 +292,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.
>   *
> @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1699,6 +1699,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 *);
>  } __randomize_layout;
>  
>  struct inode_operations {
> @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3849,6 +3849,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
> 
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
@ 2017-07-31  7:01     ` Jan Kara
  0 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-07-31  7:01 UTC (permalink / raw)
  To: linux-security-module

On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> 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.

The patch looks mostly good to me. Just one question: How did you select
filesystems that implement .integrity_read method? And I still maintain
that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
unless you either make sure they are mounted in local-only mode or figure
out how to deal with proper cluster locking.

								Honza
 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> Cc: Matthew Garrett <matthew.garrett@nebula.com>
> 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 <yuchao0@huawei.com>
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: Bob Peterson <rpeterso@redhat.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dave Kleikamp <shaggy@kernel.org>
> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> Cc: Mark Fasheh <mfasheh@versity.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Chris Mason <clm@fb.com>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> 
> Changelog v4:
> - define ext2/4 specific ->integrity_read functions.
> - properly fail file open with O_DIRECT on filesystem not mounted
> with "-o dax".
> 
> ---
> Changelog v3:
> - define simple_read_iter_from_buffer
> - replace the existing efivarfs ->read method with ->read_iter method.
> - squashed other fs definitions of ->integrity_read with this patch.
> 
> 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            | 17 +++++++++++++++++
>  fs/ext4/file.c            | 23 +++++++++++++++++++++++
>  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, 129 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index 9e75d8a39aac..2542dc66c85c 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> --- a/fs/ext2/file.c
> +++ b/fs/ext2/file.c
> @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  	return generic_file_read_iter(iocb, to);
>  }
>  
> +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> +					     struct iov_iter *to)
> +{
> +	struct inode *inode = file_inode(iocb->ki_filp);
> +
> +	lockdep_assert_held(&inode->i_rwsem);
> +#ifdef CONFIG_FS_DAX
> +	if (!iov_iter_count(to))
> +		return 0; /* skip atime */
> +
> +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> +#endif
> +	return generic_file_read_iter(iocb, to);
> +}
> +
>  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  {
>  #ifdef CONFIG_FS_DAX
> @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
>  };
>  
>  const struct inode_operations ext2_file_inode_operations = {
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 58294c9a7e1d..cb423fff935f 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  	return generic_file_read_iter(iocb, to);
>  }
>  
> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> +					     struct iov_iter *to)
> +{
> +	struct inode *inode = file_inode(iocb->ki_filp);
> +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> +	lockdep_assert_held(&inode->i_rwsem);
> +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> +		return -EIO;
> +
> +	if (!iov_iter_count(to))
> +		return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> +	if (IS_DAX(inode))
> +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> +	if (o_direct)
> +		return -EINVAL;
> +	return generic_file_read_iter(iocb, to);
> +}
> +
>  /*
>   * Called when an inode is released. Note that this is different
>   * from ext4_file_open: open gets called at every open, but release
> @@ -747,6 +769,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_integrity_read_iter,
>  };
>  
>  const struct inode_operations ext4_file_inode_operations = {
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 2706130c261b..82ea81da0b2d 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -292,6 +292,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.
>   *
> @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1699,6 +1699,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 *);
>  } __randomize_layout;
>  
>  struct inode_operations {
> @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3849,6 +3849,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
> 
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data
  2017-07-31  7:01     ` Jan Kara
@ 2017-07-31 19:08       ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-31 19:08 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > 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.
> 
> The patch looks mostly good to me.

Thanks!  Can I include your Ack-by?

> Just one question: How did you select
> filesystems that implement .integrity_read method?

Initially I started out looking at the fs/.../Kconfig, but after
spending a while looking at the number of filesystems, I gave up and
asked Christoph (offline) where to begin.  I also compared the
measurement list from before and after the change and noticed some
missing file measurements (eg. ramfs, shmem, efivarfs).

> And I still maintain
> that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> unless you either make sure they are mounted in local-only mode or figure
> out how to deal with proper cluster locking.
> 
> 								Honza

Agreed.  With patch 1/7 "ima: always measure and audit files in
policy", at least a file measurement containing a 0x00's hash value
will be included in the IMA measurement list.

thanks,

Mimi

> > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > Cc: Matthew Garrett <matthew.garrett@nebula.com>
> > 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 <yuchao0@huawei.com>
> > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > Cc: Bob Peterson <rpeterso@redhat.com>
> > Cc: David Woodhouse <dwmw2@infradead.org>
> > Cc: Dave Kleikamp <shaggy@kernel.org>
> > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > Cc: Mark Fasheh <mfasheh@versity.com>
> > Cc: Joel Becker <jlbec@evilplan.org>
> > Cc: Richard Weinberger <richard@nod.at>
> > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > Cc: Hugh Dickins <hughd@google.com>
> > Cc: Chris Mason <clm@fb.com>
> > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > 
> > Changelog v4:
> > - define ext2/4 specific ->integrity_read functions.
> > - properly fail file open with O_DIRECT on filesystem not mounted
> > with "-o dax".
> > 
> > ---
> > Changelog v3:
> > - define simple_read_iter_from_buffer
> > - replace the existing efivarfs ->read method with ->read_iter method.
> > - squashed other fs definitions of ->integrity_read with this patch.
> > 
> > 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            | 17 +++++++++++++++++
> >  fs/ext4/file.c            | 23 +++++++++++++++++++++++
> >  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, 129 insertions(+), 11 deletions(-)
> > 
> > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > index 9e75d8a39aac..2542dc66c85c 100644
> > --- a/fs/btrfs/file.c
> > +++ b/fs/btrfs/file.c
> > @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> > --- a/fs/ext2/file.c
> > +++ b/fs/ext2/file.c
> > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> >  	return generic_file_read_iter(iocb, to);
> >  }
> >  
> > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > +					     struct iov_iter *to)
> > +{
> > +	struct inode *inode = file_inode(iocb->ki_filp);
> > +
> > +	lockdep_assert_held(&inode->i_rwsem);
> > +#ifdef CONFIG_FS_DAX
> > +	if (!iov_iter_count(to))
> > +		return 0; /* skip atime */
> > +
> > +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > +#endif
> > +	return generic_file_read_iter(iocb, to);
> > +}
> > +
> >  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> >  {
> >  #ifdef CONFIG_FS_DAX
> > @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
> >  };
> >  
> >  const struct inode_operations ext2_file_inode_operations = {
> > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > index 58294c9a7e1d..cb423fff935f 100644
> > --- a/fs/ext4/file.c
> > +++ b/fs/ext4/file.c
> > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> >  	return generic_file_read_iter(iocb, to);
> >  }
> >  
> > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > +					     struct iov_iter *to)
> > +{
> > +	struct inode *inode = file_inode(iocb->ki_filp);
> > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > +
> > +	lockdep_assert_held(&inode->i_rwsem);
> > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > +		return -EIO;
> > +
> > +	if (!iov_iter_count(to))
> > +		return 0; /* skip atime */
> > +
> > +#ifdef CONFIG_FS_DAX
> > +	if (IS_DAX(inode))
> > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > +#endif
> > +	if (o_direct)
> > +		return -EINVAL;
> > +	return generic_file_read_iter(iocb, to);
> > +}
> > +
> >  /*
> >   * Called when an inode is released. Note that this is different
> >   * from ext4_file_open: open gets called at every open, but release
> > @@ -747,6 +769,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_integrity_read_iter,
> >  };
> >  
> >  const struct inode_operations ext4_file_inode_operations = {
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 2706130c261b..82ea81da0b2d 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> > --- a/fs/ubifs/file.c
> > +++ b/fs/ubifs/file.c
> > @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> > --- a/fs/xfs/xfs_file.c
> > +++ b/fs/xfs/xfs_file.c
> > @@ -292,6 +292,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.
> >   *
> > @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -1699,6 +1699,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 *);
> >  } __randomize_layout;
> >  
> >  struct inode_operations {
> > @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> > --- a/mm/shmem.c
> > +++ b/mm/shmem.c
> > @@ -3849,6 +3849,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
> > 
> > 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
@ 2017-07-31 19:08       ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-07-31 19:08 UTC (permalink / raw)
  To: linux-security-module

On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > 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.
> 
> The patch looks mostly good to me.

Thanks! ?Can I include your Ack-by?

> Just one question: How did you select
> filesystems that implement .integrity_read method?

Initially I started out looking at the fs/.../Kconfig, but after
spending a while looking at the number of filesystems, I gave up and
asked Christoph (offline) where to begin.??I also compared the
measurement list from before and after the change and noticed some
missing file measurements (eg. ramfs, shmem, efivarfs).

> And I still maintain
> that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> unless you either make sure they are mounted in local-only mode or figure
> out how to deal with proper cluster locking.
> 
> 								Honza

Agreed. ?With patch 1/7 "ima: always measure and audit files in
policy", at least a file measurement containing a 0x00's hash value
will be included in the IMA measurement list.

thanks,

Mimi

> > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > Cc: Matthew Garrett <matthew.garrett@nebula.com>
> > 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 <yuchao0@huawei.com>
> > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > Cc: Bob Peterson <rpeterso@redhat.com>
> > Cc: David Woodhouse <dwmw2@infradead.org>
> > Cc: Dave Kleikamp <shaggy@kernel.org>
> > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > Cc: Mark Fasheh <mfasheh@versity.com>
> > Cc: Joel Becker <jlbec@evilplan.org>
> > Cc: Richard Weinberger <richard@nod.at>
> > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > Cc: Hugh Dickins <hughd@google.com>
> > Cc: Chris Mason <clm@fb.com>
> > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > 
> > Changelog v4:
> > - define ext2/4 specific ->integrity_read functions.
> > - properly fail file open with O_DIRECT on filesystem not mounted
> > with "-o dax".
> > 
> > ---
> > Changelog v3:
> > - define simple_read_iter_from_buffer
> > - replace the existing efivarfs ->read method with ->read_iter method.
> > - squashed other fs definitions of ->integrity_read with this patch.
> > 
> > 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            | 17 +++++++++++++++++
> >  fs/ext4/file.c            | 23 +++++++++++++++++++++++
> >  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, 129 insertions(+), 11 deletions(-)
> > 
> > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > index 9e75d8a39aac..2542dc66c85c 100644
> > --- a/fs/btrfs/file.c
> > +++ b/fs/btrfs/file.c
> > @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> > --- a/fs/ext2/file.c
> > +++ b/fs/ext2/file.c
> > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> >  	return generic_file_read_iter(iocb, to);
> >  }
> >  
> > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > +					     struct iov_iter *to)
> > +{
> > +	struct inode *inode = file_inode(iocb->ki_filp);
> > +
> > +	lockdep_assert_held(&inode->i_rwsem);
> > +#ifdef CONFIG_FS_DAX
> > +	if (!iov_iter_count(to))
> > +		return 0; /* skip atime */
> > +
> > +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > +#endif
> > +	return generic_file_read_iter(iocb, to);
> > +}
> > +
> >  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> >  {
> >  #ifdef CONFIG_FS_DAX
> > @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
> >  };
> >  
> >  const struct inode_operations ext2_file_inode_operations = {
> > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > index 58294c9a7e1d..cb423fff935f 100644
> > --- a/fs/ext4/file.c
> > +++ b/fs/ext4/file.c
> > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> >  	return generic_file_read_iter(iocb, to);
> >  }
> >  
> > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > +					     struct iov_iter *to)
> > +{
> > +	struct inode *inode = file_inode(iocb->ki_filp);
> > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > +
> > +	lockdep_assert_held(&inode->i_rwsem);
> > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > +		return -EIO;
> > +
> > +	if (!iov_iter_count(to))
> > +		return 0; /* skip atime */
> > +
> > +#ifdef CONFIG_FS_DAX
> > +	if (IS_DAX(inode))
> > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > +#endif
> > +	if (o_direct)
> > +		return -EINVAL;
> > +	return generic_file_read_iter(iocb, to);
> > +}
> > +
> >  /*
> >   * Called when an inode is released. Note that this is different
> >   * from ext4_file_open: open gets called at every open, but release
> > @@ -747,6 +769,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_integrity_read_iter,
> >  };
> >  
> >  const struct inode_operations ext4_file_inode_operations = {
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 2706130c261b..82ea81da0b2d 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> > --- a/fs/ubifs/file.c
> > +++ b/fs/ubifs/file.c
> > @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> > --- a/fs/xfs/xfs_file.c
> > +++ b/fs/xfs/xfs_file.c
> > @@ -292,6 +292,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.
> >   *
> > @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -1699,6 +1699,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 *);
> >  } __randomize_layout;
> >  
> >  struct inode_operations {
> > @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> > --- a/mm/shmem.c
> > +++ b/mm/shmem.c
> > @@ -3849,6 +3849,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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data
  2017-07-31 19:08       ` Mimi Zohar
@ 2017-08-01 10:42         ` Jan Kara
  -1 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-01 10:42 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Jan Kara, Christoph Hellwig, Al Viro, James Morris,
	linux-fsdevel, linux-ima-devel, linux-security-module,
	Matthew Garrett, Jan Kara, Theodore Ts'o, Andreas Dilger,
	Jaegeuk Kim, Chao Yu, Steven Whitehouse, Bob Peterson,
	David Woodhouse, Dave Kleikamp, Ryusuke Konishi, Mark Fasheh,
	Joel Becker, Richard Weinberger, Darrick J. Wong, Hugh Dickins,
	Chris Mason

On Mon 31-07-17 15:08:53, Mimi Zohar wrote:
> On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> > On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > > 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.
> > 
> > The patch looks mostly good to me.
> 
> Thanks! �Can I include your Ack-by?

After gfs2 & ocfs2 matters are settled...

> 
> > Just one question: How did you select
> > filesystems that implement .integrity_read method?
> 
> Initially I started out looking at the fs/.../Kconfig, but after
> spending a while looking at the number of filesystems, I gave up and
> asked Christoph (offline) where to begin.��I also compared the
> measurement list from before and after the change and noticed some
> missing file measurements (eg. ramfs, shmem, efivarfs).

OK, makes sense.

> > And I still maintain
> > that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> > unless you either make sure they are mounted in local-only mode or figure
> > out how to deal with proper cluster locking.
> 
> Agreed. �With patch 1/7 "ima: always measure and audit files in
> policy", at least a file measurement containing a 0x00's hash value
> will be included in the IMA measurement list.

Well, but for OCFS2 and GFS2 you have defined .integrity_read methods to
generic_file_read_iter() and they will return data so IMA will think
everything is fine. Just they may crash while doing so or return bogus data
due to insufficient locking generic_file_read_iter() provides. So my
suggestion is to just not provide .integrity_read for these two filesystems
until you (or someone else) can figure out how to do that safely.

								Honza

> > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > > Cc: Matthew Garrett <matthew.garrett@nebula.com>
> > > 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 <yuchao0@huawei.com>
> > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > Cc: Joel Becker <jlbec@evilplan.org>
> > > Cc: Richard Weinberger <richard@nod.at>
> > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > Cc: Hugh Dickins <hughd@google.com>
> > > Cc: Chris Mason <clm@fb.com>
> > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > 
> > > Changelog v4:
> > > - define ext2/4 specific ->integrity_read functions.
> > > - properly fail file open with O_DIRECT on filesystem not mounted
> > > with "-o dax".
> > > 
> > > ---
> > > Changelog v3:
> > > - define simple_read_iter_from_buffer
> > > - replace the existing efivarfs ->read method with ->read_iter method.
> > > - squashed other fs definitions of ->integrity_read with this patch.
> > > 
> > > 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            | 17 +++++++++++++++++
> > >  fs/ext4/file.c            | 23 +++++++++++++++++++++++
> > >  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, 129 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > > index 9e75d8a39aac..2542dc66c85c 100644
> > > --- a/fs/btrfs/file.c
> > > +++ b/fs/btrfs/file.c
> > > @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> > > --- a/fs/ext2/file.c
> > > +++ b/fs/ext2/file.c
> > > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > >  	return generic_file_read_iter(iocb, to);
> > >  }
> > >  
> > > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > > +					     struct iov_iter *to)
> > > +{
> > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > +
> > > +	lockdep_assert_held(&inode->i_rwsem);
> > > +#ifdef CONFIG_FS_DAX
> > > +	if (!iov_iter_count(to))
> > > +		return 0; /* skip atime */
> > > +
> > > +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > > +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > > +#endif
> > > +	return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > >  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > >  {
> > >  #ifdef CONFIG_FS_DAX
> > > @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
> > >  };
> > >  
> > >  const struct inode_operations ext2_file_inode_operations = {
> > > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > > index 58294c9a7e1d..cb423fff935f 100644
> > > --- a/fs/ext4/file.c
> > > +++ b/fs/ext4/file.c
> > > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > >  	return generic_file_read_iter(iocb, to);
> > >  }
> > >  
> > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > +					     struct iov_iter *to)
> > > +{
> > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > +
> > > +	lockdep_assert_held(&inode->i_rwsem);
> > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > +		return -EIO;
> > > +
> > > +	if (!iov_iter_count(to))
> > > +		return 0; /* skip atime */
> > > +
> > > +#ifdef CONFIG_FS_DAX
> > > +	if (IS_DAX(inode))
> > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > +#endif
> > > +	if (o_direct)
> > > +		return -EINVAL;
> > > +	return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > >  /*
> > >   * Called when an inode is released. Note that this is different
> > >   * from ext4_file_open: open gets called at every open, but release
> > > @@ -747,6 +769,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_integrity_read_iter,
> > >  };
> > >  
> > >  const struct inode_operations ext4_file_inode_operations = {
> > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > > index 2706130c261b..82ea81da0b2d 100644
> > > --- a/fs/f2fs/file.c
> > > +++ b/fs/f2fs/file.c
> > > @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> > > --- a/fs/ubifs/file.c
> > > +++ b/fs/ubifs/file.c
> > > @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> > > --- a/fs/xfs/xfs_file.c
> > > +++ b/fs/xfs/xfs_file.c
> > > @@ -292,6 +292,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.
> > >   *
> > > @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> > > --- a/include/linux/fs.h
> > > +++ b/include/linux/fs.h
> > > @@ -1699,6 +1699,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 *);
> > >  } __randomize_layout;
> > >  
> > >  struct inode_operations {
> > > @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> > > --- a/mm/shmem.c
> > > +++ b/mm/shmem.c
> > > @@ -3849,6 +3849,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
> > > 
> > > 
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
@ 2017-08-01 10:42         ` Jan Kara
  0 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-01 10:42 UTC (permalink / raw)
  To: linux-security-module

On Mon 31-07-17 15:08:53, Mimi Zohar wrote:
> On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> > On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > > 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.
> > 
> > The patch looks mostly good to me.
> 
> Thanks! ?Can I include your Ack-by?

After gfs2 & ocfs2 matters are settled...

> 
> > Just one question: How did you select
> > filesystems that implement .integrity_read method?
> 
> Initially I started out looking at the fs/.../Kconfig, but after
> spending a while looking at the number of filesystems, I gave up and
> asked Christoph (offline) where to begin.??I also compared the
> measurement list from before and after the change and noticed some
> missing file measurements (eg. ramfs, shmem, efivarfs).

OK, makes sense.

> > And I still maintain
> > that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> > unless you either make sure they are mounted in local-only mode or figure
> > out how to deal with proper cluster locking.
> 
> Agreed. ?With patch 1/7 "ima: always measure and audit files in
> policy", at least a file measurement containing a 0x00's hash value
> will be included in the IMA measurement list.

Well, but for OCFS2 and GFS2 you have defined .integrity_read methods to
generic_file_read_iter() and they will return data so IMA will think
everything is fine. Just they may crash while doing so or return bogus data
due to insufficient locking generic_file_read_iter() provides. So my
suggestion is to just not provide .integrity_read for these two filesystems
until you (or someone else) can figure out how to do that safely.

								Honza

> > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > > Cc: Matthew Garrett <matthew.garrett@nebula.com>
> > > 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 <yuchao0@huawei.com>
> > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > Cc: Joel Becker <jlbec@evilplan.org>
> > > Cc: Richard Weinberger <richard@nod.at>
> > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > Cc: Hugh Dickins <hughd@google.com>
> > > Cc: Chris Mason <clm@fb.com>
> > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > 
> > > Changelog v4:
> > > - define ext2/4 specific ->integrity_read functions.
> > > - properly fail file open with O_DIRECT on filesystem not mounted
> > > with "-o dax".
> > > 
> > > ---
> > > Changelog v3:
> > > - define simple_read_iter_from_buffer
> > > - replace the existing efivarfs ->read method with ->read_iter method.
> > > - squashed other fs definitions of ->integrity_read with this patch.
> > > 
> > > 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            | 17 +++++++++++++++++
> > >  fs/ext4/file.c            | 23 +++++++++++++++++++++++
> > >  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, 129 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > > index 9e75d8a39aac..2542dc66c85c 100644
> > > --- a/fs/btrfs/file.c
> > > +++ b/fs/btrfs/file.c
> > > @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> > > --- a/fs/ext2/file.c
> > > +++ b/fs/ext2/file.c
> > > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > >  	return generic_file_read_iter(iocb, to);
> > >  }
> > >  
> > > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > > +					     struct iov_iter *to)
> > > +{
> > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > +
> > > +	lockdep_assert_held(&inode->i_rwsem);
> > > +#ifdef CONFIG_FS_DAX
> > > +	if (!iov_iter_count(to))
> > > +		return 0; /* skip atime */
> > > +
> > > +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > > +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > > +#endif
> > > +	return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > >  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > >  {
> > >  #ifdef CONFIG_FS_DAX
> > > @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
> > >  };
> > >  
> > >  const struct inode_operations ext2_file_inode_operations = {
> > > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > > index 58294c9a7e1d..cb423fff935f 100644
> > > --- a/fs/ext4/file.c
> > > +++ b/fs/ext4/file.c
> > > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > >  	return generic_file_read_iter(iocb, to);
> > >  }
> > >  
> > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > +					     struct iov_iter *to)
> > > +{
> > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > +
> > > +	lockdep_assert_held(&inode->i_rwsem);
> > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > +		return -EIO;
> > > +
> > > +	if (!iov_iter_count(to))
> > > +		return 0; /* skip atime */
> > > +
> > > +#ifdef CONFIG_FS_DAX
> > > +	if (IS_DAX(inode))
> > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > +#endif
> > > +	if (o_direct)
> > > +		return -EINVAL;
> > > +	return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > >  /*
> > >   * Called when an inode is released. Note that this is different
> > >   * from ext4_file_open: open gets called at every open, but release
> > > @@ -747,6 +769,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_integrity_read_iter,
> > >  };
> > >  
> > >  const struct inode_operations ext4_file_inode_operations = {
> > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > > index 2706130c261b..82ea81da0b2d 100644
> > > --- a/fs/f2fs/file.c
> > > +++ b/fs/f2fs/file.c
> > > @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> > > --- a/fs/ubifs/file.c
> > > +++ b/fs/ubifs/file.c
> > > @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> > > --- a/fs/xfs/xfs_file.c
> > > +++ b/fs/xfs/xfs_file.c
> > > @@ -292,6 +292,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.
> > >   *
> > > @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> > > --- a/include/linux/fs.h
> > > +++ b/include/linux/fs.h
> > > @@ -1699,6 +1699,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 *);
> > >  } __randomize_layout;
> > >  
> > >  struct inode_operations {
> > > @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> > > --- a/mm/shmem.c
> > > +++ b/mm/shmem.c
> > > @@ -3849,6 +3849,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
> > > 
> > > 
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data
  2017-08-01 10:42         ` Jan Kara
@ 2017-08-01 15:38           ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-01 15:38 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Tue, 2017-08-01 at 12:42 +0200, Jan Kara wrote:
> On Mon 31-07-17 15:08:53, Mimi Zohar wrote:
> > On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> > > On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > > > 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.
> > > 
> > > The patch looks mostly good to me.
> > 
> > Thanks!  Can I include your Ack-by?
> 
> After gfs2 & ocfs2 matters are settled...
> 
> > 
> > > Just one question: How did you select
> > > filesystems that implement .integrity_read method?
> > 
> > Initially I started out looking at the fs/.../Kconfig, but after
> > spending a while looking at the number of filesystems, I gave up and
> > asked Christoph (offline) where to begin.  I also compared the
> > measurement list from before and after the change and noticed some
> > missing file measurements (eg. ramfs, shmem, efivarfs).
> 
> OK, makes sense.
> 
> > > And I still maintain
> > > that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> > > unless you either make sure they are mounted in local-only mode or figure
> > > out how to deal with proper cluster locking.
> > 
> > Agreed.  With patch 1/7 "ima: always measure and audit files in
> > policy", at least a file measurement containing a 0x00's hash value
> > will be included in the IMA measurement list.
> 
> Well, but for OCFS2 and GFS2 you have defined .integrity_read methods to
> generic_file_read_iter() and they will return data so IMA will think
> everything is fine. Just they may crash while doing so or return bogus data
> due to insufficient locking generic_file_read_iter() provides. So my
> suggestion is to just not provide .integrity_read for these two filesystems
> until you (or someone else) can figure out how to do that safely.

Sorry my explanation above wasn't clear.  Yes, I'll remove the
integrity_read method definitions for gfs2 and ocfs2.  As a result of
removing the integrity_read operation, the measurement list will
contain 0x00 hash values, instead of the real file hash.

Mimi 


> 
> > > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > > > Cc: Matthew Garrett <matthew.garrett@nebula.com>
> > > > 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 <yuchao0@huawei.com>
> > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > Cc: Richard Weinberger <richard@nod.at>
> > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > Cc: Hugh Dickins <hughd@google.com>
> > > > Cc: Chris Mason <clm@fb.com>
> > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > > 
> > > > Changelog v4:
> > > > - define ext2/4 specific ->integrity_read functions.
> > > > - properly fail file open with O_DIRECT on filesystem not mounted
> > > > with "-o dax".
> > > > 
> > > > ---
> > > > Changelog v3:
> > > > - define simple_read_iter_from_buffer
> > > > - replace the existing efivarfs ->read method with ->read_iter method.
> > > > - squashed other fs definitions of ->integrity_read with this patch.
> > > > 
> > > > 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            | 17 +++++++++++++++++
> > > >  fs/ext4/file.c            | 23 +++++++++++++++++++++++
> > > >  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, 129 insertions(+), 11 deletions(-)
> > > > 
> > > > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > > > index 9e75d8a39aac..2542dc66c85c 100644
> > > > --- a/fs/btrfs/file.c
> > > > +++ b/fs/btrfs/file.c
> > > > @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> > > > --- a/fs/ext2/file.c
> > > > +++ b/fs/ext2/file.c
> > > > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > >  	return generic_file_read_iter(iocb, to);
> > > >  }
> > > >  
> > > > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > > > +					     struct iov_iter *to)
> > > > +{
> > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > +
> > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > +#ifdef CONFIG_FS_DAX
> > > > +	if (!iov_iter_count(to))
> > > > +		return 0; /* skip atime */
> > > > +
> > > > +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > > > +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > > > +#endif
> > > > +	return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > >  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > > >  {
> > > >  #ifdef CONFIG_FS_DAX
> > > > @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
> > > >  };
> > > >  
> > > >  const struct inode_operations ext2_file_inode_operations = {
> > > > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > > > index 58294c9a7e1d..cb423fff935f 100644
> > > > --- a/fs/ext4/file.c
> > > > +++ b/fs/ext4/file.c
> > > > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > >  	return generic_file_read_iter(iocb, to);
> > > >  }
> > > >  
> > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > +					     struct iov_iter *to)
> > > > +{
> > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > +
> > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > +		return -EIO;
> > > > +
> > > > +	if (!iov_iter_count(to))
> > > > +		return 0; /* skip atime */
> > > > +
> > > > +#ifdef CONFIG_FS_DAX
> > > > +	if (IS_DAX(inode))
> > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > +#endif
> > > > +	if (o_direct)
> > > > +		return -EINVAL;
> > > > +	return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > >  /*
> > > >   * Called when an inode is released. Note that this is different
> > > >   * from ext4_file_open: open gets called at every open, but release
> > > > @@ -747,6 +769,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_integrity_read_iter,
> > > >  };
> > > >  
> > > >  const struct inode_operations ext4_file_inode_operations = {
> > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > > > index 2706130c261b..82ea81da0b2d 100644
> > > > --- a/fs/f2fs/file.c
> > > > +++ b/fs/f2fs/file.c
> > > > @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> > > > --- a/fs/ubifs/file.c
> > > > +++ b/fs/ubifs/file.c
> > > > @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> > > > --- a/fs/xfs/xfs_file.c
> > > > +++ b/fs/xfs/xfs_file.c
> > > > @@ -292,6 +292,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.
> > > >   *
> > > > @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> > > > --- a/include/linux/fs.h
> > > > +++ b/include/linux/fs.h
> > > > @@ -1699,6 +1699,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 *);
> > > >  } __randomize_layout;
> > > >  
> > > >  struct inode_operations {
> > > > @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> > > > --- a/mm/shmem.c
> > > > +++ b/mm/shmem.c
> > > > @@ -3849,6 +3849,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
> > > > 
> > > > 
> > 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
@ 2017-08-01 15:38           ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-01 15:38 UTC (permalink / raw)
  To: linux-security-module

On Tue, 2017-08-01 at 12:42 +0200, Jan Kara wrote:
> On Mon 31-07-17 15:08:53, Mimi Zohar wrote:
> > On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> > > On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > > > 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.
> > > 
> > > The patch looks mostly good to me.
> > 
> > Thanks! ?Can I include your Ack-by?
> 
> After gfs2 & ocfs2 matters are settled...
> 
> > 
> > > Just one question: How did you select
> > > filesystems that implement .integrity_read method?
> > 
> > Initially I started out looking at the fs/.../Kconfig, but after
> > spending a while looking at the number of filesystems, I gave up and
> > asked Christoph (offline) where to begin.??I also compared the
> > measurement list from before and after the change and noticed some
> > missing file measurements (eg. ramfs, shmem, efivarfs).
> 
> OK, makes sense.
> 
> > > And I still maintain
> > > that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> > > unless you either make sure they are mounted in local-only mode or figure
> > > out how to deal with proper cluster locking.
> > 
> > Agreed. ?With patch 1/7 "ima: always measure and audit files in
> > policy", at least a file measurement containing a 0x00's hash value
> > will be included in the IMA measurement list.
> 
> Well, but for OCFS2 and GFS2 you have defined .integrity_read methods to
> generic_file_read_iter() and they will return data so IMA will think
> everything is fine. Just they may crash while doing so or return bogus data
> due to insufficient locking generic_file_read_iter() provides. So my
> suggestion is to just not provide .integrity_read for these two filesystems
> until you (or someone else) can figure out how to do that safely.

Sorry my explanation above wasn't clear. ?Yes, I'll remove the
integrity_read method definitions for gfs2 and ocfs2. ?As a result of
removing the integrity_read operation, the measurement list will
contain 0x00 hash values, instead of the real file hash.

Mimi?


> 
> > > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > > > Cc: Matthew Garrett <matthew.garrett@nebula.com>
> > > > 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 <yuchao0@huawei.com>
> > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > Cc: Richard Weinberger <richard@nod.at>
> > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > Cc: Hugh Dickins <hughd@google.com>
> > > > Cc: Chris Mason <clm@fb.com>
> > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > > 
> > > > Changelog v4:
> > > > - define ext2/4 specific ->integrity_read functions.
> > > > - properly fail file open with O_DIRECT on filesystem not mounted
> > > > with "-o dax".
> > > > 
> > > > ---
> > > > Changelog v3:
> > > > - define simple_read_iter_from_buffer
> > > > - replace the existing efivarfs ->read method with ->read_iter method.
> > > > - squashed other fs definitions of ->integrity_read with this patch.
> > > > 
> > > > 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            | 17 +++++++++++++++++
> > > >  fs/ext4/file.c            | 23 +++++++++++++++++++++++
> > > >  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, 129 insertions(+), 11 deletions(-)
> > > > 
> > > > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > > > index 9e75d8a39aac..2542dc66c85c 100644
> > > > --- a/fs/btrfs/file.c
> > > > +++ b/fs/btrfs/file.c
> > > > @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> > > > --- a/fs/ext2/file.c
> > > > +++ b/fs/ext2/file.c
> > > > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > >  	return generic_file_read_iter(iocb, to);
> > > >  }
> > > >  
> > > > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > > > +					     struct iov_iter *to)
> > > > +{
> > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > +
> > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > +#ifdef CONFIG_FS_DAX
> > > > +	if (!iov_iter_count(to))
> > > > +		return 0; /* skip atime */
> > > > +
> > > > +	if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > > > +		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > > > +#endif
> > > > +	return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > >  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > > >  {
> > > >  #ifdef CONFIG_FS_DAX
> > > > @@ -216,6 +232,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	= ext2_file_integrity_read_iter,
> > > >  };
> > > >  
> > > >  const struct inode_operations ext2_file_inode_operations = {
> > > > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > > > index 58294c9a7e1d..cb423fff935f 100644
> > > > --- a/fs/ext4/file.c
> > > > +++ b/fs/ext4/file.c
> > > > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > >  	return generic_file_read_iter(iocb, to);
> > > >  }
> > > >  
> > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > +					     struct iov_iter *to)
> > > > +{
> > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > +
> > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > +		return -EIO;
> > > > +
> > > > +	if (!iov_iter_count(to))
> > > > +		return 0; /* skip atime */
> > > > +
> > > > +#ifdef CONFIG_FS_DAX
> > > > +	if (IS_DAX(inode))
> > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > +#endif
> > > > +	if (o_direct)
> > > > +		return -EINVAL;
> > > > +	return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > >  /*
> > > >   * Called when an inode is released. Note that this is different
> > > >   * from ext4_file_open: open gets called at every open, but release
> > > > @@ -747,6 +769,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_integrity_read_iter,
> > > >  };
> > > >  
> > > >  const struct inode_operations ext4_file_inode_operations = {
> > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > > > index 2706130c261b..82ea81da0b2d 100644
> > > > --- a/fs/f2fs/file.c
> > > > +++ b/fs/f2fs/file.c
> > > > @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> > > > --- a/fs/ubifs/file.c
> > > > +++ b/fs/ubifs/file.c
> > > > @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> > > > --- a/fs/xfs/xfs_file.c
> > > > +++ b/fs/xfs/xfs_file.c
> > > > @@ -292,6 +292,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.
> > > >   *
> > > > @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> > > > --- a/include/linux/fs.h
> > > > +++ b/include/linux/fs.h
> > > > @@ -1699,6 +1699,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 *);
> > > >  } __randomize_layout;
> > > >  
> > > >  struct inode_operations {
> > > > @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> > > > --- a/mm/shmem.c
> > > > +++ b/mm/shmem.c
> > > > @@ -3849,6 +3849,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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-08-01 20:24     ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-01 20:24 UTC (permalink / raw)
  To: Christoph Hellwig, Al Viro
  Cc: James Morris, linux-fsdevel, linux-ima-devel,
	linux-security-module, Matthew Garrett, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, Chao Yu,
	Steven Whitehouse, Bob Peterson, David Woodhouse, Dave Kleikamp,
	Ryusuke Konishi, Mark Fasheh, Joel Becker, Richard Weinberger,
	Darrick J. Wong, Hugh Dickins, Chris Mason

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 <matthew.garrett@nebula.com>
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 <yuchao0@huawei.com>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Bob Peterson <rpeterso@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Mark Fasheh <mfasheh@versity.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Chris Mason <clm@fb.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v5:
- removed ocf2 and gfs2 integrity_read support based on Jan Kara's review.

Changelog v4:
- define ext2/4 specific ->integrity_read functions.
- properly fail file open with O_DIRECT on filesystem not mounted
with "-o dax".

Changelog v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.

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            | 17 +++++++++++++++++
 fs/ext4/file.c            | 23 +++++++++++++++++++++++
 fs/f2fs/file.c            |  1 +
 fs/jffs2/file.c           |  1 +
 fs/jfs/file.c             |  1 +
 fs/libfs.c                | 32 ++++++++++++++++++++++++++++++++
 fs/nilfs2/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 ++++++++++++++------
 16 files changed, 126 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 9e75d8a39aac..2542dc66c85c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+
+	lockdep_assert_held(&inode->i_rwsem);
+#ifdef CONFIG_FS_DAX
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+	if (IS_DAX(iocb->ki_filp->f_mapping->host))
+		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
+#endif
+	return generic_file_read_iter(iocb, to);
+}
+
 static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 #ifdef CONFIG_FS_DAX
@@ -216,6 +232,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	= ext2_file_integrity_read_iter,
 };
 
 const struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 58294c9a7e1d..cb423fff935f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+	int o_direct = iocb->ki_flags & IOCB_DIRECT;
+
+	lockdep_assert_held(&inode->i_rwsem);
+	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+		return -EIO;
+
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+#ifdef CONFIG_FS_DAX
+	if (IS_DAX(inode))
+		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
+#endif
+	if (o_direct)
+		return -EINVAL;
+	return generic_file_read_iter(iocb, to);
+}
+
 /*
  * Called when an inode is released. Note that this is different
  * from ext4_file_open: open gets called at every open, but release
@@ -747,6 +769,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_integrity_read_iter,
 };
 
 const struct inode_operations ext4_file_inode_operations = {
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 2706130c261b..82ea81da0b2d 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2514,4 +2514,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/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 3aabe553fc45..99333264a0a7 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/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 8cad0b19b404..5e52a315e18b 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -292,6 +292,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.
  *
@@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1699,6 +1699,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 *);
 } __randomize_layout;
 
 struct inode_operations {
@@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3849,6 +3849,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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-01 20:24     ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-01 20:24 UTC (permalink / raw)
  To: linux-security-module

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 <matthew.garrett@nebula.com>
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 <yuchao0@huawei.com>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Bob Peterson <rpeterso@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Mark Fasheh <mfasheh@versity.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Chris Mason <clm@fb.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

---
Changelog v5:
- removed ocf2 and gfs2 integrity_read support based on Jan Kara's review.

Changelog v4:
- define ext2/4 specific ->integrity_read functions.
- properly fail file open with O_DIRECT on filesystem not mounted
with "-o dax".

Changelog v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.

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            | 17 +++++++++++++++++
 fs/ext4/file.c            | 23 +++++++++++++++++++++++
 fs/f2fs/file.c            |  1 +
 fs/jffs2/file.c           |  1 +
 fs/jfs/file.c             |  1 +
 fs/libfs.c                | 32 ++++++++++++++++++++++++++++++++
 fs/nilfs2/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 ++++++++++++++------
 16 files changed, 126 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 9e75d8a39aac..2542dc66c85c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+
+	lockdep_assert_held(&inode->i_rwsem);
+#ifdef CONFIG_FS_DAX
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+	if (IS_DAX(iocb->ki_filp->f_mapping->host))
+		return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
+#endif
+	return generic_file_read_iter(iocb, to);
+}
+
 static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 #ifdef CONFIG_FS_DAX
@@ -216,6 +232,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	= ext2_file_integrity_read_iter,
 };
 
 const struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 58294c9a7e1d..cb423fff935f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
+					     struct iov_iter *to)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+	int o_direct = iocb->ki_flags & IOCB_DIRECT;
+
+	lockdep_assert_held(&inode->i_rwsem);
+	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+		return -EIO;
+
+	if (!iov_iter_count(to))
+		return 0; /* skip atime */
+
+#ifdef CONFIG_FS_DAX
+	if (IS_DAX(inode))
+		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
+#endif
+	if (o_direct)
+		return -EINVAL;
+	return generic_file_read_iter(iocb, to);
+}
+
 /*
  * Called when an inode is released. Note that this is different
  * from ext4_file_open: open gets called at every open, but release
@@ -747,6 +769,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_integrity_read_iter,
 };
 
 const struct inode_operations ext4_file_inode_operations = {
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 2706130c261b..82ea81da0b2d 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2514,4 +2514,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/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 3aabe553fc45..99333264a0a7 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/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 8cad0b19b404..5e52a315e18b 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -292,6 +292,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.
  *
@@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1699,6 +1699,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 *);
 } __randomize_layout;
 
 struct inode_operations {
@@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3849,6 +3849,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

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-01 20:24     ` Mimi Zohar
@ 2017-08-02  8:01       ` Jan Kara
  -1 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-02  8:01 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> 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 <matthew.garrett@nebula.com>
> 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 <yuchao0@huawei.com>
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: Bob Peterson <rpeterso@redhat.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dave Kleikamp <shaggy@kernel.org>
> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> Cc: Mark Fasheh <mfasheh@versity.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Chris Mason <clm@fb.com>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

...

> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> +					     struct iov_iter *to)
> +{
> +	struct inode *inode = file_inode(iocb->ki_filp);
> +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> +	lockdep_assert_held(&inode->i_rwsem);
> +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> +		return -EIO;
> +
> +	if (!iov_iter_count(to))
> +		return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> +	if (IS_DAX(inode))
> +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> +	if (o_direct)
> +		return -EINVAL;
> +	return generic_file_read_iter(iocb, to);
> +}

I have noticed this o_direct check - why is it only in ext4 and shouldn't
rather higher layers make sure IOCB_DIRECT iocbs cannot reach
.integrity_read() methods?

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-02  8:01       ` Jan Kara
  0 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-02  8:01 UTC (permalink / raw)
  To: linux-security-module

On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> 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 <matthew.garrett@nebula.com>
> 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 <yuchao0@huawei.com>
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: Bob Peterson <rpeterso@redhat.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dave Kleikamp <shaggy@kernel.org>
> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> Cc: Mark Fasheh <mfasheh@versity.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Chris Mason <clm@fb.com>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

...

> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> +					     struct iov_iter *to)
> +{
> +	struct inode *inode = file_inode(iocb->ki_filp);
> +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> +	lockdep_assert_held(&inode->i_rwsem);
> +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> +		return -EIO;
> +
> +	if (!iov_iter_count(to))
> +		return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> +	if (IS_DAX(inode))
> +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> +	if (o_direct)
> +		return -EINVAL;
> +	return generic_file_read_iter(iocb, to);
> +}

I have noticed this o_direct check - why is it only in ext4 and shouldn't
rather higher layers make sure IOCB_DIRECT iocbs cannot reach
.integrity_read() methods?

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-02  8:01       ` Jan Kara
@ 2017-08-02 17:11         ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-02 17:11 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > 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 <matthew.garrett@nebula.com>
> > 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 <yuchao0@huawei.com>
> > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > Cc: Bob Peterson <rpeterso@redhat.com>
> > Cc: David Woodhouse <dwmw2@infradead.org>
> > Cc: Dave Kleikamp <shaggy@kernel.org>
> > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > Cc: Mark Fasheh <mfasheh@versity.com>
> > Cc: Joel Becker <jlbec@evilplan.org>
> > Cc: Richard Weinberger <richard@nod.at>
> > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > Cc: Hugh Dickins <hughd@google.com>
> > Cc: Chris Mason <clm@fb.com>
> > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> 
> ...
> 
> > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > +					     struct iov_iter *to)
> > +{
> > +	struct inode *inode = file_inode(iocb->ki_filp);
> > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > +
> > +	lockdep_assert_held(&inode->i_rwsem);
> > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > +		return -EIO;
> > +
> > +	if (!iov_iter_count(to))
> > +		return 0; /* skip atime */
> > +
> > +#ifdef CONFIG_FS_DAX
> > +	if (IS_DAX(inode))
> > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > +#endif
> > +	if (o_direct)
> > +		return -EINVAL;
> > +	return generic_file_read_iter(iocb, to);
> > +}
> 
> I have noticed this o_direct check - why is it only in ext4 and shouldn't
> rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> .integrity_read() methods?
 
This failure happens when opening a file with O_DIRECT on a block
device that does not support dax (eg. loop). xfs makes it to here too,
but the call to generic_file_read_iter() fails properly with -EINVAL. 
(Only tested on those filesystems included that support dax (eg. ext2,
ext4, and xfs).)

Mimi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-02 17:11         ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-02 17:11 UTC (permalink / raw)
  To: linux-security-module

On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > 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 <matthew.garrett@nebula.com>
> > 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 <yuchao0@huawei.com>
> > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > Cc: Bob Peterson <rpeterso@redhat.com>
> > Cc: David Woodhouse <dwmw2@infradead.org>
> > Cc: Dave Kleikamp <shaggy@kernel.org>
> > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > Cc: Mark Fasheh <mfasheh@versity.com>
> > Cc: Joel Becker <jlbec@evilplan.org>
> > Cc: Richard Weinberger <richard@nod.at>
> > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > Cc: Hugh Dickins <hughd@google.com>
> > Cc: Chris Mason <clm@fb.com>
> > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> 
> ...
> 
> > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > +					     struct iov_iter *to)
> > +{
> > +	struct inode *inode = file_inode(iocb->ki_filp);
> > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > +
> > +	lockdep_assert_held(&inode->i_rwsem);
> > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > +		return -EIO;
> > +
> > +	if (!iov_iter_count(to))
> > +		return 0; /* skip atime */
> > +
> > +#ifdef CONFIG_FS_DAX
> > +	if (IS_DAX(inode))
> > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > +#endif
> > +	if (o_direct)
> > +		return -EINVAL;
> > +	return generic_file_read_iter(iocb, to);
> > +}
> 
> I have noticed this o_direct check - why is it only in ext4 and shouldn't
> rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> .integrity_read() methods?
 
This failure happens when opening a file with O_DIRECT on a block
device that does not support dax (eg. loop). xfs makes it to here too,
but the call to generic_file_read_iter() fails properly with -EINVAL.?
(Only tested on those filesystems included that support dax (eg. ext2,
ext4, and xfs).)

Mimi

--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-02 17:11         ` Mimi Zohar
@ 2017-08-03 10:56           ` Jan Kara
  -1 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-03 10:56 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Jan Kara, Christoph Hellwig, Al Viro, James Morris,
	linux-fsdevel, linux-ima-devel, linux-security-module,
	Matthew Garrett, Jan Kara, Theodore Ts'o, Andreas Dilger,
	Jaegeuk Kim, Chao Yu, Steven Whitehouse, Bob Peterson,
	David Woodhouse, Dave Kleikamp, Ryusuke Konishi, Mark Fasheh,
	Joel Becker, Richard Weinberger, Darrick J. Wong, Hugh Dickins,
	Chris Mason

On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > 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 <matthew.garrett@nebula.com>
> > > 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 <yuchao0@huawei.com>
> > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > Cc: Joel Becker <jlbec@evilplan.org>
> > > Cc: Richard Weinberger <richard@nod.at>
> > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > Cc: Hugh Dickins <hughd@google.com>
> > > Cc: Chris Mason <clm@fb.com>
> > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > 
> > ...
> > 
> > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > +					     struct iov_iter *to)
> > > +{
> > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > +
> > > +	lockdep_assert_held(&inode->i_rwsem);
> > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > +		return -EIO;
> > > +
> > > +	if (!iov_iter_count(to))
> > > +		return 0; /* skip atime */
> > > +
> > > +#ifdef CONFIG_FS_DAX
> > > +	if (IS_DAX(inode))
> > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > +#endif
> > > +	if (o_direct)
> > > +		return -EINVAL;
> > > +	return generic_file_read_iter(iocb, to);
> > > +}
> > 
> > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > .integrity_read() methods?
>  
> This failure happens when opening a file with O_DIRECT on a block
> device that does not support dax (eg. loop). xfs makes it to here too,
> but the call to generic_file_read_iter() fails properly with -EINVAL.�
> (Only tested on those filesystems included that support dax (eg. ext2,
> ext4, and xfs).)

Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
pretty much all filesystems except for XFS). However I fail to see why IMA
should care (which is probably due to my lack of knowledge about IMA).
Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?

								Honza

-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-03 10:56           ` Jan Kara
  0 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-03 10:56 UTC (permalink / raw)
  To: linux-security-module

On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > 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 <matthew.garrett@nebula.com>
> > > 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 <yuchao0@huawei.com>
> > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > Cc: Joel Becker <jlbec@evilplan.org>
> > > Cc: Richard Weinberger <richard@nod.at>
> > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > Cc: Hugh Dickins <hughd@google.com>
> > > Cc: Chris Mason <clm@fb.com>
> > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > 
> > ...
> > 
> > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > +					     struct iov_iter *to)
> > > +{
> > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > +
> > > +	lockdep_assert_held(&inode->i_rwsem);
> > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > +		return -EIO;
> > > +
> > > +	if (!iov_iter_count(to))
> > > +		return 0; /* skip atime */
> > > +
> > > +#ifdef CONFIG_FS_DAX
> > > +	if (IS_DAX(inode))
> > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > +#endif
> > > +	if (o_direct)
> > > +		return -EINVAL;
> > > +	return generic_file_read_iter(iocb, to);
> > > +}
> > 
> > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > .integrity_read() methods?
>  
> This failure happens when opening a file with O_DIRECT on a block
> device that does not support dax (eg. loop). xfs makes it to here too,
> but the call to generic_file_read_iter() fails properly with -EINVAL.?
> (Only tested on those filesystems included that support dax (eg. ext2,
> ext4, and xfs).)

Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
pretty much all filesystems except for XFS). However I fail to see why IMA
should care (which is probably due to my lack of knowledge about IMA).
Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?

								Honza

-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-03 10:56           ` Jan Kara
@ 2017-08-04 21:07             ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-04 21:07 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Thu, 2017-08-03 at 12:56 +0200, Jan Kara wrote:
> On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> > On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > > 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 <matthew.garrett@nebula.com>
> > > > 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 <yuchao0@huawei.com>
> > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > Cc: Richard Weinberger <richard@nod.at>
> > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > Cc: Hugh Dickins <hughd@google.com>
> > > > Cc: Chris Mason <clm@fb.com>
> > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > 
> > > ...
> > > 
> > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > +					     struct iov_iter *to)
> > > > +{
> > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > +
> > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > +		return -EIO;
> > > > +
> > > > +	if (!iov_iter_count(to))
> > > > +		return 0; /* skip atime */
> > > > +
> > > > +#ifdef CONFIG_FS_DAX
> > > > +	if (IS_DAX(inode))
> > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > +#endif
> > > > +	if (o_direct)
> > > > +		return -EINVAL;
> > > > +	return generic_file_read_iter(iocb, to);
> > > > +}
> > > 
> > > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > > .integrity_read() methods?
> >  
> > This failure happens when opening a file with O_DIRECT on a block
> > device that does not support dax (eg. loop). xfs makes it to here too,
> > but the call to generic_file_read_iter() fails properly with -EINVAL. 
> > (Only tested on those filesystems included that support dax (eg. ext2,
> > ext4, and xfs).)
> 
> Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
> pretty much all filesystems except for XFS). However I fail to see why IMA
> should care (which is probably due to my lack of knowledge about IMA).
> Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?

Thank you for the explanation!  (I was confused about the relationship
between O_DIRECT and DAX.)  You're correct.  IMA does not support
O_DIRECT in the buffered case for two reasons, locking and updating
the file hash, which are described in commit f9b2a735bddd "ima: audit
log files opened with O_DIRECT flag".  After reverting this commit,
the O_DIRECT check is needed before calling generic_file_read_iter().
 Most likely the same would need to be done for other filesystems that
support O_DIRECT.  Probably a generic_integrity_file_read_iter()
should be defined.
 
For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
lock has been taken.  Assuming the file system is mounted with
i_version, the file hash is updated properly.

Mimi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-04 21:07             ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-04 21:07 UTC (permalink / raw)
  To: linux-security-module

On Thu, 2017-08-03 at 12:56 +0200, Jan Kara wrote:
> On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> > On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > > 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 <matthew.garrett@nebula.com>
> > > > 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 <yuchao0@huawei.com>
> > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > Cc: Richard Weinberger <richard@nod.at>
> > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > Cc: Hugh Dickins <hughd@google.com>
> > > > Cc: Chris Mason <clm@fb.com>
> > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > 
> > > ...
> > > 
> > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > +					     struct iov_iter *to)
> > > > +{
> > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > +
> > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > +		return -EIO;
> > > > +
> > > > +	if (!iov_iter_count(to))
> > > > +		return 0; /* skip atime */
> > > > +
> > > > +#ifdef CONFIG_FS_DAX
> > > > +	if (IS_DAX(inode))
> > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > +#endif
> > > > +	if (o_direct)
> > > > +		return -EINVAL;
> > > > +	return generic_file_read_iter(iocb, to);
> > > > +}
> > > 
> > > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > > .integrity_read() methods?
> >  
> > This failure happens when opening a file with O_DIRECT on a block
> > device that does not support dax (eg. loop). xfs makes it to here too,
> > but the call to generic_file_read_iter() fails properly with -EINVAL.?
> > (Only tested on those filesystems included that support dax (eg. ext2,
> > ext4, and xfs).)
> 
> Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
> pretty much all filesystems except for XFS). However I fail to see why IMA
> should care (which is probably due to my lack of knowledge about IMA).
> Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?

Thank you for the explanation! ?(I was confused about the relationship
between O_DIRECT and DAX.) ?You're correct. ?IMA does not support
O_DIRECT in the buffered case for two reasons, locking and updating
the file hash, which are described in commit?f9b2a735bddd "ima: audit
log files opened with O_DIRECT flag". ?After reverting this commit,
the O_DIRECT check is needed before calling generic_file_read_iter().
?Most likely the same would need to be done for other filesystems that
support O_DIRECT. ?Probably a generic_integrity_file_read_iter()
should be defined.
?
For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
lock has been taken. ?Assuming the file system is mounted with
i_version, the file hash is updated properly.

Mimi

--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-04 21:07             ` Mimi Zohar
@ 2017-08-07 10:04               ` Jan Kara
  -1 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-07 10:04 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Jan Kara, Christoph Hellwig, Al Viro, James Morris,
	linux-fsdevel, linux-ima-devel, linux-security-module,
	Matthew Garrett, Jan Kara, Theodore Ts'o, Andreas Dilger,
	Jaegeuk Kim, Chao Yu, Steven Whitehouse, Bob Peterson,
	David Woodhouse, Dave Kleikamp, Ryusuke Konishi, Mark Fasheh,
	Joel Becker, Richard Weinberger, Darrick J. Wong, Hugh Dickins,
	Chris Mason

On Fri 04-08-17 17:07:11, Mimi Zohar wrote:
> On Thu, 2017-08-03 at 12:56 +0200, Jan Kara wrote:
> > On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> > > On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > > > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > > > 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 <matthew.garrett@nebula.com>
> > > > > 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 <yuchao0@huawei.com>
> > > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > > Cc: Richard Weinberger <richard@nod.at>
> > > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > > Cc: Hugh Dickins <hughd@google.com>
> > > > > Cc: Chris Mason <clm@fb.com>
> > > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > > 
> > > > ...
> > > > 
> > > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > > +					     struct iov_iter *to)
> > > > > +{
> > > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > > +
> > > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > > +		return -EIO;
> > > > > +
> > > > > +	if (!iov_iter_count(to))
> > > > > +		return 0; /* skip atime */
> > > > > +
> > > > > +#ifdef CONFIG_FS_DAX
> > > > > +	if (IS_DAX(inode))
> > > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > > +#endif
> > > > > +	if (o_direct)
> > > > > +		return -EINVAL;
> > > > > +	return generic_file_read_iter(iocb, to);
> > > > > +}
> > > > 
> > > > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > > > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > > > .integrity_read() methods?
> > >  
> > > This failure happens when opening a file with O_DIRECT on a block
> > > device that does not support dax (eg. loop). xfs makes it to here too,
> > > but the call to generic_file_read_iter() fails properly with -EINVAL.�
> > > (Only tested on those filesystems included that support dax (eg. ext2,
> > > ext4, and xfs).)
> > 
> > Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
> > pretty much all filesystems except for XFS). However I fail to see why IMA
> > should care (which is probably due to my lack of knowledge about IMA).
> > Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?
> 
> Thank you for the explanation! �(I was confused about the relationship
> between O_DIRECT and DAX.) �You're correct. �IMA does not support
> O_DIRECT in the buffered case for two reasons, locking and updating
> the file hash, which are described in commit�f9b2a735bddd "ima: audit
> log files opened with O_DIRECT flag". �After reverting this commit,
> the O_DIRECT check is needed before calling generic_file_read_iter().

Thanks for the pointer. This cleaned up the issue for me.

> �Most likely the same would need to be done for other filesystems that
> support O_DIRECT. �Probably a generic_integrity_file_read_iter()
> should be defined.

Yeah, then please define some common helper that takes care of refusing
direct IO - IMO you should check this even before calling into
->integrity_read helper.

> For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
> the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
> lock has been taken. �Assuming the file system is mounted with
> i_version, the file hash is updated properly.

Yes, for DAX direct IO is basically no different but frankly I would just
refuse O_DIRECT on DAX inodes as well just for the consistency sake.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-07 10:04               ` Jan Kara
  0 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-07 10:04 UTC (permalink / raw)
  To: linux-security-module

On Fri 04-08-17 17:07:11, Mimi Zohar wrote:
> On Thu, 2017-08-03 at 12:56 +0200, Jan Kara wrote:
> > On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> > > On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > > > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > > > 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 <matthew.garrett@nebula.com>
> > > > > 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 <yuchao0@huawei.com>
> > > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > > Cc: Richard Weinberger <richard@nod.at>
> > > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > > Cc: Hugh Dickins <hughd@google.com>
> > > > > Cc: Chris Mason <clm@fb.com>
> > > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > > 
> > > > ...
> > > > 
> > > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > > +					     struct iov_iter *to)
> > > > > +{
> > > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > > +
> > > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > > +		return -EIO;
> > > > > +
> > > > > +	if (!iov_iter_count(to))
> > > > > +		return 0; /* skip atime */
> > > > > +
> > > > > +#ifdef CONFIG_FS_DAX
> > > > > +	if (IS_DAX(inode))
> > > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > > +#endif
> > > > > +	if (o_direct)
> > > > > +		return -EINVAL;
> > > > > +	return generic_file_read_iter(iocb, to);
> > > > > +}
> > > > 
> > > > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > > > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > > > .integrity_read() methods?
> > >  
> > > This failure happens when opening a file with O_DIRECT on a block
> > > device that does not support dax (eg. loop). xfs makes it to here too,
> > > but the call to generic_file_read_iter() fails properly with -EINVAL.?
> > > (Only tested on those filesystems included that support dax (eg. ext2,
> > > ext4, and xfs).)
> > 
> > Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
> > pretty much all filesystems except for XFS). However I fail to see why IMA
> > should care (which is probably due to my lack of knowledge about IMA).
> > Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?
> 
> Thank you for the explanation! ?(I was confused about the relationship
> between O_DIRECT and DAX.) ?You're correct. ?IMA does not support
> O_DIRECT in the buffered case for two reasons, locking and updating
> the file hash, which are described in commit?f9b2a735bddd "ima: audit
> log files opened with O_DIRECT flag". ?After reverting this commit,
> the O_DIRECT check is needed before calling generic_file_read_iter().

Thanks for the pointer. This cleaned up the issue for me.

> ?Most likely the same would need to be done for other filesystems that
> support O_DIRECT. ?Probably a generic_integrity_file_read_iter()
> should be defined.

Yeah, then please define some common helper that takes care of refusing
direct IO - IMO you should check this even before calling into
->integrity_read helper.

> For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
> the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
> lock has been taken. ?Assuming the file system is mounted with
> i_version, the file hash is updated properly.

Yes, for DAX direct IO is basically no different but frankly I would just
refuse O_DIRECT on DAX inodes as well just for the consistency sake.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-07 10:04               ` Jan Kara
@ 2017-08-07 20:12                 ` Mimi Zohar
  -1 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-07 20:12 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

On Mon, 2017-08-07 at 12:04 +0200, Jan Kara wrote:
> On Fri 04-08-17 17:07:11, Mimi Zohar wrote:
> > On Thu, 2017-08-03 at 12:56 +0200, Jan Kara wrote:
> > > On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> > > > On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > > > > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > > > > 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 <matthew.garrett@nebula.com>
> > > > > > 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 <yuchao0@huawei.com>
> > > > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > > > Cc: Richard Weinberger <richard@nod.at>
> > > > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > > > Cc: Hugh Dickins <hughd@google.com>
> > > > > > Cc: Chris Mason <clm@fb.com>
> > > > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > > > 
> > > > > ...
> > > > > 
> > > > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > > > +					     struct iov_iter *to)
> > > > > > +{
> > > > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > > > +
> > > > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > > > +		return -EIO;
> > > > > > +
> > > > > > +	if (!iov_iter_count(to))
> > > > > > +		return 0; /* skip atime */
> > > > > > +
> > > > > > +#ifdef CONFIG_FS_DAX
> > > > > > +	if (IS_DAX(inode))
> > > > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > > > +#endif
> > > > > > +	if (o_direct)
> > > > > > +		return -EINVAL;
> > > > > > +	return generic_file_read_iter(iocb, to);
> > > > > > +}
> > > > > 
> > > > > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > > > > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > > > > .integrity_read() methods?
> > > >  
> > > > This failure happens when opening a file with O_DIRECT on a block
> > > > device that does not support dax (eg. loop). xfs makes it to here too,
> > > > but the call to generic_file_read_iter() fails properly with -EINVAL. 
> > > > (Only tested on those filesystems included that support dax (eg. ext2,
> > > > ext4, and xfs).)
> > > 
> > > Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
> > > pretty much all filesystems except for XFS). However I fail to see why IMA
> > > should care (which is probably due to my lack of knowledge about IMA).
> > > Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?
> > 
> > Thank you for the explanation!  (I was confused about the relationship
> > between O_DIRECT and DAX.)  You're correct.  IMA does not support
> > O_DIRECT in the buffered case for two reasons, locking and updating
> > the file hash, which are described in commit f9b2a735bddd "ima: audit
> > log files opened with O_DIRECT flag".  After reverting this commit,
> > the O_DIRECT check is needed before calling generic_file_read_iter().
> 
> Thanks for the pointer. This cleaned up the issue for me.

Great!

> >  Most likely the same would need to be done for other filesystems that
> > support O_DIRECT.  Probably a generic_integrity_file_read_iter()
> > should be defined.
> 
> Yeah, then please define some common helper that takes care of refusing
> direct IO - IMO you should check this even before calling into
> ->integrity_read helper.

Agreed.

> > For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
> > the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
> > lock has been taken.  Assuming the file system is mounted with
> > i_version, the file hash is updated properly.
> 
> Yes, for DAX direct IO is basically no different but frankly I would just
> refuse O_DIRECT on DAX inodes as well just for the consistency sake.

Ok.  So I shouldn't revert the original commit, which fails the
O_DIRECT open for either the buffered read or DAX.  I'll just move the
code to a bit later, so that the failure is added to the measurement
list.

The original commit returned -EACCES.  On xfs, the open for direct IO
buffer read fails with -EINVAL.  Do you have a preference IMA should
return?

thanks!

Mimi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-07 20:12                 ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2017-08-07 20:12 UTC (permalink / raw)
  To: linux-security-module

On Mon, 2017-08-07 at 12:04 +0200, Jan Kara wrote:
> On Fri 04-08-17 17:07:11, Mimi Zohar wrote:
> > On Thu, 2017-08-03 at 12:56 +0200, Jan Kara wrote:
> > > On Wed 02-08-17 13:11:52, Mimi Zohar wrote:
> > > > On Wed, 2017-08-02 at 10:01 +0200, Jan Kara wrote:
> > > > > On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> > > > > > 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 <matthew.garrett@nebula.com>
> > > > > > 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 <yuchao0@huawei.com>
> > > > > > Cc: Steven Whitehouse <swhiteho@redhat.com>
> > > > > > Cc: Bob Peterson <rpeterso@redhat.com>
> > > > > > Cc: David Woodhouse <dwmw2@infradead.org>
> > > > > > Cc: Dave Kleikamp <shaggy@kernel.org>
> > > > > > Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> > > > > > Cc: Mark Fasheh <mfasheh@versity.com>
> > > > > > Cc: Joel Becker <jlbec@evilplan.org>
> > > > > > Cc: Richard Weinberger <richard@nod.at>
> > > > > > Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> > > > > > Cc: Hugh Dickins <hughd@google.com>
> > > > > > Cc: Chris Mason <clm@fb.com>
> > > > > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> > > > > 
> > > > > ...
> > > > > 
> > > > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > > > +					     struct iov_iter *to)
> > > > > > +{
> > > > > > +	struct inode *inode = file_inode(iocb->ki_filp);
> > > > > > +	int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > > > +
> > > > > > +	lockdep_assert_held(&inode->i_rwsem);
> > > > > > +	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > > > +		return -EIO;
> > > > > > +
> > > > > > +	if (!iov_iter_count(to))
> > > > > > +		return 0; /* skip atime */
> > > > > > +
> > > > > > +#ifdef CONFIG_FS_DAX
> > > > > > +	if (IS_DAX(inode))
> > > > > > +		return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > > > +#endif
> > > > > > +	if (o_direct)
> > > > > > +		return -EINVAL;
> > > > > > +	return generic_file_read_iter(iocb, to);
> > > > > > +}
> > > > > 
> > > > > I have noticed this o_direct check - why is it only in ext4 and shouldn't
> > > > > rather higher layers make sure IOCB_DIRECT iocbs cannot reach
> > > > > .integrity_read() methods?
> > > >  
> > > > This failure happens when opening a file with O_DIRECT on a block
> > > > device that does not support dax (eg. loop). xfs makes it to here too,
> > > > but the call to generic_file_read_iter() fails properly with -EINVAL.?
> > > > (Only tested on those filesystems included that support dax (eg. ext2,
> > > > ext4, and xfs).)
> > > 
> > > Well, yes, ext2 and ext4 will silently fall back to buffered read (as do
> > > pretty much all filesystems except for XFS). However I fail to see why IMA
> > > should care (which is probably due to my lack of knowledge about IMA).
> > > Is O_DIRECT somehow excepted from IMA? But then why it is not for DAX?
> > 
> > Thank you for the explanation! ?(I was confused about the relationship
> > between O_DIRECT and DAX.) ?You're correct. ?IMA does not support
> > O_DIRECT in the buffered case for two reasons, locking and updating
> > the file hash, which are described in commit?f9b2a735bddd "ima: audit
> > log files opened with O_DIRECT flag". ?After reverting this commit,
> > the O_DIRECT check is needed before calling generic_file_read_iter().
> 
> Thanks for the pointer. This cleaned up the issue for me.

Great!

> > ?Most likely the same would need to be done for other filesystems that
> > support O_DIRECT. ?Probably a generic_integrity_file_read_iter()
> > should be defined.
> 
> Yeah, then please define some common helper that takes care of refusing
> direct IO - IMO you should check this even before calling into
> ->integrity_read helper.

Agreed.

> > For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
> > the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
> > lock has been taken. ?Assuming the file system is mounted with
> > i_version, the file hash is updated properly.
> 
> Yes, for DAX direct IO is basically no different but frankly I would just
> refuse O_DIRECT on DAX inodes as well just for the consistency sake.

Ok. ?So I shouldn't revert the original commit, which fails the
O_DIRECT open for either the buffered read or DAX. ?I'll just move the
code to a bit later, so that the failure is added to the measurement
list.

The original commit returned -EACCES.??On xfs, the open for direct IO
buffer read fails with -EINVAL.??Do you have a preference IMA should
return?

thanks!

Mimi

--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
  2017-08-07 20:12                 ` Mimi Zohar
@ 2017-08-08 11:17                   ` Jan Kara
  -1 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-08 11:17 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Jan Kara, Christoph Hellwig, Al Viro, James Morris,
	linux-fsdevel, linux-ima-devel, linux-security-module,
	Matthew Garrett, Jan Kara, Theodore Ts'o, Andreas Dilger,
	Jaegeuk Kim, Chao Yu, Steven Whitehouse, Bob Peterson,
	David Woodhouse, Dave Kleikamp, Ryusuke Konishi, Mark Fasheh,
	Joel Becker, Richard Weinberger, Darrick J. Wong, Hugh Dickins,
	Chris Mason

On Mon 07-08-17 16:12:51, Mimi Zohar wrote:
> On Mon, 2017-08-07 at 12:04 +0200, Jan Kara wrote:
> > > For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
> > > the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
> > > lock has been taken. �Assuming the file system is mounted with
> > > i_version, the file hash is updated properly.
> > 
> > Yes, for DAX direct IO is basically no different but frankly I would just
> > refuse O_DIRECT on DAX inodes as well just for the consistency sake.
> 
> Ok. �So I shouldn't revert the original commit, which fails the
> O_DIRECT open for either the buffered read or DAX. �I'll just move the
> code to a bit later, so that the failure is added to the measurement
> list.
> 
> The original commit returned -EACCES.��On xfs, the open for direct IO
> buffer read fails with -EINVAL.��Do you have a preference IMA should
> return?

Not really. -EINVAL is more traditional when direct IO is not supported but
since IMA denies access to the file, -EACCES makes sense as well.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data [updated]
@ 2017-08-08 11:17                   ` Jan Kara
  0 siblings, 0 replies; 48+ messages in thread
From: Jan Kara @ 2017-08-08 11:17 UTC (permalink / raw)
  To: linux-security-module

On Mon 07-08-17 16:12:51, Mimi Zohar wrote:
> On Mon, 2017-08-07 at 12:04 +0200, Jan Kara wrote:
> > > For DAX, unlike do_blockdev_direct_IO() which takes the lock, reading
> > > the file with O_DIRECT is fine, as dax_iomap_rw() only checks that the
> > > lock has been taken. ?Assuming the file system is mounted with
> > > i_version, the file hash is updated properly.
> > 
> > Yes, for DAX direct IO is basically no different but frankly I would just
> > refuse O_DIRECT on DAX inodes as well just for the consistency sake.
> 
> Ok. ?So I shouldn't revert the original commit, which fails the
> O_DIRECT open for either the buffered read or DAX. ?I'll just move the
> code to a bit later, so that the failure is added to the measurement
> list.
> 
> The original commit returned -EACCES.??On xfs, the open for direct IO
> buffer read fails with -EINVAL.??Do you have a preference IMA should
> return?

Not really. -EINVAL is more traditional when direct IO is not supported but
since IMA denies access to the file, -EACCES makes sense as well.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Linux-ima-devel] [PATCH v4 1/5] ima: always measure and audit files in policy
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-08-22  9:24     ` Dmitry Kasatkin
  -1 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:24 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, linux-fsdevel, linux-ima-devel,
	linux-security-module

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> All files matching a "measure" rule must be included in the IMA
> measurement list, even when the file hash cannot be calculated.
> Similarly, all files matching an "audit" rule must be audited, even when
> the file hash can not be calculated.
>
> The file data hash field contained in the IMA measurement list template
> data will contain 0's instead of the actual file hash digest.
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> ---
> Changelog v4:
> - Based on both -EBADF and -EINVAL
> - clean up ima_collect_measurement()
>
>  security/integrity/ima/ima_api.c  | 58 +++++++++++++++++++++++----------------
>  security/integrity/ima/ima_main.c |  4 +--
>  2 files changed, 37 insertions(+), 25 deletions(-)
>
> diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
> index c2edba8de35e..bbf3ba8bbb09 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -199,37 +199,49 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
>         struct inode *inode = file_inode(file);
>         const char *filename = file->f_path.dentry->d_name.name;
>         int result = 0;
> +       int length;
> +       void *tmpbuf;
> +       u64 i_version;
>         struct {
>                 struct ima_digest_data hdr;
>                 char digest[IMA_MAX_DIGEST_SIZE];
>         } hash;
>
> -       if (!(iint->flags & IMA_COLLECTED)) {
> -               u64 i_version = file_inode(file)->i_version;
> +       if (iint->flags & IMA_COLLECTED)
> +               goto out;
>
> -               if (file->f_flags & O_DIRECT) {
> -                       audit_cause = "failed(directio)";
> -                       result = -EACCES;
> -                       goto out;
> -               }
> +       if (file->f_flags & O_DIRECT) {
> +               audit_cause = "failed(directio)";
> +               result = -EACCES;
> +               goto out;
> +       }
>
> -               hash.hdr.algo = algo;
> -
> -               result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
> -                       ima_calc_buffer_hash(buf, size, &hash.hdr);
> -               if (!result) {
> -                       int length = sizeof(hash.hdr) + hash.hdr.length;
> -                       void *tmpbuf = krealloc(iint->ima_hash, length,
> -                                               GFP_NOFS);
> -                       if (tmpbuf) {
> -                               iint->ima_hash = tmpbuf;
> -                               memcpy(iint->ima_hash, &hash, length);
> -                               iint->version = i_version;
> -                               iint->flags |= IMA_COLLECTED;
> -                       } else
> -                               result = -ENOMEM;
> -               }
> +       i_version = file_inode(file)->i_version;
> +       hash.hdr.algo = algo;
> +
> +       /* Initialize hash digest to 0's in case of failure */
> +       memset(&hash.digest, 0, sizeof(hash.digest));
> +
> +       result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
> +               ima_calc_buffer_hash(buf, size, &hash.hdr);
> +
> +       if (result && result != -EBADF && result != -EINVAL)
> +               goto out;
> +
> +       length = sizeof(hash.hdr) + hash.hdr.length;
> +       tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
> +       if (!tmpbuf) {
> +               result = -ENOMEM;
> +               goto out;
>         }
> +
> +       iint->ima_hash = tmpbuf;
> +       memcpy(iint->ima_hash, &hash, length);
> +       iint->version = i_version;
> +
> +       /* Possibly temporary failure due to type of read (eg. DAX, O_DIRECT) */
> +       if (result != -EBADF && result != -EINVAL)
> +               iint->flags |= IMA_COLLECTED;

Result can be other than 0, EBADF and EINVAL here?
It is confusing.. simpler than can be just

if (!result)
 iint->flags |= IMA_COLLECTED;

Isn't it?

>  out:
>         if (result)
>                 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 2aebb7984437..3941371402ff 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -235,7 +235,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>         hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
>
>         rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
> -       if (rc != 0) {
> +       if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
>                 if (file->f_flags & O_DIRECT)
>                         rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
>                 goto out_digsig;
> @@ -247,7 +247,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>         if (action & IMA_MEASURE)
>                 ima_store_measurement(iint, file, pathname,
>                                       xattr_value, xattr_len, pcr);
> -       if (action & IMA_APPRAISE_SUBMASK)
> +       if ((rc == 0) && (action & IMA_APPRAISE_SUBMASK))
>                 rc = ima_appraise_measurement(func, iint, file, pathname,
>                                               xattr_value, xattr_len, opened);
>         if (action & IMA_AUDIT)
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Linux-ima-devel] [PATCH v4 1/5] ima: always measure and audit files in policy
@ 2017-08-22  9:24     ` Dmitry Kasatkin
  0 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:24 UTC (permalink / raw)
  To: linux-security-module

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> All files matching a "measure" rule must be included in the IMA
> measurement list, even when the file hash cannot be calculated.
> Similarly, all files matching an "audit" rule must be audited, even when
> the file hash can not be calculated.
>
> The file data hash field contained in the IMA measurement list template
> data will contain 0's instead of the actual file hash digest.
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> ---
> Changelog v4:
> - Based on both -EBADF and -EINVAL
> - clean up ima_collect_measurement()
>
>  security/integrity/ima/ima_api.c  | 58 +++++++++++++++++++++++----------------
>  security/integrity/ima/ima_main.c |  4 +--
>  2 files changed, 37 insertions(+), 25 deletions(-)
>
> diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
> index c2edba8de35e..bbf3ba8bbb09 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -199,37 +199,49 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
>         struct inode *inode = file_inode(file);
>         const char *filename = file->f_path.dentry->d_name.name;
>         int result = 0;
> +       int length;
> +       void *tmpbuf;
> +       u64 i_version;
>         struct {
>                 struct ima_digest_data hdr;
>                 char digest[IMA_MAX_DIGEST_SIZE];
>         } hash;
>
> -       if (!(iint->flags & IMA_COLLECTED)) {
> -               u64 i_version = file_inode(file)->i_version;
> +       if (iint->flags & IMA_COLLECTED)
> +               goto out;
>
> -               if (file->f_flags & O_DIRECT) {
> -                       audit_cause = "failed(directio)";
> -                       result = -EACCES;
> -                       goto out;
> -               }
> +       if (file->f_flags & O_DIRECT) {
> +               audit_cause = "failed(directio)";
> +               result = -EACCES;
> +               goto out;
> +       }
>
> -               hash.hdr.algo = algo;
> -
> -               result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
> -                       ima_calc_buffer_hash(buf, size, &hash.hdr);
> -               if (!result) {
> -                       int length = sizeof(hash.hdr) + hash.hdr.length;
> -                       void *tmpbuf = krealloc(iint->ima_hash, length,
> -                                               GFP_NOFS);
> -                       if (tmpbuf) {
> -                               iint->ima_hash = tmpbuf;
> -                               memcpy(iint->ima_hash, &hash, length);
> -                               iint->version = i_version;
> -                               iint->flags |= IMA_COLLECTED;
> -                       } else
> -                               result = -ENOMEM;
> -               }
> +       i_version = file_inode(file)->i_version;
> +       hash.hdr.algo = algo;
> +
> +       /* Initialize hash digest to 0's in case of failure */
> +       memset(&hash.digest, 0, sizeof(hash.digest));
> +
> +       result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
> +               ima_calc_buffer_hash(buf, size, &hash.hdr);
> +
> +       if (result && result != -EBADF && result != -EINVAL)
> +               goto out;
> +
> +       length = sizeof(hash.hdr) + hash.hdr.length;
> +       tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
> +       if (!tmpbuf) {
> +               result = -ENOMEM;
> +               goto out;
>         }
> +
> +       iint->ima_hash = tmpbuf;
> +       memcpy(iint->ima_hash, &hash, length);
> +       iint->version = i_version;
> +
> +       /* Possibly temporary failure due to type of read (eg. DAX, O_DIRECT) */
> +       if (result != -EBADF && result != -EINVAL)
> +               iint->flags |= IMA_COLLECTED;

Result can be other than 0, EBADF and EINVAL here?
It is confusing.. simpler than can be just

if (!result)
 iint->flags |= IMA_COLLECTED;

Isn't it?

>  out:
>         if (result)
>                 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 2aebb7984437..3941371402ff 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -235,7 +235,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>         hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
>
>         rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
> -       if (rc != 0) {
> +       if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
>                 if (file->f_flags & O_DIRECT)
>                         rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
>                 goto out_digsig;
> @@ -247,7 +247,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>         if (action & IMA_MEASURE)
>                 ima_store_measurement(iint, file, pathname,
>                                       xattr_value, xattr_len, pcr);
> -       if (action & IMA_APPRAISE_SUBMASK)
> +       if ((rc == 0) && (action & IMA_APPRAISE_SUBMASK))
>                 rc = ima_appraise_measurement(func, iint, file, pathname,
>                                               xattr_value, xattr_len, opened);
>         if (action & IMA_AUDIT)
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Linux-ima-devel] [PATCH v4 5/5] ima: remove permit_directio policy option
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-08-22  9:27     ` Dmitry Kasatkin
  -1 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:27 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, linux-fsdevel, linux-ima-devel,
	linux-security-module

Looks good to me.

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> With the new ->integrity_read file_operations method support, files
> opened with the O_DIRECT flag should work properly.  This patch
> reverts commit f9b2a735bddd "ima: audit log files opened with O_DIRECT
> flag".
>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> ---
>  Documentation/ABI/testing/ima_policy | 2 +-
>  security/integrity/ima/ima_api.c     | 6 ------
>  security/integrity/ima/ima_main.c    | 5 +----
>  security/integrity/ima/ima_policy.c  | 8 +-------
>  security/integrity/integrity.h       | 1 -
>  5 files changed, 3 insertions(+), 19 deletions(-)
>
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index f271207743e5..441a78e7b87e 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -24,7 +24,7 @@ Description:
>                                 [euid=] [fowner=]]
>                         lsm:    [[subj_user=] [subj_role=] [subj_type=]
>                                  [obj_user=] [obj_role=] [obj_type=]]
> -                       option: [[appraise_type=]] [permit_directio]
> +                       option: [[appraise_type=]]
>
>                 base:   func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
>                                 [FIRMWARE_CHECK]
> diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
> index bbf3ba8bbb09..7bc8e76c06f5 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -210,12 +210,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
>         if (iint->flags & IMA_COLLECTED)
>                 goto out;
>
> -       if (file->f_flags & O_DIRECT) {
> -               audit_cause = "failed(directio)";
> -               result = -EACCES;
> -               goto out;
> -       }
> -
>         i_version = file_inode(file)->i_version;
>         hash.hdr.algo = algo;
>
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 664edab0f758..9b8ede84337f 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -240,11 +240,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>         hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
>
>         rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
> -       if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
> -               if (file->f_flags & O_DIRECT)
> -                       rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
> +       if (rc != 0 && rc != -EBADF && rc != -EINVAL)
>                 goto out_digsig;
> -       }
>
>         if (!pathbuf)   /* ima_rdwr_violation possibly pre-fetched */
>                 pathname = ima_d_path(&file->f_path, &pathbuf, filename);
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index cddd9dfb01e1..3b54fb32e837 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -545,7 +545,7 @@ enum {
>         Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
>         Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
>         Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
> -       Opt_appraise_type, Opt_permit_directio,
> +       Opt_appraise_type,
>         Opt_pcr, Opt_dont_failsafe
>  };
>
> @@ -575,7 +575,6 @@ static match_table_t policy_tokens = {
>         {Opt_euid_lt, "euid<%s"},
>         {Opt_fowner_lt, "fowner<%s"},
>         {Opt_appraise_type, "appraise_type=%s"},
> -       {Opt_permit_directio, "permit_directio"},
>         {Opt_pcr, "pcr=%s"},
>         {Opt_dont_failsafe, "dont_failsafe"},
>         {Opt_err, NULL}
> @@ -892,9 +891,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>                         else
>                                 result = -EINVAL;
>                         break;
> -               case Opt_permit_directio:
> -                       entry->flags |= IMA_PERMIT_DIRECTIO;
> -                       break;
>                 case Opt_pcr:
>                         if (entry->action != MEASURE) {
>                                 result = -EINVAL;
> @@ -1179,8 +1175,6 @@ int ima_policy_show(struct seq_file *m, void *v)
>         }
>         if (entry->flags & IMA_DIGSIG_REQUIRED)
>                 seq_puts(m, "appraise_type=imasig ");
> -       if (entry->flags & IMA_PERMIT_DIRECTIO)
> -               seq_puts(m, "permit_directio ");
>         rcu_read_unlock();
>         seq_puts(m, "\n");
>         return 0;
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index a53e7e4ab06c..790f07e515a7 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -31,7 +31,6 @@
>  #define IMA_ACTION_RULE_FLAGS  0x06000000
>  #define IMA_DIGSIG             0x01000000
>  #define IMA_DIGSIG_REQUIRED    0x02000000
> -#define IMA_PERMIT_DIRECTIO    0x04000000
>  #define IMA_NEW_FILE           0x08000000
>
>  #define IMA_DO_MASK            (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Linux-ima-devel] [PATCH v4 5/5] ima: remove permit_directio policy option
@ 2017-08-22  9:27     ` Dmitry Kasatkin
  0 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:27 UTC (permalink / raw)
  To: linux-security-module

Looks good to me.

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> With the new ->integrity_read file_operations method support, files
> opened with the O_DIRECT flag should work properly.  This patch
> reverts commit f9b2a735bddd "ima: audit log files opened with O_DIRECT
> flag".
>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> ---
>  Documentation/ABI/testing/ima_policy | 2 +-
>  security/integrity/ima/ima_api.c     | 6 ------
>  security/integrity/ima/ima_main.c    | 5 +----
>  security/integrity/ima/ima_policy.c  | 8 +-------
>  security/integrity/integrity.h       | 1 -
>  5 files changed, 3 insertions(+), 19 deletions(-)
>
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index f271207743e5..441a78e7b87e 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -24,7 +24,7 @@ Description:
>                                 [euid=] [fowner=]]
>                         lsm:    [[subj_user=] [subj_role=] [subj_type=]
>                                  [obj_user=] [obj_role=] [obj_type=]]
> -                       option: [[appraise_type=]] [permit_directio]
> +                       option: [[appraise_type=]]
>
>                 base:   func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
>                                 [FIRMWARE_CHECK]
> diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
> index bbf3ba8bbb09..7bc8e76c06f5 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -210,12 +210,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
>         if (iint->flags & IMA_COLLECTED)
>                 goto out;
>
> -       if (file->f_flags & O_DIRECT) {
> -               audit_cause = "failed(directio)";
> -               result = -EACCES;
> -               goto out;
> -       }
> -
>         i_version = file_inode(file)->i_version;
>         hash.hdr.algo = algo;
>
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 664edab0f758..9b8ede84337f 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -240,11 +240,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>         hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
>
>         rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
> -       if (rc != 0 && rc != -EBADF && rc != -EINVAL) {
> -               if (file->f_flags & O_DIRECT)
> -                       rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
> +       if (rc != 0 && rc != -EBADF && rc != -EINVAL)
>                 goto out_digsig;
> -       }
>
>         if (!pathbuf)   /* ima_rdwr_violation possibly pre-fetched */
>                 pathname = ima_d_path(&file->f_path, &pathbuf, filename);
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index cddd9dfb01e1..3b54fb32e837 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -545,7 +545,7 @@ enum {
>         Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
>         Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
>         Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
> -       Opt_appraise_type, Opt_permit_directio,
> +       Opt_appraise_type,
>         Opt_pcr, Opt_dont_failsafe
>  };
>
> @@ -575,7 +575,6 @@ static match_table_t policy_tokens = {
>         {Opt_euid_lt, "euid<%s"},
>         {Opt_fowner_lt, "fowner<%s"},
>         {Opt_appraise_type, "appraise_type=%s"},
> -       {Opt_permit_directio, "permit_directio"},
>         {Opt_pcr, "pcr=%s"},
>         {Opt_dont_failsafe, "dont_failsafe"},
>         {Opt_err, NULL}
> @@ -892,9 +891,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>                         else
>                                 result = -EINVAL;
>                         break;
> -               case Opt_permit_directio:
> -                       entry->flags |= IMA_PERMIT_DIRECTIO;
> -                       break;
>                 case Opt_pcr:
>                         if (entry->action != MEASURE) {
>                                 result = -EINVAL;
> @@ -1179,8 +1175,6 @@ int ima_policy_show(struct seq_file *m, void *v)
>         }
>         if (entry->flags & IMA_DIGSIG_REQUIRED)
>                 seq_puts(m, "appraise_type=imasig ");
> -       if (entry->flags & IMA_PERMIT_DIRECTIO)
> -               seq_puts(m, "permit_directio ");
>         rcu_read_unlock();
>         seq_puts(m, "\n");
>         return 0;
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index a53e7e4ab06c..790f07e515a7 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -31,7 +31,6 @@
>  #define IMA_ACTION_RULE_FLAGS  0x06000000
>  #define IMA_DIGSIG             0x01000000
>  #define IMA_DIGSIG_REQUIRED    0x02000000
> -#define IMA_PERMIT_DIRECTIO    0x04000000
>  #define IMA_NEW_FILE           0x08000000
>
>  #define IMA_DO_MASK            (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Linux-ima-devel] [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-08-22  9:34     ` Dmitry Kasatkin
  -1 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:34 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, linux-fsdevel, linux-ima-devel,
	linux-security-module

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> Permit normally denied access/execute permission for files in policy
> on IMA unsupported filesystems.  This patch defines the "dont_failsafe"
> policy action rule.
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> ---
> Changelog v3:
> - include dont_failsafe rule when displaying policy
> - fail attempt to add dont_failsafe rule when appending to the policy
>
>  Documentation/ABI/testing/ima_policy |  3 ++-
>  security/integrity/ima/ima.h         |  1 +
>  security/integrity/ima/ima_main.c    | 11 ++++++++++-
>  security/integrity/ima/ima_policy.c  | 29 ++++++++++++++++++++++++++++-
>  4 files changed, 41 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index e76432b9954d..f271207743e5 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -17,7 +17,8 @@ Description:
>
>                 rule format: action [condition ...]
>
> -               action: measure | dont_measure | appraise | dont_appraise | audit
> +               action: measure | dont_meaure | appraise | dont_appraise |
> +                       audit | dont_failsafe
>                 condition:= base | lsm  [option]
>                         base:   [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
>                                 [euid=] [fowner=]]
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index d52b487ad259..c5f34f7c5b0f 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -224,6 +224,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
>  void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
>  void ima_policy_stop(struct seq_file *m, void *v);
>  int ima_policy_show(struct seq_file *m, void *v);
> +void set_failsafe(bool flag);
>
>  /* Appraise integrity measurements */
>  #define IMA_APPRAISE_ENFORCE   0x01
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 3941371402ff..664edab0f758 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -38,6 +38,11 @@ int ima_appraise;
>  int ima_hash_algo = HASH_ALGO_SHA1;
>  static int hash_setup_done;
>
> +static bool ima_failsafe = 1;
> +void set_failsafe(bool flag) {
> +       ima_failsafe = flag;
> +}
> +
>  static int __init hash_setup(char *str)
>  {
>         struct ima_template_desc *template_desc = ima_template_desc_current();
> @@ -263,8 +268,12 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>                 __putname(pathbuf);
>  out:
>         inode_unlock(inode);
> -       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
> +       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) {
> +               if (!ima_failsafe && rc == -EBADF)
> +                       return 0;
> +

By default IMA is failsaif. ima_failsafe is true.
Return 0 is needed in failsafe mode. right?
But in this logic it will happen if ima_failsafe is false. meaning it
is not failsafe.
Is it a typo?


>                 return -EACCES;
> +       }
>         return 0;
>  }
>
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 95209a5f8595..43b85a4fb8e8 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -40,12 +40,14 @@
>  #define APPRAISE       0x0004  /* same as IMA_APPRAISE */
>  #define DONT_APPRAISE  0x0008
>  #define AUDIT          0x0040
> +#define DONT_FAILSAFE  0x0400
>
>  #define INVALID_PCR(a) (((a) < 0) || \
>         (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
>
>  int ima_policy_flag;
>  static int temp_ima_appraise;
> +static bool temp_failsafe = 1;
>
>  #define MAX_LSM_RULES 6
>  enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
> @@ -513,6 +515,9 @@ void ima_update_policy(void)
>         if (ima_rules != policy) {
>                 ima_policy_flag = 0;
>                 ima_rules = policy;
> +
> +               /* Only update on initial policy replacement, not append */
> +               set_failsafe(temp_failsafe);
>         }
>         ima_update_policy_flag();
>  }
> @@ -529,7 +534,7 @@ enum {
>         Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
>         Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
>         Opt_appraise_type, Opt_permit_directio,
> -       Opt_pcr
> +       Opt_pcr, Opt_dont_failsafe
>  };
>
>  static match_table_t policy_tokens = {
> @@ -560,6 +565,7 @@ static match_table_t policy_tokens = {
>         {Opt_appraise_type, "appraise_type=%s"},
>         {Opt_permit_directio, "permit_directio"},
>         {Opt_pcr, "pcr=%s"},
> +       {Opt_dont_failsafe, "dont_failsafe"},
>         {Opt_err, NULL}
>  };
>
> @@ -630,6 +636,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>                 if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
>                         continue;
>                 token = match_token(p, policy_tokens, args);
> +               if (entry->action == DONT_FAILSAFE) {
> +                       /* no args permitted, force invalid rule */
> +                       token = Opt_dont_failsafe;
> +               }
> +
>                 switch (token) {
>                 case Opt_measure:
>                         ima_log_string(ab, "action", "measure");
> @@ -671,6 +682,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>
>                         entry->action = AUDIT;
>                         break;
> +               case Opt_dont_failsafe:
> +                       ima_log_string(ab, "action", "dont_failsafe");
> +
> +                       if (entry->action != UNKNOWN)
> +                               result = -EINVAL;
> +
> +                       /* Permit on initial policy replacement only */
> +                       if (ima_rules != &ima_policy_rules)
> +                               temp_failsafe = 0;
> +                       else
> +                               result = -EINVAL;
> +                       entry->action = DONT_FAILSAFE;
> +                       break;
>                 case Opt_func:
>                         ima_log_string(ab, "func", args[0].from);
>
> @@ -949,6 +973,7 @@ void ima_delete_rules(void)
>         int i;
>
>         temp_ima_appraise = 0;
> +       temp_failsafe = 1;
>         list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
>                 for (i = 0; i < MAX_LSM_RULES; i++)
>                         kfree(entry->lsm[i].args_p);
> @@ -1040,6 +1065,8 @@ int ima_policy_show(struct seq_file *m, void *v)
>                 seq_puts(m, pt(Opt_dont_appraise));
>         if (entry->action & AUDIT)
>                 seq_puts(m, pt(Opt_audit));
> +       if (entry->action & DONT_FAILSAFE)
> +               seq_puts(m, pt(Opt_dont_failsafe));
>
>         seq_puts(m, " ");
>
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Linux-ima-devel] [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule
@ 2017-08-22  9:34     ` Dmitry Kasatkin
  0 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:34 UTC (permalink / raw)
  To: linux-security-module

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> Permit normally denied access/execute permission for files in policy
> on IMA unsupported filesystems.  This patch defines the "dont_failsafe"
> policy action rule.
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> ---
> Changelog v3:
> - include dont_failsafe rule when displaying policy
> - fail attempt to add dont_failsafe rule when appending to the policy
>
>  Documentation/ABI/testing/ima_policy |  3 ++-
>  security/integrity/ima/ima.h         |  1 +
>  security/integrity/ima/ima_main.c    | 11 ++++++++++-
>  security/integrity/ima/ima_policy.c  | 29 ++++++++++++++++++++++++++++-
>  4 files changed, 41 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index e76432b9954d..f271207743e5 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -17,7 +17,8 @@ Description:
>
>                 rule format: action [condition ...]
>
> -               action: measure | dont_measure | appraise | dont_appraise | audit
> +               action: measure | dont_meaure | appraise | dont_appraise |
> +                       audit | dont_failsafe
>                 condition:= base | lsm  [option]
>                         base:   [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
>                                 [euid=] [fowner=]]
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index d52b487ad259..c5f34f7c5b0f 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -224,6 +224,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
>  void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
>  void ima_policy_stop(struct seq_file *m, void *v);
>  int ima_policy_show(struct seq_file *m, void *v);
> +void set_failsafe(bool flag);
>
>  /* Appraise integrity measurements */
>  #define IMA_APPRAISE_ENFORCE   0x01
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 3941371402ff..664edab0f758 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -38,6 +38,11 @@ int ima_appraise;
>  int ima_hash_algo = HASH_ALGO_SHA1;
>  static int hash_setup_done;
>
> +static bool ima_failsafe = 1;
> +void set_failsafe(bool flag) {
> +       ima_failsafe = flag;
> +}
> +
>  static int __init hash_setup(char *str)
>  {
>         struct ima_template_desc *template_desc = ima_template_desc_current();
> @@ -263,8 +268,12 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>                 __putname(pathbuf);
>  out:
>         inode_unlock(inode);
> -       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
> +       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) {
> +               if (!ima_failsafe && rc == -EBADF)
> +                       return 0;
> +

By default IMA is failsaif. ima_failsafe is true.
Return 0 is needed in failsafe mode. right?
But in this logic it will happen if ima_failsafe is false. meaning it
is not failsafe.
Is it a typo?


>                 return -EACCES;
> +       }
>         return 0;
>  }
>
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 95209a5f8595..43b85a4fb8e8 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -40,12 +40,14 @@
>  #define APPRAISE       0x0004  /* same as IMA_APPRAISE */
>  #define DONT_APPRAISE  0x0008
>  #define AUDIT          0x0040
> +#define DONT_FAILSAFE  0x0400
>
>  #define INVALID_PCR(a) (((a) < 0) || \
>         (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
>
>  int ima_policy_flag;
>  static int temp_ima_appraise;
> +static bool temp_failsafe = 1;
>
>  #define MAX_LSM_RULES 6
>  enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
> @@ -513,6 +515,9 @@ void ima_update_policy(void)
>         if (ima_rules != policy) {
>                 ima_policy_flag = 0;
>                 ima_rules = policy;
> +
> +               /* Only update on initial policy replacement, not append */
> +               set_failsafe(temp_failsafe);
>         }
>         ima_update_policy_flag();
>  }
> @@ -529,7 +534,7 @@ enum {
>         Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
>         Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
>         Opt_appraise_type, Opt_permit_directio,
> -       Opt_pcr
> +       Opt_pcr, Opt_dont_failsafe
>  };
>
>  static match_table_t policy_tokens = {
> @@ -560,6 +565,7 @@ static match_table_t policy_tokens = {
>         {Opt_appraise_type, "appraise_type=%s"},
>         {Opt_permit_directio, "permit_directio"},
>         {Opt_pcr, "pcr=%s"},
> +       {Opt_dont_failsafe, "dont_failsafe"},
>         {Opt_err, NULL}
>  };
>
> @@ -630,6 +636,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>                 if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
>                         continue;
>                 token = match_token(p, policy_tokens, args);
> +               if (entry->action == DONT_FAILSAFE) {
> +                       /* no args permitted, force invalid rule */
> +                       token = Opt_dont_failsafe;
> +               }
> +
>                 switch (token) {
>                 case Opt_measure:
>                         ima_log_string(ab, "action", "measure");
> @@ -671,6 +682,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>
>                         entry->action = AUDIT;
>                         break;
> +               case Opt_dont_failsafe:
> +                       ima_log_string(ab, "action", "dont_failsafe");
> +
> +                       if (entry->action != UNKNOWN)
> +                               result = -EINVAL;
> +
> +                       /* Permit on initial policy replacement only */
> +                       if (ima_rules != &ima_policy_rules)
> +                               temp_failsafe = 0;
> +                       else
> +                               result = -EINVAL;
> +                       entry->action = DONT_FAILSAFE;
> +                       break;
>                 case Opt_func:
>                         ima_log_string(ab, "func", args[0].from);
>
> @@ -949,6 +973,7 @@ void ima_delete_rules(void)
>         int i;
>
>         temp_ima_appraise = 0;
> +       temp_failsafe = 1;
>         list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
>                 for (i = 0; i < MAX_LSM_RULES; i++)
>                         kfree(entry->lsm[i].args_p);
> @@ -1040,6 +1065,8 @@ int ima_policy_show(struct seq_file *m, void *v)
>                 seq_puts(m, pt(Opt_dont_appraise));
>         if (entry->action & AUDIT)
>                 seq_puts(m, pt(Opt_audit));
> +       if (entry->action & DONT_FAILSAFE)
> +               seq_puts(m, pt(Opt_dont_failsafe));
>
>         seq_puts(m, " ");
>
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Linux-ima-devel] [PATCH v4 4/5] ima: define "fs_unsafe" builtin policy
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-08-22  9:36     ` Dmitry Kasatkin
  -1 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:36 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, linux-fsdevel, linux-ima-devel,
	linux-security-module

Looks good to me.

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> Permit normally denied access/execute permission for files in policy
> on IMA unsupported filesystems.  This patch defines "fs_unsafe", a
> builtin policy.
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> ---
> Changelog v3:
> - include dont_failsafe rule when displaying policy
>
>  Documentation/admin-guide/kernel-parameters.txt |  8 +++++++-
>  security/integrity/ima/ima_policy.c             | 12 ++++++++++++
>  2 files changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index d9c171ce4190..4e303be83df6 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1502,7 +1502,7 @@
>
>         ima_policy=     [IMA]
>                         The builtin policies to load during IMA setup.
> -                       Format: "tcb | appraise_tcb | secure_boot"
> +                       Format: "tcb | appraise_tcb | secure_boot | fs_unsafe"
>
>                         The "tcb" policy measures all programs exec'd, files
>                         mmap'd for exec, and all files opened with the read
> @@ -1517,6 +1517,12 @@
>                         of files (eg. kexec kernel image, kernel modules,
>                         firmware, policy, etc) based on file signatures.
>
> +                       The "fs_unsafe" policy permits normally denied
> +                       access/execute permission for files in policy on IMA
> +                       unsupported filesystems.  Note this option, as the
> +                       name implies, is not safe and not recommended for
> +                       any environments other than testing.
> +
>         ima_tcb         [IMA] Deprecated.  Use ima_policy= instead.
>                         Load a policy which meets the needs of the Trusted
>                         Computing Base.  This means IMA will measure all
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 43b85a4fb8e8..cddd9dfb01e1 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -169,6 +169,10 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
>          .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
>  };
>
> +static struct ima_rule_entry dont_failsafe_rules[] __ro_after_init = {
> +       {.action = DONT_FAILSAFE}
> +};
> +
>  static LIST_HEAD(ima_default_rules);
>  static LIST_HEAD(ima_policy_rules);
>  static LIST_HEAD(ima_temp_rules);
> @@ -188,6 +192,7 @@ __setup("ima_tcb", default_measure_policy_setup);
>
>  static bool ima_use_appraise_tcb __initdata;
>  static bool ima_use_secure_boot __initdata;
> +static bool ima_use_dont_failsafe __initdata;
>  static int __init policy_setup(char *str)
>  {
>         char *p;
> @@ -201,6 +206,10 @@ static int __init policy_setup(char *str)
>                         ima_use_appraise_tcb = 1;
>                 else if (strcmp(p, "secure_boot") == 0)
>                         ima_use_secure_boot = 1;
> +               else if (strcmp(p, "fs_unsafe") == 0) {
> +                       ima_use_dont_failsafe = 1;
> +                       set_failsafe(0);
> +               }
>         }
>
>         return 1;
> @@ -470,6 +479,9 @@ void __init ima_init_policy(void)
>                         temp_ima_appraise |= IMA_APPRAISE_POLICY;
>         }
>
> +       if (ima_use_dont_failsafe)
> +               list_add_tail(&dont_failsafe_rules[0].list, &ima_default_rules);
> +
>         ima_rules = &ima_default_rules;
>         ima_update_policy_flag();
>  }
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Linux-ima-devel] [PATCH v4 4/5] ima: define "fs_unsafe" builtin policy
@ 2017-08-22  9:36     ` Dmitry Kasatkin
  0 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:36 UTC (permalink / raw)
  To: linux-security-module

Looks good to me.

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> Permit normally denied access/execute permission for files in policy
> on IMA unsupported filesystems.  This patch defines "fs_unsafe", a
> builtin policy.
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> ---
> Changelog v3:
> - include dont_failsafe rule when displaying policy
>
>  Documentation/admin-guide/kernel-parameters.txt |  8 +++++++-
>  security/integrity/ima/ima_policy.c             | 12 ++++++++++++
>  2 files changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index d9c171ce4190..4e303be83df6 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1502,7 +1502,7 @@
>
>         ima_policy=     [IMA]
>                         The builtin policies to load during IMA setup.
> -                       Format: "tcb | appraise_tcb | secure_boot"
> +                       Format: "tcb | appraise_tcb | secure_boot | fs_unsafe"
>
>                         The "tcb" policy measures all programs exec'd, files
>                         mmap'd for exec, and all files opened with the read
> @@ -1517,6 +1517,12 @@
>                         of files (eg. kexec kernel image, kernel modules,
>                         firmware, policy, etc) based on file signatures.
>
> +                       The "fs_unsafe" policy permits normally denied
> +                       access/execute permission for files in policy on IMA
> +                       unsupported filesystems.  Note this option, as the
> +                       name implies, is not safe and not recommended for
> +                       any environments other than testing.
> +
>         ima_tcb         [IMA] Deprecated.  Use ima_policy= instead.
>                         Load a policy which meets the needs of the Trusted
>                         Computing Base.  This means IMA will measure all
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 43b85a4fb8e8..cddd9dfb01e1 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -169,6 +169,10 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
>          .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
>  };
>
> +static struct ima_rule_entry dont_failsafe_rules[] __ro_after_init = {
> +       {.action = DONT_FAILSAFE}
> +};
> +
>  static LIST_HEAD(ima_default_rules);
>  static LIST_HEAD(ima_policy_rules);
>  static LIST_HEAD(ima_temp_rules);
> @@ -188,6 +192,7 @@ __setup("ima_tcb", default_measure_policy_setup);
>
>  static bool ima_use_appraise_tcb __initdata;
>  static bool ima_use_secure_boot __initdata;
> +static bool ima_use_dont_failsafe __initdata;
>  static int __init policy_setup(char *str)
>  {
>         char *p;
> @@ -201,6 +206,10 @@ static int __init policy_setup(char *str)
>                         ima_use_appraise_tcb = 1;
>                 else if (strcmp(p, "secure_boot") == 0)
>                         ima_use_secure_boot = 1;
> +               else if (strcmp(p, "fs_unsafe") == 0) {
> +                       ima_use_dont_failsafe = 1;
> +                       set_failsafe(0);
> +               }
>         }
>
>         return 1;
> @@ -470,6 +479,9 @@ void __init ima_init_policy(void)
>                         temp_ima_appraise |= IMA_APPRAISE_POLICY;
>         }
>
> +       if (ima_use_dont_failsafe)
> +               list_add_tail(&dont_failsafe_rules[0].list, &ima_default_rules);
> +
>         ima_rules = &ima_default_rules;
>         ima_update_policy_flag();
>  }
> --
> 2.7.4
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-ima-devel mailing list
> Linux-ima-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel



-- 
Thanks,
Dmitry
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Linux-ima-devel] [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule
  2017-08-22  9:34     ` Dmitry Kasatkin
@ 2017-08-22  9:39       ` Dmitry Kasatkin
  -1 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:39 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, linux-fsdevel, linux-ima-devel,
	linux-security-module

Also where is checking for DONT_FAILSAFE (enforcement)?


On Tue, Aug 22, 2017 at 12:34 PM, Dmitry Kasatkin
<dmitry.kasatkin@gmail.com> wrote:
> On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
>> Permit normally denied access/execute permission for files in policy
>> on IMA unsupported filesystems.  This patch defines the "dont_failsafe"
>> policy action rule.
>>
>> Mimi Zohar <zohar@linux.vnet.ibm.com>
>>
>> ---
>> Changelog v3:
>> - include dont_failsafe rule when displaying policy
>> - fail attempt to add dont_failsafe rule when appending to the policy
>>
>>  Documentation/ABI/testing/ima_policy |  3 ++-
>>  security/integrity/ima/ima.h         |  1 +
>>  security/integrity/ima/ima_main.c    | 11 ++++++++++-
>>  security/integrity/ima/ima_policy.c  | 29 ++++++++++++++++++++++++++++-
>>  4 files changed, 41 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
>> index e76432b9954d..f271207743e5 100644
>> --- a/Documentation/ABI/testing/ima_policy
>> +++ b/Documentation/ABI/testing/ima_policy
>> @@ -17,7 +17,8 @@ Description:
>>
>>                 rule format: action [condition ...]
>>
>> -               action: measure | dont_measure | appraise | dont_appraise | audit
>> +               action: measure | dont_meaure | appraise | dont_appraise |
>> +                       audit | dont_failsafe
>>                 condition:= base | lsm  [option]
>>                         base:   [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
>>                                 [euid=] [fowner=]]
>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>> index d52b487ad259..c5f34f7c5b0f 100644
>> --- a/security/integrity/ima/ima.h
>> +++ b/security/integrity/ima/ima.h
>> @@ -224,6 +224,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
>>  void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
>>  void ima_policy_stop(struct seq_file *m, void *v);
>>  int ima_policy_show(struct seq_file *m, void *v);
>> +void set_failsafe(bool flag);
>>
>>  /* Appraise integrity measurements */
>>  #define IMA_APPRAISE_ENFORCE   0x01
>> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
>> index 3941371402ff..664edab0f758 100644
>> --- a/security/integrity/ima/ima_main.c
>> +++ b/security/integrity/ima/ima_main.c
>> @@ -38,6 +38,11 @@ int ima_appraise;
>>  int ima_hash_algo = HASH_ALGO_SHA1;
>>  static int hash_setup_done;
>>
>> +static bool ima_failsafe = 1;
>> +void set_failsafe(bool flag) {
>> +       ima_failsafe = flag;
>> +}
>> +
>>  static int __init hash_setup(char *str)
>>  {
>>         struct ima_template_desc *template_desc = ima_template_desc_current();
>> @@ -263,8 +268,12 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>>                 __putname(pathbuf);
>>  out:
>>         inode_unlock(inode);
>> -       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
>> +       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) {
>> +               if (!ima_failsafe && rc == -EBADF)
>> +                       return 0;
>> +
>
> By default IMA is failsaif. ima_failsafe is true.
> Return 0 is needed in failsafe mode. right?
> But in this logic it will happen if ima_failsafe is false. meaning it
> is not failsafe.
> Is it a typo?
>
>
>>                 return -EACCES;
>> +       }
>>         return 0;
>>  }
>>
>> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
>> index 95209a5f8595..43b85a4fb8e8 100644
>> --- a/security/integrity/ima/ima_policy.c
>> +++ b/security/integrity/ima/ima_policy.c
>> @@ -40,12 +40,14 @@
>>  #define APPRAISE       0x0004  /* same as IMA_APPRAISE */
>>  #define DONT_APPRAISE  0x0008
>>  #define AUDIT          0x0040
>> +#define DONT_FAILSAFE  0x0400
>>
>>  #define INVALID_PCR(a) (((a) < 0) || \
>>         (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
>>
>>  int ima_policy_flag;
>>  static int temp_ima_appraise;
>> +static bool temp_failsafe = 1;
>>
>>  #define MAX_LSM_RULES 6
>>  enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
>> @@ -513,6 +515,9 @@ void ima_update_policy(void)
>>         if (ima_rules != policy) {
>>                 ima_policy_flag = 0;
>>                 ima_rules = policy;
>> +
>> +               /* Only update on initial policy replacement, not append */
>> +               set_failsafe(temp_failsafe);
>>         }
>>         ima_update_policy_flag();
>>  }
>> @@ -529,7 +534,7 @@ enum {
>>         Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
>>         Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
>>         Opt_appraise_type, Opt_permit_directio,
>> -       Opt_pcr
>> +       Opt_pcr, Opt_dont_failsafe
>>  };
>>
>>  static match_table_t policy_tokens = {
>> @@ -560,6 +565,7 @@ static match_table_t policy_tokens = {
>>         {Opt_appraise_type, "appraise_type=%s"},
>>         {Opt_permit_directio, "permit_directio"},
>>         {Opt_pcr, "pcr=%s"},
>> +       {Opt_dont_failsafe, "dont_failsafe"},
>>         {Opt_err, NULL}
>>  };
>>
>> @@ -630,6 +636,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>>                 if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
>>                         continue;
>>                 token = match_token(p, policy_tokens, args);
>> +               if (entry->action == DONT_FAILSAFE) {
>> +                       /* no args permitted, force invalid rule */
>> +                       token = Opt_dont_failsafe;
>> +               }
>> +
>>                 switch (token) {
>>                 case Opt_measure:
>>                         ima_log_string(ab, "action", "measure");
>> @@ -671,6 +682,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>>
>>                         entry->action = AUDIT;
>>                         break;
>> +               case Opt_dont_failsafe:
>> +                       ima_log_string(ab, "action", "dont_failsafe");
>> +
>> +                       if (entry->action != UNKNOWN)
>> +                               result = -EINVAL;
>> +
>> +                       /* Permit on initial policy replacement only */
>> +                       if (ima_rules != &ima_policy_rules)
>> +                               temp_failsafe = 0;
>> +                       else
>> +                               result = -EINVAL;
>> +                       entry->action = DONT_FAILSAFE;
>> +                       break;
>>                 case Opt_func:
>>                         ima_log_string(ab, "func", args[0].from);
>>
>> @@ -949,6 +973,7 @@ void ima_delete_rules(void)
>>         int i;
>>
>>         temp_ima_appraise = 0;
>> +       temp_failsafe = 1;
>>         list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
>>                 for (i = 0; i < MAX_LSM_RULES; i++)
>>                         kfree(entry->lsm[i].args_p);
>> @@ -1040,6 +1065,8 @@ int ima_policy_show(struct seq_file *m, void *v)
>>                 seq_puts(m, pt(Opt_dont_appraise));
>>         if (entry->action & AUDIT)
>>                 seq_puts(m, pt(Opt_audit));
>> +       if (entry->action & DONT_FAILSAFE)
>> +               seq_puts(m, pt(Opt_dont_failsafe));
>>
>>         seq_puts(m, " ");
>>
>> --
>> 2.7.4
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> Linux-ima-devel mailing list
>> Linux-ima-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel
>
>
>
> --
> Thanks,
> Dmitry



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Linux-ima-devel] [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule
@ 2017-08-22  9:39       ` Dmitry Kasatkin
  0 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:39 UTC (permalink / raw)
  To: linux-security-module

Also where is checking for DONT_FAILSAFE (enforcement)?


On Tue, Aug 22, 2017 at 12:34 PM, Dmitry Kasatkin
<dmitry.kasatkin@gmail.com> wrote:
> On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
>> Permit normally denied access/execute permission for files in policy
>> on IMA unsupported filesystems.  This patch defines the "dont_failsafe"
>> policy action rule.
>>
>> Mimi Zohar <zohar@linux.vnet.ibm.com>
>>
>> ---
>> Changelog v3:
>> - include dont_failsafe rule when displaying policy
>> - fail attempt to add dont_failsafe rule when appending to the policy
>>
>>  Documentation/ABI/testing/ima_policy |  3 ++-
>>  security/integrity/ima/ima.h         |  1 +
>>  security/integrity/ima/ima_main.c    | 11 ++++++++++-
>>  security/integrity/ima/ima_policy.c  | 29 ++++++++++++++++++++++++++++-
>>  4 files changed, 41 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
>> index e76432b9954d..f271207743e5 100644
>> --- a/Documentation/ABI/testing/ima_policy
>> +++ b/Documentation/ABI/testing/ima_policy
>> @@ -17,7 +17,8 @@ Description:
>>
>>                 rule format: action [condition ...]
>>
>> -               action: measure | dont_measure | appraise | dont_appraise | audit
>> +               action: measure | dont_meaure | appraise | dont_appraise |
>> +                       audit | dont_failsafe
>>                 condition:= base | lsm  [option]
>>                         base:   [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
>>                                 [euid=] [fowner=]]
>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>> index d52b487ad259..c5f34f7c5b0f 100644
>> --- a/security/integrity/ima/ima.h
>> +++ b/security/integrity/ima/ima.h
>> @@ -224,6 +224,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
>>  void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
>>  void ima_policy_stop(struct seq_file *m, void *v);
>>  int ima_policy_show(struct seq_file *m, void *v);
>> +void set_failsafe(bool flag);
>>
>>  /* Appraise integrity measurements */
>>  #define IMA_APPRAISE_ENFORCE   0x01
>> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
>> index 3941371402ff..664edab0f758 100644
>> --- a/security/integrity/ima/ima_main.c
>> +++ b/security/integrity/ima/ima_main.c
>> @@ -38,6 +38,11 @@ int ima_appraise;
>>  int ima_hash_algo = HASH_ALGO_SHA1;
>>  static int hash_setup_done;
>>
>> +static bool ima_failsafe = 1;
>> +void set_failsafe(bool flag) {
>> +       ima_failsafe = flag;
>> +}
>> +
>>  static int __init hash_setup(char *str)
>>  {
>>         struct ima_template_desc *template_desc = ima_template_desc_current();
>> @@ -263,8 +268,12 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
>>                 __putname(pathbuf);
>>  out:
>>         inode_unlock(inode);
>> -       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
>> +       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) {
>> +               if (!ima_failsafe && rc == -EBADF)
>> +                       return 0;
>> +
>
> By default IMA is failsaif. ima_failsafe is true.
> Return 0 is needed in failsafe mode. right?
> But in this logic it will happen if ima_failsafe is false. meaning it
> is not failsafe.
> Is it a typo?
>
>
>>                 return -EACCES;
>> +       }
>>         return 0;
>>  }
>>
>> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
>> index 95209a5f8595..43b85a4fb8e8 100644
>> --- a/security/integrity/ima/ima_policy.c
>> +++ b/security/integrity/ima/ima_policy.c
>> @@ -40,12 +40,14 @@
>>  #define APPRAISE       0x0004  /* same as IMA_APPRAISE */
>>  #define DONT_APPRAISE  0x0008
>>  #define AUDIT          0x0040
>> +#define DONT_FAILSAFE  0x0400
>>
>>  #define INVALID_PCR(a) (((a) < 0) || \
>>         (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
>>
>>  int ima_policy_flag;
>>  static int temp_ima_appraise;
>> +static bool temp_failsafe = 1;
>>
>>  #define MAX_LSM_RULES 6
>>  enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
>> @@ -513,6 +515,9 @@ void ima_update_policy(void)
>>         if (ima_rules != policy) {
>>                 ima_policy_flag = 0;
>>                 ima_rules = policy;
>> +
>> +               /* Only update on initial policy replacement, not append */
>> +               set_failsafe(temp_failsafe);
>>         }
>>         ima_update_policy_flag();
>>  }
>> @@ -529,7 +534,7 @@ enum {
>>         Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
>>         Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
>>         Opt_appraise_type, Opt_permit_directio,
>> -       Opt_pcr
>> +       Opt_pcr, Opt_dont_failsafe
>>  };
>>
>>  static match_table_t policy_tokens = {
>> @@ -560,6 +565,7 @@ static match_table_t policy_tokens = {
>>         {Opt_appraise_type, "appraise_type=%s"},
>>         {Opt_permit_directio, "permit_directio"},
>>         {Opt_pcr, "pcr=%s"},
>> +       {Opt_dont_failsafe, "dont_failsafe"},
>>         {Opt_err, NULL}
>>  };
>>
>> @@ -630,6 +636,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>>                 if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
>>                         continue;
>>                 token = match_token(p, policy_tokens, args);
>> +               if (entry->action == DONT_FAILSAFE) {
>> +                       /* no args permitted, force invalid rule */
>> +                       token = Opt_dont_failsafe;
>> +               }
>> +
>>                 switch (token) {
>>                 case Opt_measure:
>>                         ima_log_string(ab, "action", "measure");
>> @@ -671,6 +682,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>>
>>                         entry->action = AUDIT;
>>                         break;
>> +               case Opt_dont_failsafe:
>> +                       ima_log_string(ab, "action", "dont_failsafe");
>> +
>> +                       if (entry->action != UNKNOWN)
>> +                               result = -EINVAL;
>> +
>> +                       /* Permit on initial policy replacement only */
>> +                       if (ima_rules != &ima_policy_rules)
>> +                               temp_failsafe = 0;
>> +                       else
>> +                               result = -EINVAL;
>> +                       entry->action = DONT_FAILSAFE;
>> +                       break;
>>                 case Opt_func:
>>                         ima_log_string(ab, "func", args[0].from);
>>
>> @@ -949,6 +973,7 @@ void ima_delete_rules(void)
>>         int i;
>>
>>         temp_ima_appraise = 0;
>> +       temp_failsafe = 1;
>>         list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
>>                 for (i = 0; i < MAX_LSM_RULES; i++)
>>                         kfree(entry->lsm[i].args_p);
>> @@ -1040,6 +1065,8 @@ int ima_policy_show(struct seq_file *m, void *v)
>>                 seq_puts(m, pt(Opt_dont_appraise));
>>         if (entry->action & AUDIT)
>>                 seq_puts(m, pt(Opt_audit));
>> +       if (entry->action & DONT_FAILSAFE)
>> +               seq_puts(m, pt(Opt_dont_failsafe));
>>
>>         seq_puts(m, " ");
>>
>> --
>> 2.7.4
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> Linux-ima-devel mailing list
>> Linux-ima-devel at lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/linux-ima-devel
>
>
>
> --
> Thanks,
> Dmitry



-- 
Thanks,
Dmitry
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 2/5] ima: use fs method to read integrity data
  2017-07-26 13:22   ` Mimi Zohar
@ 2017-08-22  9:59     ` Dmitry Kasatkin
  -1 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:59 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Christoph Hellwig, Al Viro, James Morris, linux-fsdevel,
	linux-ima-devel, linux-security-module, Matthew Garrett,
	Jan Kara, Theodore Ts'o, Andreas Dilger, Jaegeuk Kim,
	Chao Yu, Steven Whitehouse, Bob Peterson, David Woodhouse,
	Dave Kleikamp, Ryusuke Konishi, Mark Fasheh, Joel Becker,
	Richard Weinberger, Darrick J. Wong, Hugh Dickins, Chris Mason

Seems to look good from IMA side.

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 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 <matthew.garrett@nebula.com>
> 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 <yuchao0@huawei.com>
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: Bob Peterson <rpeterso@redhat.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dave Kleikamp <shaggy@kernel.org>
> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> Cc: Mark Fasheh <mfasheh@versity.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Chris Mason <clm@fb.com>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> Changelog v4:
> - define ext2/4 specific ->integrity_read functions.
> - properly fail file open with O_DIRECT on filesystem not mounted
> with "-o dax".
>
> ---
> Changelog v3:
> - define simple_read_iter_from_buffer
> - replace the existing efivarfs ->read method with ->read_iter method.
> - squashed other fs definitions of ->integrity_read with this patch.
>
> 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            | 17 +++++++++++++++++
>  fs/ext4/file.c            | 23 +++++++++++++++++++++++
>  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, 129 insertions(+), 11 deletions(-)
>
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index 9e75d8a39aac..2542dc66c85c 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> --- a/fs/ext2/file.c
> +++ b/fs/ext2/file.c
> @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>         return generic_file_read_iter(iocb, to);
>  }
>
> +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> +                                            struct iov_iter *to)
> +{
> +       struct inode *inode = file_inode(iocb->ki_filp);
> +
> +       lockdep_assert_held(&inode->i_rwsem);
> +#ifdef CONFIG_FS_DAX
> +       if (!iov_iter_count(to))
> +               return 0; /* skip atime */
> +
> +       if (IS_DAX(iocb->ki_filp->f_mapping->host))
> +               return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> +#endif
> +       return generic_file_read_iter(iocb, to);
> +}
> +
>  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  {
>  #ifdef CONFIG_FS_DAX
> @@ -216,6 +232,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 = ext2_file_integrity_read_iter,
>  };
>
>  const struct inode_operations ext2_file_inode_operations = {
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 58294c9a7e1d..cb423fff935f 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>         return generic_file_read_iter(iocb, to);
>  }
>
> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> +                                            struct iov_iter *to)
> +{
> +       struct inode *inode = file_inode(iocb->ki_filp);
> +       int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> +       lockdep_assert_held(&inode->i_rwsem);
> +       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> +               return -EIO;
> +
> +       if (!iov_iter_count(to))
> +               return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> +       if (IS_DAX(inode))
> +               return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> +       if (o_direct)
> +               return -EINVAL;
> +       return generic_file_read_iter(iocb, to);
> +}
> +
>  /*
>   * Called when an inode is released. Note that this is different
>   * from ext4_file_open: open gets called at every open, but release
> @@ -747,6 +769,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_integrity_read_iter,
>  };
>
>  const struct inode_operations ext4_file_inode_operations = {
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 2706130c261b..82ea81da0b2d 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -292,6 +292,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.
>   *
> @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1699,6 +1699,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 *);
>  } __randomize_layout;
>
>  struct inode_operations {
> @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3849,6 +3849,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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 2/5] ima: use fs method to read integrity data
@ 2017-08-22  9:59     ` Dmitry Kasatkin
  0 siblings, 0 replies; 48+ messages in thread
From: Dmitry Kasatkin @ 2017-08-22  9:59 UTC (permalink / raw)
  To: linux-security-module

Seems to look good from IMA side.

On Wed, Jul 26, 2017 at 4:22 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 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 <matthew.garrett@nebula.com>
> 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 <yuchao0@huawei.com>
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: Bob Peterson <rpeterso@redhat.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dave Kleikamp <shaggy@kernel.org>
> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
> Cc: Mark Fasheh <mfasheh@versity.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Chris Mason <clm@fb.com>
> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> Changelog v4:
> - define ext2/4 specific ->integrity_read functions.
> - properly fail file open with O_DIRECT on filesystem not mounted
> with "-o dax".
>
> ---
> Changelog v3:
> - define simple_read_iter_from_buffer
> - replace the existing efivarfs ->read method with ->read_iter method.
> - squashed other fs definitions of ->integrity_read with this patch.
>
> 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            | 17 +++++++++++++++++
>  fs/ext4/file.c            | 23 +++++++++++++++++++++++
>  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, 129 insertions(+), 11 deletions(-)
>
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index 9e75d8a39aac..2542dc66c85c 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3125,6 +3125,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 d34d32bdc944..111069de1973 100644
> --- a/fs/ext2/file.c
> +++ b/fs/ext2/file.c
> @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>         return generic_file_read_iter(iocb, to);
>  }
>
> +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> +                                            struct iov_iter *to)
> +{
> +       struct inode *inode = file_inode(iocb->ki_filp);
> +
> +       lockdep_assert_held(&inode->i_rwsem);
> +#ifdef CONFIG_FS_DAX
> +       if (!iov_iter_count(to))
> +               return 0; /* skip atime */
> +
> +       if (IS_DAX(iocb->ki_filp->f_mapping->host))
> +               return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> +#endif
> +       return generic_file_read_iter(iocb, to);
> +}
> +
>  static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  {
>  #ifdef CONFIG_FS_DAX
> @@ -216,6 +232,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 = ext2_file_integrity_read_iter,
>  };
>
>  const struct inode_operations ext2_file_inode_operations = {
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 58294c9a7e1d..cb423fff935f 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>         return generic_file_read_iter(iocb, to);
>  }
>
> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> +                                            struct iov_iter *to)
> +{
> +       struct inode *inode = file_inode(iocb->ki_filp);
> +       int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> +       lockdep_assert_held(&inode->i_rwsem);
> +       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> +               return -EIO;
> +
> +       if (!iov_iter_count(to))
> +               return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> +       if (IS_DAX(inode))
> +               return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> +       if (o_direct)
> +               return -EINVAL;
> +       return generic_file_read_iter(iocb, to);
> +}
> +
>  /*
>   * Called when an inode is released. Note that this is different
>   * from ext4_file_open: open gets called at every open, but release
> @@ -747,6 +769,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_integrity_read_iter,
>  };
>
>  const struct inode_operations ext4_file_inode_operations = {
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 2706130c261b..82ea81da0b2d 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -2514,4 +2514,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 3aabe553fc45..99333264a0a7 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 8cad0b19b404..5e52a315e18b 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -1747,4 +1747,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 c4893e226fd8..0a6704b563d6 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -292,6 +292,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.
>   *
> @@ -1175,6 +1195,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 6e1fd5d21248..8d0d10e1dd93 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1699,6 +1699,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 *);
>  } __randomize_layout;
>
>  struct inode_operations {
> @@ -3097,6 +3098,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 b0aa6075d164..805d99011ca4 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3849,6 +3849,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



-- 
Thanks,
Dmitry
--
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

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2017-08-22  9:59 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-26 13:22 [PATCH v4 0/5] define new fs integrity_read method Mimi Zohar
2017-07-26 13:22 ` Mimi Zohar
2017-07-26 13:22 ` [PATCH v4 1/5] ima: always measure and audit files in policy Mimi Zohar
2017-07-26 13:22   ` Mimi Zohar
2017-08-22  9:24   ` [Linux-ima-devel] " Dmitry Kasatkin
2017-08-22  9:24     ` Dmitry Kasatkin
2017-07-26 13:22 ` [PATCH v4 2/5] ima: use fs method to read integrity data Mimi Zohar
2017-07-26 13:22   ` Mimi Zohar
2017-07-31  7:01   ` Jan Kara
2017-07-31  7:01     ` Jan Kara
2017-07-31 19:08     ` Mimi Zohar
2017-07-31 19:08       ` Mimi Zohar
2017-08-01 10:42       ` Jan Kara
2017-08-01 10:42         ` Jan Kara
2017-08-01 15:38         ` Mimi Zohar
2017-08-01 15:38           ` Mimi Zohar
2017-08-01 20:24   ` [PATCH v4 2/5] ima: use fs method to read integrity data [updated] Mimi Zohar
2017-08-01 20:24     ` Mimi Zohar
2017-08-02  8:01     ` Jan Kara
2017-08-02  8:01       ` Jan Kara
2017-08-02 17:11       ` Mimi Zohar
2017-08-02 17:11         ` Mimi Zohar
2017-08-03 10:56         ` Jan Kara
2017-08-03 10:56           ` Jan Kara
2017-08-04 21:07           ` Mimi Zohar
2017-08-04 21:07             ` Mimi Zohar
2017-08-07 10:04             ` Jan Kara
2017-08-07 10:04               ` Jan Kara
2017-08-07 20:12               ` Mimi Zohar
2017-08-07 20:12                 ` Mimi Zohar
2017-08-08 11:17                 ` Jan Kara
2017-08-08 11:17                   ` Jan Kara
2017-08-22  9:59   ` [PATCH v4 2/5] ima: use fs method to read integrity data Dmitry Kasatkin
2017-08-22  9:59     ` Dmitry Kasatkin
2017-07-26 13:22 ` [PATCH v4 3/5] ima: define "dont_failsafe" policy action rule Mimi Zohar
2017-07-26 13:22   ` Mimi Zohar
2017-08-22  9:34   ` [Linux-ima-devel] " Dmitry Kasatkin
2017-08-22  9:34     ` Dmitry Kasatkin
2017-08-22  9:39     ` Dmitry Kasatkin
2017-08-22  9:39       ` Dmitry Kasatkin
2017-07-26 13:22 ` [PATCH v4 4/5] ima: define "fs_unsafe" builtin policy Mimi Zohar
2017-07-26 13:22   ` Mimi Zohar
2017-08-22  9:36   ` [Linux-ima-devel] " Dmitry Kasatkin
2017-08-22  9:36     ` Dmitry Kasatkin
2017-07-26 13:22 ` [PATCH v4 5/5] ima: remove permit_directio policy option Mimi Zohar
2017-07-26 13:22   ` Mimi Zohar
2017-08-22  9:27   ` [Linux-ima-devel] " Dmitry Kasatkin
2017-08-22  9:27     ` Dmitry Kasatkin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.