Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 904f9c14 authored by Mimi Zohar's avatar Mimi Zohar Committed by Greg Kroah-Hartman
Browse files

ima: detect changes to the backing overlay file



[ Upstream commit b836c4d29f2744200b2af41e14bf50758dddc818 ]

Commit 18b44bc5a672 ("ovl: Always reevaluate the file signature for
IMA") forced signature re-evaulation on every file access.

Instead of always re-evaluating the file's integrity, detect a change
to the backing file, by comparing the cached file metadata with the
backing file's metadata.  Verifying just the i_version has not changed
is insufficient.  In addition save and compare the i_ino and s_dev
as well.

Reviewed-by: default avatarAmir Goldstein <amir73il@gmail.com>
Tested-by: default avatarEric Snowberg <eric.snowberg@oracle.com>
Tested-by: default avatarRaul E Rangel <rrangel@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 410fb31d
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
{
	const char *audit_cause = "failed";
	struct inode *inode = file_inode(file);
	struct inode *real_inode = d_real_inode(file_dentry(file));
	const char *filename = file->f_path.dentry->d_name.name;
	int result = 0;
	int length;
@@ -243,6 +244,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
	iint->ima_hash = tmpbuf;
	memcpy(iint->ima_hash, &hash, length);
	iint->version = i_version;
	if (real_inode != inode) {
		iint->real_ino = real_inode->i_ino;
		iint->real_dev = real_inode->i_sb->s_dev;
	}

	/* Possibly temporary failure due to type of read (eg. O_DIRECT) */
	if (!result)
+15 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/ima.h>
#include <linux/iversion.h>
#include <linux/fs.h>
#include <linux/iversion.h>

#include "ima.h"

@@ -170,7 +171,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
			       u32 secid, char *buf, loff_t size, int mask,
			       enum ima_hooks func)
{
	struct inode *inode = file_inode(file);
	struct inode *backing_inode, *inode = file_inode(file);
	struct integrity_iint_cache *iint = NULL;
	struct ima_template_desc *template_desc;
	char *pathbuf = NULL;
@@ -242,6 +243,19 @@ static int process_measurement(struct file *file, const struct cred *cred,
		iint->measured_pcrs = 0;
	}

	/* Detect and re-evaluate changes made to the backing file. */
	backing_inode = d_real_inode(file_dentry(file));
	if (backing_inode != inode &&
	    (action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
		if (!IS_I_VERSION(backing_inode) ||
		    backing_inode->i_sb->s_dev != iint->real_dev ||
		    backing_inode->i_ino != iint->real_ino ||
		    !inode_eq_iversion(backing_inode, iint->version)) {
			iint->flags &= ~IMA_DONE_MASK;
			iint->measured_pcrs = 0;
		}
	}

	/* Determine if already appraised/measured based on bitmask
	 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
	 *  IMA_AUDIT, IMA_AUDITED)
+2 −0
Original line number Diff line number Diff line
@@ -122,6 +122,8 @@ struct integrity_iint_cache {
	unsigned long flags;
	unsigned long measured_pcrs;
	unsigned long atomic_flags;
	unsigned long real_ino;
	dev_t real_dev;
	enum integrity_status ima_file_status:4;
	enum integrity_status ima_mmap_status:4;
	enum integrity_status ima_bprm_status:4;