Skip to content

Commit a652aa5

Browse files
stefanbergermimizohar
authored andcommitted
evm: Store and detect metadata inode attributes changes
On stacked filesystem the metadata inode may be different than the one file data inode and therefore changes to it need to be detected independently. Therefore, store the i_version, device number, and inode number associated with the file metadata inode. Implement a function to detect changes to the inode and if a change is detected reset the evm_status. This function will be called by IMA when IMA detects that the metadata inode is different from the file's inode. 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>
1 parent 309e2b7 commit a652aa5

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

include/linux/evm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
2626
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
2727
int buffer_size, char type,
2828
bool canonical_fmt);
29+
extern bool evm_metadata_changed(struct inode *inode,
30+
struct inode *metadata_inode);
2931
#ifdef CONFIG_FS_POSIX_ACL
3032
extern int posix_xattr_acl(const char *xattrname);
3133
#else
@@ -76,5 +78,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
7678
return -EOPNOTSUPP;
7779
}
7880

81+
static inline bool evm_metadata_changed(struct inode *inode,
82+
struct inode *metadata_inode)
83+
{
84+
return false;
85+
}
86+
7987
#endif /* CONFIG_EVM */
8088
#endif /* LINUX_EVM_H */

security/integrity/evm/evm.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct xattr_list {
3939
struct evm_iint_cache {
4040
unsigned long flags;
4141
enum integrity_status evm_status:4;
42+
struct integrity_inode_attributes metadata_inode;
4243
};
4344

4445
extern struct lsm_blob_sizes evm_blob_sizes;
@@ -74,11 +75,12 @@ int evm_update_evmxattr(struct dentry *dentry,
7475
size_t req_xattr_value_len);
7576
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
7677
const char *req_xattr_value,
77-
size_t req_xattr_value_len, struct evm_digest *data);
78+
size_t req_xattr_value_len, struct evm_digest *data,
79+
struct evm_iint_cache *iint);
7880
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
7981
const char *req_xattr_value,
8082
size_t req_xattr_value_len, char type,
81-
struct evm_digest *data);
83+
struct evm_digest *data, struct evm_iint_cache *iint);
8284
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
8385
char *hmac_val);
8486
int evm_init_secfs(void);

security/integrity/evm/evm_crypto.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
221221
const char *req_xattr_name,
222222
const char *req_xattr_value,
223223
size_t req_xattr_value_len,
224-
uint8_t type, struct evm_digest *data)
224+
uint8_t type, struct evm_digest *data,
225+
struct evm_iint_cache *iint)
225226
{
226227
struct inode *inode = d_inode(d_real(dentry, D_REAL_METADATA));
227228
struct xattr_list *xattr;
@@ -231,6 +232,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
231232
int error;
232233
int size, user_space_size;
233234
bool ima_present = false;
235+
u64 i_version = 0;
234236

235237
if (!(inode->i_opflags & IOP_XATTR) ||
236238
inode->i_sb->s_user_ns != &init_user_ns)
@@ -294,6 +296,13 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
294296
}
295297
hmac_add_misc(desc, inode, type, data->digest);
296298

299+
if (inode != d_backing_inode(dentry) && iint) {
300+
if (IS_I_VERSION(inode))
301+
i_version = inode_query_iversion(inode);
302+
integrity_inode_attrs_store(&iint->metadata_inode, i_version,
303+
inode);
304+
}
305+
297306
/* Portable EVM signatures must include an IMA hash */
298307
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
299308
error = -EPERM;
@@ -305,18 +314,19 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
305314

306315
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
307316
const char *req_xattr_value, size_t req_xattr_value_len,
308-
struct evm_digest *data)
317+
struct evm_digest *data, struct evm_iint_cache *iint)
309318
{
310319
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
311-
req_xattr_value_len, EVM_XATTR_HMAC, data);
320+
req_xattr_value_len, EVM_XATTR_HMAC, data,
321+
iint);
312322
}
313323

314324
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
315325
const char *req_xattr_value, size_t req_xattr_value_len,
316-
char type, struct evm_digest *data)
326+
char type, struct evm_digest *data, struct evm_iint_cache *iint)
317327
{
318328
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
319-
req_xattr_value_len, type, data);
329+
req_xattr_value_len, type, data, iint);
320330
}
321331

322332
static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
@@ -357,6 +367,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
357367
const char *xattr_value, size_t xattr_value_len)
358368
{
359369
struct inode *inode = d_backing_inode(dentry);
370+
struct evm_iint_cache *iint = evm_iint_inode(inode);
360371
struct evm_digest data;
361372
int rc = 0;
362373

@@ -372,7 +383,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
372383

373384
data.hdr.algo = HASH_ALGO_SHA1;
374385
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
375-
xattr_value_len, &data);
386+
xattr_value_len, &data, iint);
376387
if (rc == 0) {
377388
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
378389
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry,

security/integrity/evm/evm_main.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
226226

227227
digest.hdr.algo = HASH_ALGO_SHA1;
228228
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
229-
xattr_value_len, &digest);
229+
xattr_value_len, &digest, iint);
230230
if (rc)
231231
break;
232232
rc = crypto_memneq(xattr_data->data, digest.digest,
@@ -247,7 +247,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
247247
hdr = (struct signature_v2_hdr *)xattr_data;
248248
digest.hdr.algo = hdr->hash_algo;
249249
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
250-
xattr_value_len, xattr_data->type, &digest);
250+
xattr_value_len, xattr_data->type, &digest,
251+
iint);
251252
if (rc)
252253
break;
253254
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
@@ -733,6 +734,31 @@ static void evm_reset_status(struct inode *inode)
733734
iint->evm_status = INTEGRITY_UNKNOWN;
734735
}
735736

737+
/**
738+
* evm_metadata_changed: Detect changes to the metadata
739+
* @inode: a file's inode
740+
* @metadata_inode: metadata inode
741+
*
742+
* On a stacked filesystem detect whether the metadata has changed. If this is
743+
* the case reset the evm_status associated with the inode that represents the
744+
* file.
745+
*/
746+
bool evm_metadata_changed(struct inode *inode, struct inode *metadata_inode)
747+
{
748+
struct evm_iint_cache *iint = evm_iint_inode(inode);
749+
bool ret = false;
750+
751+
if (iint) {
752+
ret = (!IS_I_VERSION(metadata_inode) ||
753+
integrity_inode_attrs_changed(&iint->metadata_inode,
754+
metadata_inode));
755+
if (ret)
756+
iint->evm_status = INTEGRITY_UNKNOWN;
757+
}
758+
759+
return ret;
760+
}
761+
736762
/**
737763
* evm_revalidate_status - report whether EVM status re-validation is necessary
738764
* @xattr_name: pointer to the affected extended attribute name

0 commit comments

Comments
 (0)