Skip to content

Commit

Permalink
ima: Move file-change detection variables into new structure
Browse files Browse the repository at this point in the history
Move all the variables used for file change detection into a structure
that can be used by IMA and EVM. Implement an inline function for storing
the identification of an inode and one for detecting changes to an inode
based on this new structure.

Co-developed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
  • Loading branch information
stefanberger authored and mimizohar committed Apr 9, 2024
1 parent faf9948 commit 309e2b7
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 13 deletions.
34 changes: 34 additions & 0 deletions include/linux/integrity.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define _LINUX_INTEGRITY_H

#include <linux/fs.h>
#include <linux/iversion.h>

enum integrity_status {
INTEGRITY_PASS = 0,
Expand All @@ -28,4 +29,37 @@ static inline void integrity_load_keys(void)
}
#endif /* CONFIG_INTEGRITY */

/* An inode's attributes for detection of changes */
struct integrity_inode_attributes {
u64 version; /* track inode changes */
unsigned long ino;
dev_t dev;
};

/*
* On stacked filesystems the i_version alone is not enough to detect file data
* or metadata change. Additional metadata is required.
*/
static inline void
integrity_inode_attrs_store(struct integrity_inode_attributes *attrs,
u64 i_version, const struct inode *inode)
{
attrs->version = i_version;
attrs->dev = inode->i_sb->s_dev;
attrs->ino = inode->i_ino;
}

/*
* On stacked filesystems detect whether the inode or its content has changed.
*/
static inline bool
integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
const struct inode *inode)
{
return (inode->i_sb->s_dev != attrs->dev ||
inode->i_ino != attrs->ino ||
!inode_eq_iversion(inode, attrs->version));
}


#endif /* _LINUX_INTEGRITY_H */
4 changes: 1 addition & 3 deletions security/integrity/ima/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,10 @@ struct ima_kexec_hdr {
/* IMA integrity metadata associated with an inode */
struct ima_iint_cache {
struct mutex mutex; /* protects: version, flags, digest */
u64 version; /* track inode changes */
struct integrity_inode_attributes real_inode;
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;
Expand Down
10 changes: 5 additions & 5 deletions security/integrity/ima/ima_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,11 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,

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;
}
if (real_inode == inode)
iint->real_inode.version = i_version;
else
integrity_inode_attrs_store(&iint->real_inode, i_version,
real_inode);

/* Possibly temporary failure due to type of read (eg. O_DIRECT) */
if (!result)
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_iint.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static void ima_iint_init_always(struct ima_iint_cache *iint,
struct inode *inode)
{
iint->ima_hash = NULL;
iint->version = 0;
iint->real_inode.version = 0;
iint->flags = 0UL;
iint->atomic_flags = 0UL;
iint->ima_file_status = INTEGRITY_UNKNOWN;
Expand Down
7 changes: 3 additions & 4 deletions security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
STATX_CHANGE_COOKIE,
AT_STATX_SYNC_AS_STAT) ||
!(stat.result_mask & STATX_CHANGE_COOKIE) ||
stat.change_cookie != iint->version) {
stat.change_cookie != iint->real_inode.version) {
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
iint->measured_pcrs = 0;
if (update)
Expand Down Expand Up @@ -292,9 +292,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (real_inode != inode &&
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
if (!IS_I_VERSION(real_inode) ||
real_inode->i_sb->s_dev != iint->real_dev ||
real_inode->i_ino != iint->real_ino ||
!inode_eq_iversion(real_inode, iint->version)) {
integrity_inode_attrs_changed(&iint->real_inode,
real_inode)) {
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
}
Expand Down

0 comments on commit 309e2b7

Please sign in to comment.