Commit b836c4d2 authored by Mimi Zohar's avatar Mimi Zohar

ima: detect changes to the backing overlay file

Commit 18b44bc5 ("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>
parent b4650306
...@@ -1489,7 +1489,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1489,7 +1489,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
ovl_trusted_xattr_handlers; ovl_trusted_xattr_handlers;
sb->s_fs_info = ofs; sb->s_fs_info = ofs;
sb->s_flags |= SB_POSIXACL; sb->s_flags |= SB_POSIXACL;
sb->s_iflags |= SB_I_SKIP_SYNC | SB_I_IMA_UNVERIFIABLE_SIGNATURE; sb->s_iflags |= SB_I_SKIP_SYNC;
err = -ENOMEM; err = -ENOMEM;
root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe); root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe);
......
...@@ -243,6 +243,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -243,6 +243,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
{ {
const char *audit_cause = "failed"; const char *audit_cause = "failed";
struct inode *inode = file_inode(file); 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; const char *filename = file->f_path.dentry->d_name.name;
struct ima_max_digest_data hash; struct ima_max_digest_data hash;
struct kstat stat; struct kstat stat;
...@@ -302,6 +303,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -302,6 +303,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
iint->ima_hash = tmpbuf; iint->ima_hash = tmpbuf;
memcpy(iint->ima_hash, &hash, length); memcpy(iint->ima_hash, &hash, length);
iint->version = i_version; 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) */ /* Possibly temporary failure due to type of read (eg. O_DIRECT) */
if (!result) if (!result)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/ima.h> #include <linux/ima.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/iversion.h>
#include "ima.h" #include "ima.h"
...@@ -207,7 +208,7 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -207,7 +208,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
u32 secid, char *buf, loff_t size, int mask, u32 secid, char *buf, loff_t size, int mask,
enum ima_hooks func) 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 integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc = NULL; struct ima_template_desc *template_desc = NULL;
char *pathbuf = NULL; char *pathbuf = NULL;
...@@ -284,6 +285,19 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -284,6 +285,19 @@ static int process_measurement(struct file *file, const struct cred *cred,
iint->measured_pcrs = 0; 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 /* Determine if already appraised/measured based on bitmask
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
* IMA_AUDIT, IMA_AUDITED) * IMA_AUDIT, IMA_AUDITED)
......
...@@ -164,6 +164,8 @@ struct integrity_iint_cache { ...@@ -164,6 +164,8 @@ struct integrity_iint_cache {
unsigned long flags; unsigned long flags;
unsigned long measured_pcrs; unsigned long measured_pcrs;
unsigned long atomic_flags; unsigned long atomic_flags;
unsigned long real_ino;
dev_t real_dev;
enum integrity_status ima_file_status:4; enum integrity_status ima_file_status:4;
enum integrity_status ima_mmap_status:4; enum integrity_status ima_mmap_status:4;
enum integrity_status ima_bprm_status:4; enum integrity_status ima_bprm_status:4;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment