mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +00:00
integrity-v6.10
-----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQQdXVVFGN5XqKr1Hj7LwZzRsCrn5QUCZkQD2xQcem9oYXJAbGlu dXguaWJtLmNvbQAKCRDLwZzRsCrn5b81APwINCoiLDB0L9KkyUhQjqvLLZCS85u9 Qo3/wdUGAb2tygD/RYKJgtGxvqO1Ap1IysytKHId0yo+vokdXG5stpMPJQE= =dIrw -----END PGP SIGNATURE----- Merge tag 'integrity-v6.10' of ssh://ra.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity Pull integrity updates from Mimi Zohar: "Two IMA changes, one EVM change, a use after free bug fix, and a code cleanup to address "-Wflex-array-member-not-at-end" warnings: - The existing IMA {ascii, binary}_runtime_measurements lists include a hard coded SHA1 hash. To address this limitation, define per TPM enabled hash algorithm {ascii, binary}_runtime_measurements lists - Close an IMA integrity init_module syscall measurement gap by defining a new critical-data record - Enable (partial) EVM support on stacked filesystems (overlayfs). Only EVM portable & immutable file signatures are copied up, since they do not contain filesystem specific metadata" * tag 'integrity-v6.10' of ssh://ra.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity: ima: add crypto agility support for template-hash algorithm evm: Rename is_unsupported_fs to is_unsupported_hmac_fs fs: Rename SB_I_EVM_UNSUPPORTED to SB_I_EVM_HMAC_UNSUPPORTED evm: Enforce signatures on unsupported filesystem for EVM_INIT_X509 ima: re-evaluate file integrity on file metadata change evm: Store and detect metadata inode attributes changes ima: Move file-change detection variables into new structure evm: Use the metadata inode to calculate metadata hash evm: Implement per signature type decision in security_inode_copy_up_xattr security: allow finer granularity in permitting copy-up of security xattrs ima: Rename backing_inode to real_inode integrity: Avoid -Wflex-array-member-not-at-end warnings ima: define an init_module critical data record ima: Fix use-after-free on a dentry's dname.name
This commit is contained in:
commit
353ad6c083
@ -114,7 +114,7 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
|
||||
if (ovl_is_private_xattr(sb, name))
|
||||
continue;
|
||||
|
||||
error = security_inode_copy_up_xattr(name);
|
||||
error = security_inode_copy_up_xattr(old, name);
|
||||
if (error < 0 && error != -EOPNOTSUPP)
|
||||
break;
|
||||
if (error == 1) {
|
||||
|
@ -1460,7 +1460,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
* lead to unexpected results.
|
||||
*/
|
||||
sb->s_iflags |= SB_I_NOUMASK;
|
||||
sb->s_iflags |= SB_I_EVM_UNSUPPORTED;
|
||||
sb->s_iflags |= SB_I_EVM_HMAC_UNSUPPORTED;
|
||||
|
||||
err = -ENOMEM;
|
||||
root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe);
|
||||
|
@ -26,6 +26,8 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
|
||||
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
||||
int buffer_size, char type,
|
||||
bool canonical_fmt);
|
||||
extern bool evm_metadata_changed(struct inode *inode,
|
||||
struct inode *metadata_inode);
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
extern int posix_xattr_acl(const char *xattrname);
|
||||
#else
|
||||
@ -76,5 +78,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline bool evm_metadata_changed(struct inode *inode,
|
||||
struct inode *metadata_inode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EVM */
|
||||
#endif /* LINUX_EVM_H */
|
||||
|
@ -1174,7 +1174,7 @@ extern int send_sigurg(struct fown_struct *fown);
|
||||
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
|
||||
#define SB_I_IMA_UNVERIFIABLE_SIGNATURE 0x00000020
|
||||
#define SB_I_UNTRUSTED_MOUNTER 0x00000040
|
||||
#define SB_I_EVM_UNSUPPORTED 0x00000080
|
||||
#define SB_I_EVM_HMAC_UNSUPPORTED 0x00000080
|
||||
|
||||
#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
|
||||
#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define _LINUX_INTEGRITY_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/iversion.h>
|
||||
|
||||
enum integrity_status {
|
||||
INTEGRITY_PASS = 0,
|
||||
@ -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 */
|
||||
|
@ -176,7 +176,8 @@ LSM_HOOK(int, 0, inode_listsecurity, struct inode *inode, char *buffer,
|
||||
size_t buffer_size)
|
||||
LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
|
||||
LSM_HOOK(int, 0, inode_copy_up, struct dentry *src, struct cred **new)
|
||||
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, const char *name)
|
||||
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, struct dentry *src,
|
||||
const char *name)
|
||||
LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
|
||||
struct kernfs_node *kn)
|
||||
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
|
||||
|
@ -398,7 +398,7 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void
|
||||
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
|
||||
void security_inode_getsecid(struct inode *inode, u32 *secid);
|
||||
int security_inode_copy_up(struct dentry *src, struct cred **new);
|
||||
int security_inode_copy_up_xattr(const char *name);
|
||||
int security_inode_copy_up_xattr(struct dentry *src, const char *name);
|
||||
int security_kernfs_init_security(struct kernfs_node *kn_dir,
|
||||
struct kernfs_node *kn);
|
||||
int security_file_permission(struct file *file, int mask);
|
||||
@ -1016,7 +1016,7 @@ static inline int security_kernfs_init_security(struct kernfs_node *kn_dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_inode_copy_up_xattr(const char *name)
|
||||
static inline int security_inode_copy_up_xattr(struct dentry *src, const char *name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ struct xattr_list {
|
||||
struct evm_iint_cache {
|
||||
unsigned long flags;
|
||||
enum integrity_status evm_status:4;
|
||||
struct integrity_inode_attributes metadata_inode;
|
||||
};
|
||||
|
||||
extern struct lsm_blob_sizes evm_blob_sizes;
|
||||
@ -61,7 +62,7 @@ extern int evm_hmac_attrs;
|
||||
extern struct list_head evm_config_xattrnames;
|
||||
|
||||
struct evm_digest {
|
||||
struct ima_digest_data hdr;
|
||||
struct ima_digest_data_hdr hdr;
|
||||
char digest[IMA_MAX_DIGEST_SIZE];
|
||||
} __packed;
|
||||
|
||||
@ -74,11 +75,12 @@ int evm_update_evmxattr(struct dentry *dentry,
|
||||
size_t req_xattr_value_len);
|
||||
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
|
||||
const char *req_xattr_value,
|
||||
size_t req_xattr_value_len, struct evm_digest *data);
|
||||
size_t req_xattr_value_len, struct evm_digest *data,
|
||||
struct evm_iint_cache *iint);
|
||||
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
|
||||
const char *req_xattr_value,
|
||||
size_t req_xattr_value_len, char type,
|
||||
struct evm_digest *data);
|
||||
struct evm_digest *data, struct evm_iint_cache *iint);
|
||||
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
|
||||
char *hmac_val);
|
||||
int evm_init_secfs(void);
|
||||
|
@ -221,9 +221,10 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
|
||||
const char *req_xattr_name,
|
||||
const char *req_xattr_value,
|
||||
size_t req_xattr_value_len,
|
||||
uint8_t type, struct evm_digest *data)
|
||||
uint8_t type, struct evm_digest *data,
|
||||
struct evm_iint_cache *iint)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct inode *inode = d_inode(d_real(dentry, D_REAL_METADATA));
|
||||
struct xattr_list *xattr;
|
||||
struct shash_desc *desc;
|
||||
size_t xattr_size = 0;
|
||||
@ -231,6 +232,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
|
||||
int error;
|
||||
int size, user_space_size;
|
||||
bool ima_present = false;
|
||||
u64 i_version = 0;
|
||||
|
||||
if (!(inode->i_opflags & IOP_XATTR) ||
|
||||
inode->i_sb->s_user_ns != &init_user_ns)
|
||||
@ -294,6 +296,13 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
|
||||
}
|
||||
hmac_add_misc(desc, inode, type, data->digest);
|
||||
|
||||
if (inode != d_backing_inode(dentry) && iint) {
|
||||
if (IS_I_VERSION(inode))
|
||||
i_version = inode_query_iversion(inode);
|
||||
integrity_inode_attrs_store(&iint->metadata_inode, i_version,
|
||||
inode);
|
||||
}
|
||||
|
||||
/* Portable EVM signatures must include an IMA hash */
|
||||
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
|
||||
error = -EPERM;
|
||||
@ -305,18 +314,19 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
|
||||
|
||||
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
|
||||
const char *req_xattr_value, size_t req_xattr_value_len,
|
||||
struct evm_digest *data)
|
||||
struct evm_digest *data, struct evm_iint_cache *iint)
|
||||
{
|
||||
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
|
||||
req_xattr_value_len, EVM_XATTR_HMAC, data);
|
||||
req_xattr_value_len, EVM_XATTR_HMAC, data,
|
||||
iint);
|
||||
}
|
||||
|
||||
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
|
||||
const char *req_xattr_value, size_t req_xattr_value_len,
|
||||
char type, struct evm_digest *data)
|
||||
char type, struct evm_digest *data, struct evm_iint_cache *iint)
|
||||
{
|
||||
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
|
||||
req_xattr_value_len, type, data);
|
||||
req_xattr_value_len, type, data, iint);
|
||||
}
|
||||
|
||||
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,
|
||||
const char *xattr_value, size_t xattr_value_len)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||
struct evm_digest data;
|
||||
int rc = 0;
|
||||
|
||||
@ -372,7 +383,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
|
||||
|
||||
data.hdr.algo = HASH_ALGO_SHA1;
|
||||
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len, &data);
|
||||
xattr_value_len, &data, iint);
|
||||
if (rc == 0) {
|
||||
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
|
||||
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry,
|
||||
|
@ -151,11 +151,11 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
|
||||
return count;
|
||||
}
|
||||
|
||||
static int is_unsupported_fs(struct dentry *dentry)
|
||||
static int is_unsupported_hmac_fs(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
|
||||
if (inode->i_sb->s_iflags & SB_I_EVM_UNSUPPORTED) {
|
||||
if (inode->i_sb->s_iflags & SB_I_EVM_HMAC_UNSUPPORTED) {
|
||||
pr_info_once("%s not supported\n", inode->i_sb->s_type->name);
|
||||
return 1;
|
||||
}
|
||||
@ -192,7 +192,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
|
||||
return iint->evm_status;
|
||||
|
||||
if (is_unsupported_fs(dentry))
|
||||
/*
|
||||
* On unsupported filesystems without EVM_INIT_X509 enabled, skip
|
||||
* signature verification.
|
||||
*/
|
||||
if (!(evm_initialized & EVM_INIT_X509) &&
|
||||
is_unsupported_hmac_fs(dentry))
|
||||
return INTEGRITY_UNKNOWN;
|
||||
|
||||
/* if status is not PASS, try to check again - against -ENOMEM */
|
||||
@ -226,7 +231,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
|
||||
digest.hdr.algo = HASH_ALGO_SHA1;
|
||||
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len, &digest);
|
||||
xattr_value_len, &digest, iint);
|
||||
if (rc)
|
||||
break;
|
||||
rc = crypto_memneq(xattr_data->data, digest.digest,
|
||||
@ -247,7 +252,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
hdr = (struct signature_v2_hdr *)xattr_data;
|
||||
digest.hdr.algo = hdr->hash_algo;
|
||||
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len, xattr_data->type, &digest);
|
||||
xattr_value_len, xattr_data->type, &digest,
|
||||
iint);
|
||||
if (rc)
|
||||
break;
|
||||
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
|
||||
@ -260,7 +266,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
evm_status = INTEGRITY_PASS_IMMUTABLE;
|
||||
} else if (!IS_RDONLY(inode) &&
|
||||
!(inode->i_sb->s_readonly_remount) &&
|
||||
!IS_IMMUTABLE(inode)) {
|
||||
!IS_IMMUTABLE(inode) &&
|
||||
!is_unsupported_hmac_fs(dentry)) {
|
||||
evm_update_evmxattr(dentry, xattr_name,
|
||||
xattr_value,
|
||||
xattr_value_len);
|
||||
@ -418,9 +425,6 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
||||
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
|
||||
return INTEGRITY_UNKNOWN;
|
||||
|
||||
if (is_unsupported_fs(dentry))
|
||||
return INTEGRITY_UNKNOWN;
|
||||
|
||||
return evm_verify_hmac(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len);
|
||||
}
|
||||
@ -499,12 +503,12 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
|
||||
if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (is_unsupported_fs(dentry))
|
||||
if (is_unsupported_hmac_fs(dentry))
|
||||
return -EPERM;
|
||||
} else if (!evm_protected_xattr(xattr_name)) {
|
||||
if (!posix_xattr_acl(xattr_name))
|
||||
return 0;
|
||||
if (is_unsupported_fs(dentry))
|
||||
if (is_unsupported_hmac_fs(dentry))
|
||||
return 0;
|
||||
|
||||
evm_status = evm_verify_current_integrity(dentry);
|
||||
@ -512,7 +516,7 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
|
||||
(evm_status == INTEGRITY_NOXATTRS))
|
||||
return 0;
|
||||
goto out;
|
||||
} else if (is_unsupported_fs(dentry))
|
||||
} else if (is_unsupported_hmac_fs(dentry))
|
||||
return 0;
|
||||
|
||||
evm_status = evm_verify_current_integrity(dentry);
|
||||
@ -733,6 +737,31 @@ static void evm_reset_status(struct inode *inode)
|
||||
iint->evm_status = INTEGRITY_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_metadata_changed: Detect changes to the metadata
|
||||
* @inode: a file's inode
|
||||
* @metadata_inode: metadata inode
|
||||
*
|
||||
* On a stacked filesystem detect whether the metadata has changed. If this is
|
||||
* the case reset the evm_status associated with the inode that represents the
|
||||
* file.
|
||||
*/
|
||||
bool evm_metadata_changed(struct inode *inode, struct inode *metadata_inode)
|
||||
{
|
||||
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||
bool ret = false;
|
||||
|
||||
if (iint) {
|
||||
ret = (!IS_I_VERSION(metadata_inode) ||
|
||||
integrity_inode_attrs_changed(&iint->metadata_inode,
|
||||
metadata_inode));
|
||||
if (ret)
|
||||
iint->evm_status = INTEGRITY_UNKNOWN;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_revalidate_status - report whether EVM status re-validation is necessary
|
||||
* @xattr_name: pointer to the affected extended attribute name
|
||||
@ -789,7 +818,7 @@ static void evm_inode_post_setxattr(struct dentry *dentry,
|
||||
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||
return;
|
||||
|
||||
if (is_unsupported_fs(dentry))
|
||||
if (is_unsupported_hmac_fs(dentry))
|
||||
return;
|
||||
|
||||
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
|
||||
@ -888,7 +917,7 @@ static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
|
||||
return 0;
|
||||
|
||||
if (is_unsupported_fs(dentry))
|
||||
if (is_unsupported_hmac_fs(dentry))
|
||||
return 0;
|
||||
|
||||
if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
|
||||
@ -939,18 +968,43 @@ static void evm_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||
return;
|
||||
|
||||
if (is_unsupported_fs(dentry))
|
||||
if (is_unsupported_hmac_fs(dentry))
|
||||
return;
|
||||
|
||||
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
|
||||
evm_update_evmxattr(dentry, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static int evm_inode_copy_up_xattr(const char *name)
|
||||
static int evm_inode_copy_up_xattr(struct dentry *src, const char *name)
|
||||
{
|
||||
if (strcmp(name, XATTR_NAME_EVM) == 0)
|
||||
return 1; /* Discard */
|
||||
return -EOPNOTSUPP;
|
||||
struct evm_ima_xattr_data *xattr_data = NULL;
|
||||
int rc;
|
||||
|
||||
if (strcmp(name, XATTR_NAME_EVM) != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* first need to know the sig type */
|
||||
rc = vfs_getxattr_alloc(&nop_mnt_idmap, src, XATTR_NAME_EVM,
|
||||
(char **)&xattr_data, 0, GFP_NOFS);
|
||||
if (rc <= 0)
|
||||
return -EPERM;
|
||||
|
||||
if (rc < offsetof(struct evm_ima_xattr_data, type) +
|
||||
sizeof(xattr_data->type))
|
||||
return -EPERM;
|
||||
|
||||
switch (xattr_data->type) {
|
||||
case EVM_XATTR_PORTABLE_DIGSIG:
|
||||
rc = 0; /* allow copy-up */
|
||||
break;
|
||||
case EVM_XATTR_HMAC:
|
||||
case EVM_IMA_XATTR_DIGSIG:
|
||||
default:
|
||||
rc = 1; /* discard */
|
||||
}
|
||||
|
||||
kfree(xattr_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -49,11 +49,19 @@ extern int ima_policy_flag;
|
||||
/* bitset of digests algorithms allowed in the setxattr hook */
|
||||
extern atomic_t ima_setxattr_allowed_hash_algorithms;
|
||||
|
||||
/* IMA hash algorithm description */
|
||||
struct ima_algo_desc {
|
||||
struct crypto_shash *tfm;
|
||||
enum hash_algo algo;
|
||||
};
|
||||
|
||||
/* set during initialization */
|
||||
extern int ima_hash_algo __ro_after_init;
|
||||
extern int ima_sha1_idx __ro_after_init;
|
||||
extern int ima_hash_algo_idx __ro_after_init;
|
||||
extern int ima_extra_slots __ro_after_init;
|
||||
extern struct ima_algo_desc *ima_algo_array __ro_after_init;
|
||||
|
||||
extern int ima_appraise;
|
||||
extern struct tpm_chip *ima_tpm_chip;
|
||||
extern const char boot_aggregate_name[];
|
||||
@ -175,12 +183,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;
|
||||
|
@ -245,8 +245,10 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
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;
|
||||
struct ima_max_digest_data hash;
|
||||
struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
|
||||
struct ima_digest_data, hdr);
|
||||
struct name_snapshot filename;
|
||||
struct kstat stat;
|
||||
int result = 0;
|
||||
int length;
|
||||
@ -286,9 +288,9 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
result = -ENODATA;
|
||||
}
|
||||
} else if (buf) {
|
||||
result = ima_calc_buffer_hash(buf, size, &hash.hdr);
|
||||
result = ima_calc_buffer_hash(buf, size, hash_hdr);
|
||||
} else {
|
||||
result = ima_calc_file_hash(file, &hash.hdr);
|
||||
result = ima_calc_file_hash(file, hash_hdr);
|
||||
}
|
||||
|
||||
if (result && result != -EBADF && result != -EINVAL)
|
||||
@ -303,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)
|
||||
@ -317,9 +319,13 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
if (file->f_flags & O_DIRECT)
|
||||
audit_cause = "failed(directio)";
|
||||
|
||||
take_dentry_name_snapshot(&filename, file->f_path.dentry);
|
||||
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
||||
filename, "collect_data", audit_cause,
|
||||
result, 0);
|
||||
filename.name.name, "collect_data",
|
||||
audit_cause, result, 0);
|
||||
|
||||
release_dentry_name_snapshot(&filename);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -432,6 +438,7 @@ void ima_audit_measurement(struct ima_iint_cache *iint,
|
||||
*/
|
||||
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
|
||||
{
|
||||
struct name_snapshot filename;
|
||||
char *pathname = NULL;
|
||||
|
||||
*pathbuf = __getname();
|
||||
@ -445,7 +452,10 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
|
||||
}
|
||||
|
||||
if (!pathname) {
|
||||
strscpy(namebuf, path->dentry->d_name.name, NAME_MAX);
|
||||
take_dentry_name_snapshot(&filename, path->dentry);
|
||||
strscpy(namebuf, filename.name.name, NAME_MAX);
|
||||
release_dentry_name_snapshot(&filename);
|
||||
|
||||
pathname = namebuf;
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,9 @@ static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
}
|
||||
|
||||
rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo,
|
||||
iint->ima_hash->digest, &hash.hdr);
|
||||
iint->ima_hash->digest,
|
||||
container_of(&hash.hdr,
|
||||
struct ima_digest_data, hdr));
|
||||
if (rc) {
|
||||
*cause = "sigv3-hashing-error";
|
||||
*status = INTEGRITY_FAIL;
|
||||
|
@ -57,11 +57,6 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
|
||||
static struct crypto_shash *ima_shash_tfm;
|
||||
static struct crypto_ahash *ima_ahash_tfm;
|
||||
|
||||
struct ima_algo_desc {
|
||||
struct crypto_shash *tfm;
|
||||
enum hash_algo algo;
|
||||
};
|
||||
|
||||
int ima_sha1_idx __ro_after_init;
|
||||
int ima_hash_algo_idx __ro_after_init;
|
||||
/*
|
||||
@ -70,7 +65,7 @@ int ima_hash_algo_idx __ro_after_init;
|
||||
*/
|
||||
int ima_extra_slots __ro_after_init;
|
||||
|
||||
static struct ima_algo_desc *ima_algo_array;
|
||||
struct ima_algo_desc *ima_algo_array __ro_after_init;
|
||||
|
||||
static int __init ima_init_ima_crypto(void)
|
||||
{
|
||||
|
@ -116,9 +116,31 @@ void ima_putc(struct seq_file *m, void *data, int datalen)
|
||||
seq_putc(m, *(char *)data++);
|
||||
}
|
||||
|
||||
static struct dentry **ascii_securityfs_measurement_lists __ro_after_init;
|
||||
static struct dentry **binary_securityfs_measurement_lists __ro_after_init;
|
||||
static int securityfs_measurement_list_count __ro_after_init;
|
||||
|
||||
static void lookup_template_data_hash_algo(int *algo_idx, enum hash_algo *algo,
|
||||
struct seq_file *m,
|
||||
struct dentry **lists)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
int i;
|
||||
|
||||
dentry = file_dentry(m->file);
|
||||
|
||||
for (i = 0; i < securityfs_measurement_list_count; i++) {
|
||||
if (dentry == lists[i]) {
|
||||
*algo_idx = i;
|
||||
*algo = ima_algo_array[i].algo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* print format:
|
||||
* 32bit-le=pcr#
|
||||
* char[20]=template digest
|
||||
* char[n]=template digest
|
||||
* 32bit-le=template name size
|
||||
* char[n]=template name
|
||||
* [eventdata length]
|
||||
@ -132,7 +154,15 @@ int ima_measurements_show(struct seq_file *m, void *v)
|
||||
char *template_name;
|
||||
u32 pcr, namelen, template_data_len; /* temporary fields */
|
||||
bool is_ima_template = false;
|
||||
int i;
|
||||
enum hash_algo algo;
|
||||
int i, algo_idx;
|
||||
|
||||
algo_idx = ima_sha1_idx;
|
||||
algo = HASH_ALGO_SHA1;
|
||||
|
||||
if (m->file != NULL)
|
||||
lookup_template_data_hash_algo(&algo_idx, &algo, m,
|
||||
binary_securityfs_measurement_lists);
|
||||
|
||||
/* get entry */
|
||||
e = qe->entry;
|
||||
@ -151,7 +181,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
|
||||
ima_putc(m, &pcr, sizeof(e->pcr));
|
||||
|
||||
/* 2nd: template digest */
|
||||
ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
|
||||
ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
|
||||
|
||||
/* 3rd: template name size */
|
||||
namelen = !ima_canonical_fmt ? strlen(template_name) :
|
||||
@ -220,7 +250,15 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
|
||||
struct ima_queue_entry *qe = v;
|
||||
struct ima_template_entry *e;
|
||||
char *template_name;
|
||||
int i;
|
||||
enum hash_algo algo;
|
||||
int i, algo_idx;
|
||||
|
||||
algo_idx = ima_sha1_idx;
|
||||
algo = HASH_ALGO_SHA1;
|
||||
|
||||
if (m->file != NULL)
|
||||
lookup_template_data_hash_algo(&algo_idx, &algo, m,
|
||||
ascii_securityfs_measurement_lists);
|
||||
|
||||
/* get entry */
|
||||
e = qe->entry;
|
||||
@ -233,8 +271,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
|
||||
/* 1st: PCR used (config option) */
|
||||
seq_printf(m, "%2d ", e->pcr);
|
||||
|
||||
/* 2nd: SHA1 template hash */
|
||||
ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
|
||||
/* 2nd: template hash */
|
||||
ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
|
||||
|
||||
/* 3th: template name */
|
||||
seq_printf(m, " %s", template_name);
|
||||
@ -379,6 +417,71 @@ static const struct seq_operations ima_policy_seqops = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static void __init remove_securityfs_measurement_lists(struct dentry **lists)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (lists) {
|
||||
for (i = 0; i < securityfs_measurement_list_count; i++)
|
||||
securityfs_remove(lists[i]);
|
||||
|
||||
kfree(lists);
|
||||
}
|
||||
|
||||
securityfs_measurement_list_count = 0;
|
||||
}
|
||||
|
||||
static int __init create_securityfs_measurement_lists(void)
|
||||
{
|
||||
char file_name[NAME_MAX + 1];
|
||||
struct dentry *dentry;
|
||||
u16 algo;
|
||||
int i;
|
||||
|
||||
securityfs_measurement_list_count = NR_BANKS(ima_tpm_chip);
|
||||
|
||||
if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
|
||||
securityfs_measurement_list_count++;
|
||||
|
||||
ascii_securityfs_measurement_lists =
|
||||
kcalloc(securityfs_measurement_list_count, sizeof(struct dentry *),
|
||||
GFP_KERNEL);
|
||||
if (!ascii_securityfs_measurement_lists)
|
||||
return -ENOMEM;
|
||||
|
||||
binary_securityfs_measurement_lists =
|
||||
kcalloc(securityfs_measurement_list_count, sizeof(struct dentry *),
|
||||
GFP_KERNEL);
|
||||
if (!binary_securityfs_measurement_lists)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < securityfs_measurement_list_count; i++) {
|
||||
algo = ima_algo_array[i].algo;
|
||||
|
||||
sprintf(file_name, "ascii_runtime_measurements_%s",
|
||||
hash_algo_name[algo]);
|
||||
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
|
||||
ima_dir, NULL,
|
||||
&ima_ascii_measurements_ops);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
ascii_securityfs_measurement_lists[i] = dentry;
|
||||
|
||||
sprintf(file_name, "binary_runtime_measurements_%s",
|
||||
hash_algo_name[algo]);
|
||||
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
|
||||
ima_dir, NULL,
|
||||
&ima_measurements_ops);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
binary_securityfs_measurement_lists[i] = dentry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_open_policy: sequentialize access to the policy file
|
||||
*/
|
||||
@ -454,6 +557,9 @@ int __init ima_fs_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ascii_securityfs_measurement_lists = NULL;
|
||||
binary_securityfs_measurement_lists = NULL;
|
||||
|
||||
ima_dir = securityfs_create_dir("ima", integrity_dir);
|
||||
if (IS_ERR(ima_dir))
|
||||
return PTR_ERR(ima_dir);
|
||||
@ -465,19 +571,21 @@ int __init ima_fs_init(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = create_securityfs_measurement_lists();
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
binary_runtime_measurements =
|
||||
securityfs_create_file("binary_runtime_measurements",
|
||||
S_IRUSR | S_IRGRP, ima_dir, NULL,
|
||||
&ima_measurements_ops);
|
||||
securityfs_create_symlink("binary_runtime_measurements", ima_dir,
|
||||
"binary_runtime_measurements_sha1", NULL);
|
||||
if (IS_ERR(binary_runtime_measurements)) {
|
||||
ret = PTR_ERR(binary_runtime_measurements);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ascii_runtime_measurements =
|
||||
securityfs_create_file("ascii_runtime_measurements",
|
||||
S_IRUSR | S_IRGRP, ima_dir, NULL,
|
||||
&ima_ascii_measurements_ops);
|
||||
securityfs_create_symlink("ascii_runtime_measurements", ima_dir,
|
||||
"ascii_runtime_measurements_sha1", NULL);
|
||||
if (IS_ERR(ascii_runtime_measurements)) {
|
||||
ret = PTR_ERR(ascii_runtime_measurements);
|
||||
goto out;
|
||||
@ -515,6 +623,8 @@ int __init ima_fs_init(void)
|
||||
securityfs_remove(runtime_measurements_count);
|
||||
securityfs_remove(ascii_runtime_measurements);
|
||||
securityfs_remove(binary_runtime_measurements);
|
||||
remove_securityfs_measurement_lists(ascii_securityfs_measurement_lists);
|
||||
remove_securityfs_measurement_lists(binary_securityfs_measurement_lists);
|
||||
securityfs_remove(ima_symlink);
|
||||
securityfs_remove(ima_dir);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -48,12 +48,14 @@ static int __init ima_add_boot_aggregate(void)
|
||||
struct ima_event_data event_data = { .iint = iint,
|
||||
.filename = boot_aggregate_name };
|
||||
struct ima_max_digest_data hash;
|
||||
struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
|
||||
struct ima_digest_data, hdr);
|
||||
int result = -ENOMEM;
|
||||
int violation = 0;
|
||||
|
||||
memset(iint, 0, sizeof(*iint));
|
||||
memset(&hash, 0, sizeof(hash));
|
||||
iint->ima_hash = &hash.hdr;
|
||||
iint->ima_hash = hash_hdr;
|
||||
iint->ima_hash->algo = ima_hash_algo;
|
||||
iint->ima_hash->length = hash_digest_size[ima_hash_algo];
|
||||
|
||||
@ -70,7 +72,7 @@ static int __init ima_add_boot_aggregate(void)
|
||||
* is not found.
|
||||
*/
|
||||
if (ima_tpm_chip) {
|
||||
result = ima_calc_boot_aggregate(&hash.hdr);
|
||||
result = ima_calc_boot_aggregate(hash_hdr);
|
||||
if (result < 0) {
|
||||
audit_cause = "hashing_error";
|
||||
goto err_out;
|
||||
|
@ -30,6 +30,7 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
|
||||
goto out;
|
||||
}
|
||||
|
||||
file.file = NULL;
|
||||
file.size = segment_size;
|
||||
file.read_pos = 0;
|
||||
file.count = sizeof(khdr); /* reserved space */
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/ima.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/evm.h>
|
||||
|
||||
#include "ima.h"
|
||||
|
||||
@ -173,7 +174,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)
|
||||
@ -208,9 +209,10 @@ 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 *backing_inode, *inode = file_inode(file);
|
||||
struct inode *real_inode, *inode = file_inode(file);
|
||||
struct ima_iint_cache *iint = NULL;
|
||||
struct ima_template_desc *template_desc = NULL;
|
||||
struct inode *metadata_inode;
|
||||
char *pathbuf = NULL;
|
||||
char filename[NAME_MAX];
|
||||
const char *pathname = NULL;
|
||||
@ -285,17 +287,28 @@ 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 &&
|
||||
/*
|
||||
* On stacked filesystems, detect and re-evaluate file data and
|
||||
* metadata changes.
|
||||
*/
|
||||
real_inode = d_real_inode(file_dentry(file));
|
||||
if (real_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)) {
|
||||
if (!IS_I_VERSION(real_inode) ||
|
||||
integrity_inode_attrs_changed(&iint->real_inode,
|
||||
real_inode)) {
|
||||
iint->flags &= ~IMA_DONE_MASK;
|
||||
iint->measured_pcrs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the EVM status when metadata changed.
|
||||
*/
|
||||
metadata_inode = d_inode(d_real(file_dentry(file),
|
||||
D_REAL_METADATA));
|
||||
if (evm_metadata_changed(inode, metadata_inode))
|
||||
iint->flags &= ~(IMA_APPRAISED |
|
||||
IMA_APPRAISED_SUBMASK);
|
||||
}
|
||||
|
||||
/* Determine if already appraised/measured based on bitmask
|
||||
@ -902,6 +915,13 @@ static int ima_post_load_data(char *buf, loff_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure the init_module syscall buffer containing the ELF image.
|
||||
*/
|
||||
if (load_id == LOADING_MODULE)
|
||||
ima_measure_critical_data("modules", "init_module",
|
||||
buf, size, true, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -941,6 +961,8 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
.buf_len = size};
|
||||
struct ima_template_desc *template;
|
||||
struct ima_max_digest_data hash;
|
||||
struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
|
||||
struct ima_digest_data, hdr);
|
||||
char digest_hash[IMA_MAX_DIGEST_SIZE];
|
||||
int digest_hash_len = hash_digest_size[ima_hash_algo];
|
||||
int violation = 0;
|
||||
@ -979,7 +1001,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
if (!pcr)
|
||||
pcr = CONFIG_IMA_MEASURE_PCR_IDX;
|
||||
|
||||
iint.ima_hash = &hash.hdr;
|
||||
iint.ima_hash = hash_hdr;
|
||||
iint.ima_hash->algo = ima_hash_algo;
|
||||
iint.ima_hash->length = hash_digest_size[ima_hash_algo];
|
||||
|
||||
@ -990,7 +1012,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
}
|
||||
|
||||
if (buf_hash) {
|
||||
memcpy(digest_hash, hash.hdr.digest, digest_hash_len);
|
||||
memcpy(digest_hash, hash_hdr->digest, digest_hash_len);
|
||||
|
||||
ret = ima_calc_buffer_hash(digest_hash, digest_hash_len,
|
||||
iint.ima_hash);
|
||||
|
@ -339,6 +339,8 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
struct ima_max_digest_data hash;
|
||||
struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
|
||||
struct ima_digest_data, hdr);
|
||||
u8 *cur_digest = NULL;
|
||||
u32 cur_digestsize = 0;
|
||||
struct inode *inode;
|
||||
@ -358,7 +360,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
|
||||
if ((const char *)event_data->filename == boot_aggregate_name) {
|
||||
if (ima_tpm_chip) {
|
||||
hash.hdr.algo = HASH_ALGO_SHA1;
|
||||
result = ima_calc_boot_aggregate(&hash.hdr);
|
||||
result = ima_calc_boot_aggregate(hash_hdr);
|
||||
|
||||
/* algo can change depending on available PCR banks */
|
||||
if (!result && hash.hdr.algo != HASH_ALGO_SHA1)
|
||||
@ -368,7 +370,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
|
||||
memset(&hash, 0, sizeof(hash));
|
||||
}
|
||||
|
||||
cur_digest = hash.hdr.digest;
|
||||
cur_digest = hash_hdr->digest;
|
||||
cur_digestsize = hash_digest_size[HASH_ALGO_SHA1];
|
||||
goto out;
|
||||
}
|
||||
@ -379,14 +381,14 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
|
||||
inode = file_inode(event_data->file);
|
||||
hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
|
||||
ima_hash_algo : HASH_ALGO_SHA1;
|
||||
result = ima_calc_file_hash(event_data->file, &hash.hdr);
|
||||
result = ima_calc_file_hash(event_data->file, hash_hdr);
|
||||
if (result) {
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
||||
event_data->filename, "collect_data",
|
||||
"failed", result, 0);
|
||||
return result;
|
||||
}
|
||||
cur_digest = hash.hdr.digest;
|
||||
cur_digest = hash_hdr->digest;
|
||||
cur_digestsize = hash.hdr.length;
|
||||
out:
|
||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||
@ -483,7 +485,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
|
||||
bool size_limit)
|
||||
{
|
||||
const char *cur_filename = NULL;
|
||||
struct name_snapshot filename;
|
||||
u32 cur_filename_len = 0;
|
||||
bool snapshot = false;
|
||||
int ret;
|
||||
|
||||
BUG_ON(event_data->filename == NULL && event_data->file == NULL);
|
||||
|
||||
@ -496,7 +501,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
|
||||
}
|
||||
|
||||
if (event_data->file) {
|
||||
cur_filename = event_data->file->f_path.dentry->d_name.name;
|
||||
take_dentry_name_snapshot(&filename,
|
||||
event_data->file->f_path.dentry);
|
||||
snapshot = true;
|
||||
cur_filename = filename.name.name;
|
||||
cur_filename_len = strlen(cur_filename);
|
||||
} else
|
||||
/*
|
||||
@ -505,8 +513,13 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
|
||||
*/
|
||||
cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
|
||||
out:
|
||||
return ima_write_template_field_data(cur_filename, cur_filename_len,
|
||||
DATA_FMT_STRING, field_data);
|
||||
ret = ima_write_template_field_data(cur_filename, cur_filename_len,
|
||||
DATA_FMT_STRING, field_data);
|
||||
|
||||
if (snapshot)
|
||||
release_dentry_name_snapshot(&filename);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -31,19 +31,24 @@ enum evm_ima_xattr_type {
|
||||
};
|
||||
|
||||
struct evm_ima_xattr_data {
|
||||
u8 type;
|
||||
/* New members must be added within the __struct_group() macro below. */
|
||||
__struct_group(evm_ima_xattr_data_hdr, hdr, __packed,
|
||||
u8 type;
|
||||
);
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
/* Only used in the EVM HMAC code. */
|
||||
struct evm_xattr {
|
||||
struct evm_ima_xattr_data data;
|
||||
struct evm_ima_xattr_data_hdr data;
|
||||
u8 digest[SHA1_DIGEST_SIZE];
|
||||
} __packed;
|
||||
|
||||
#define IMA_MAX_DIGEST_SIZE HASH_MAX_DIGESTSIZE
|
||||
|
||||
struct ima_digest_data {
|
||||
/* New members must be added within the __struct_group() macro below. */
|
||||
__struct_group(ima_digest_data_hdr, hdr, __packed,
|
||||
u8 algo;
|
||||
u8 length;
|
||||
union {
|
||||
@ -57,6 +62,7 @@ struct ima_digest_data {
|
||||
} ng;
|
||||
u8 data[2];
|
||||
} xattr;
|
||||
);
|
||||
u8 digest[];
|
||||
} __packed;
|
||||
|
||||
@ -65,7 +71,7 @@ struct ima_digest_data {
|
||||
* with the maximum hash size, define ima_max_digest_data struct.
|
||||
*/
|
||||
struct ima_max_digest_data {
|
||||
struct ima_digest_data hdr;
|
||||
struct ima_digest_data_hdr hdr;
|
||||
u8 digest[HASH_MAX_DIGESTSIZE];
|
||||
} __packed;
|
||||
|
||||
|
@ -2628,6 +2628,7 @@ EXPORT_SYMBOL(security_inode_copy_up);
|
||||
|
||||
/**
|
||||
* security_inode_copy_up_xattr() - Filter xattrs in an overlayfs copy-up op
|
||||
* @src: union dentry of copy-up file
|
||||
* @name: xattr name
|
||||
*
|
||||
* Filter the xattrs being copied up when a unioned file is copied up from a
|
||||
@ -2638,7 +2639,7 @@ EXPORT_SYMBOL(security_inode_copy_up);
|
||||
* if the security module does not know about attribute, or a negative
|
||||
* error code to abort the copy up.
|
||||
*/
|
||||
int security_inode_copy_up_xattr(const char *name)
|
||||
int security_inode_copy_up_xattr(struct dentry *src, const char *name)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@ -2647,7 +2648,7 @@ int security_inode_copy_up_xattr(const char *name)
|
||||
* xattr), -EOPNOTSUPP if it does not know anything about the xattr or
|
||||
* any other error code in case of an error.
|
||||
*/
|
||||
rc = call_int_hook(inode_copy_up_xattr, name);
|
||||
rc = call_int_hook(inode_copy_up_xattr, src, name);
|
||||
if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr))
|
||||
return rc;
|
||||
|
||||
|
@ -3526,7 +3526,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int selinux_inode_copy_up_xattr(const char *name)
|
||||
static int selinux_inode_copy_up_xattr(struct dentry *dentry, const char *name)
|
||||
{
|
||||
/* The copy_up hook above sets the initial context on an inode, but we
|
||||
* don't then want to overwrite it by blindly copying all the lower
|
||||
|
@ -4886,7 +4886,7 @@ static int smack_inode_copy_up(struct dentry *dentry, struct cred **new)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smack_inode_copy_up_xattr(const char *name)
|
||||
static int smack_inode_copy_up_xattr(struct dentry *src, const char *name)
|
||||
{
|
||||
/*
|
||||
* Return 1 if this is the smack access Smack attribute.
|
||||
|
Loading…
Reference in New Issue
Block a user