Skip to content

Commit b836c4d

Browse files
committed
ima: detect changes to the backing overlay file
Commit 18b44bc ("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: Amir Goldstein <[email protected]> Tested-by: Eric Snowberg <[email protected]> Tested-by: Raul E Rangel <[email protected]> Cc: [email protected] Signed-off-by: Mimi Zohar <[email protected]>
1 parent b465030 commit b836c4d

File tree

4 files changed

+23
-2
lines changed

4 files changed

+23
-2
lines changed

fs/overlayfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1489,7 +1489,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
14891489
ovl_trusted_xattr_handlers;
14901490
sb->s_fs_info = ofs;
14911491
sb->s_flags |= SB_POSIXACL;
1492-
sb->s_iflags |= SB_I_SKIP_SYNC | SB_I_IMA_UNVERIFIABLE_SIGNATURE;
1492+
sb->s_iflags |= SB_I_SKIP_SYNC;
14931493

14941494
err = -ENOMEM;
14951495
root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe);

security/integrity/ima/ima_api.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
243243
{
244244
const char *audit_cause = "failed";
245245
struct inode *inode = file_inode(file);
246+
struct inode *real_inode = d_real_inode(file_dentry(file));
246247
const char *filename = file->f_path.dentry->d_name.name;
247248
struct ima_max_digest_data hash;
248249
struct kstat stat;
@@ -302,6 +303,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
302303
iint->ima_hash = tmpbuf;
303304
memcpy(iint->ima_hash, &hash, length);
304305
iint->version = i_version;
306+
if (real_inode != inode) {
307+
iint->real_ino = real_inode->i_ino;
308+
iint->real_dev = real_inode->i_sb->s_dev;
309+
}
305310

306311
/* Possibly temporary failure due to type of read (eg. O_DIRECT) */
307312
if (!result)

security/integrity/ima/ima_main.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/xattr.h>
2626
#include <linux/ima.h>
2727
#include <linux/fs.h>
28+
#include <linux/iversion.h>
2829

2930
#include "ima.h"
3031

@@ -207,7 +208,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
207208
u32 secid, char *buf, loff_t size, int mask,
208209
enum ima_hooks func)
209210
{
210-
struct inode *inode = file_inode(file);
211+
struct inode *backing_inode, *inode = file_inode(file);
211212
struct integrity_iint_cache *iint = NULL;
212213
struct ima_template_desc *template_desc = NULL;
213214
char *pathbuf = NULL;
@@ -284,6 +285,19 @@ static int process_measurement(struct file *file, const struct cred *cred,
284285
iint->measured_pcrs = 0;
285286
}
286287

288+
/* Detect and re-evaluate changes made to the backing file. */
289+
backing_inode = d_real_inode(file_dentry(file));
290+
if (backing_inode != inode &&
291+
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
292+
if (!IS_I_VERSION(backing_inode) ||
293+
backing_inode->i_sb->s_dev != iint->real_dev ||
294+
backing_inode->i_ino != iint->real_ino ||
295+
!inode_eq_iversion(backing_inode, iint->version)) {
296+
iint->flags &= ~IMA_DONE_MASK;
297+
iint->measured_pcrs = 0;
298+
}
299+
}
300+
287301
/* Determine if already appraised/measured based on bitmask
288302
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
289303
* IMA_AUDIT, IMA_AUDITED)

security/integrity/integrity.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ struct integrity_iint_cache {
164164
unsigned long flags;
165165
unsigned long measured_pcrs;
166166
unsigned long atomic_flags;
167+
unsigned long real_ino;
168+
dev_t real_dev;
167169
enum integrity_status ima_file_status:4;
168170
enum integrity_status ima_mmap_status:4;
169171
enum integrity_status ima_bprm_status:4;

0 commit comments

Comments
 (0)