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:
@ -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))
|
if (ovl_is_private_xattr(sb, name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
error = security_inode_copy_up_xattr(name);
|
error = security_inode_copy_up_xattr(old, name);
|
||||||
if (error < 0 && error != -EOPNOTSUPP)
|
if (error < 0 && error != -EOPNOTSUPP)
|
||||||
break;
|
break;
|
||||||
if (error == 1) {
|
if (error == 1) {
|
||||||
|
@ -1460,7 +1460,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||||||
* lead to unexpected results.
|
* lead to unexpected results.
|
||||||
*/
|
*/
|
||||||
sb->s_iflags |= SB_I_NOUMASK;
|
sb->s_iflags |= SB_I_NOUMASK;
|
||||||
sb->s_iflags |= SB_I_EVM_UNSUPPORTED;
|
sb->s_iflags |= SB_I_EVM_HMAC_UNSUPPORTED;
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe);
|
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,
|
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
||||||
int buffer_size, char type,
|
int buffer_size, char type,
|
||||||
bool canonical_fmt);
|
bool canonical_fmt);
|
||||||
|
extern bool evm_metadata_changed(struct inode *inode,
|
||||||
|
struct inode *metadata_inode);
|
||||||
#ifdef CONFIG_FS_POSIX_ACL
|
#ifdef CONFIG_FS_POSIX_ACL
|
||||||
extern int posix_xattr_acl(const char *xattrname);
|
extern int posix_xattr_acl(const char *xattrname);
|
||||||
#else
|
#else
|
||||||
@ -76,5 +78,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool evm_metadata_changed(struct inode *inode,
|
||||||
|
struct inode *metadata_inode)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_EVM */
|
#endif /* CONFIG_EVM */
|
||||||
#endif /* LINUX_EVM_H */
|
#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_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
|
||||||
#define SB_I_IMA_UNVERIFIABLE_SIGNATURE 0x00000020
|
#define SB_I_IMA_UNVERIFIABLE_SIGNATURE 0x00000020
|
||||||
#define SB_I_UNTRUSTED_MOUNTER 0x00000040
|
#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_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
|
||||||
#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */
|
#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define _LINUX_INTEGRITY_H
|
#define _LINUX_INTEGRITY_H
|
||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/iversion.h>
|
||||||
|
|
||||||
enum integrity_status {
|
enum integrity_status {
|
||||||
INTEGRITY_PASS = 0,
|
INTEGRITY_PASS = 0,
|
||||||
@ -28,4 +29,37 @@ static inline void integrity_load_keys(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_INTEGRITY */
|
#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 */
|
#endif /* _LINUX_INTEGRITY_H */
|
||||||
|
@ -176,7 +176,8 @@ LSM_HOOK(int, 0, inode_listsecurity, struct inode *inode, char *buffer,
|
|||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
|
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, 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,
|
LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
|
||||||
struct kernfs_node *kn)
|
struct kernfs_node *kn)
|
||||||
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
|
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);
|
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
|
||||||
void security_inode_getsecid(struct inode *inode, u32 *secid);
|
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(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,
|
int security_kernfs_init_security(struct kernfs_node *kn_dir,
|
||||||
struct kernfs_node *kn);
|
struct kernfs_node *kn);
|
||||||
int security_file_permission(struct file *file, int mask);
|
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;
|
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;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ struct xattr_list {
|
|||||||
struct evm_iint_cache {
|
struct evm_iint_cache {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
enum integrity_status evm_status:4;
|
enum integrity_status evm_status:4;
|
||||||
|
struct integrity_inode_attributes metadata_inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct lsm_blob_sizes evm_blob_sizes;
|
extern struct lsm_blob_sizes evm_blob_sizes;
|
||||||
@ -61,7 +62,7 @@ extern int evm_hmac_attrs;
|
|||||||
extern struct list_head evm_config_xattrnames;
|
extern struct list_head evm_config_xattrnames;
|
||||||
|
|
||||||
struct evm_digest {
|
struct evm_digest {
|
||||||
struct ima_digest_data hdr;
|
struct ima_digest_data_hdr hdr;
|
||||||
char digest[IMA_MAX_DIGEST_SIZE];
|
char digest[IMA_MAX_DIGEST_SIZE];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
@ -74,11 +75,12 @@ int evm_update_evmxattr(struct dentry *dentry,
|
|||||||
size_t req_xattr_value_len);
|
size_t req_xattr_value_len);
|
||||||
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
|
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
|
||||||
const char *req_xattr_value,
|
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,
|
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
|
||||||
const char *req_xattr_value,
|
const char *req_xattr_value,
|
||||||
size_t req_xattr_value_len, char type,
|
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,
|
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
|
||||||
char *hmac_val);
|
char *hmac_val);
|
||||||
int evm_init_secfs(void);
|
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_name,
|
||||||
const char *req_xattr_value,
|
const char *req_xattr_value,
|
||||||
size_t req_xattr_value_len,
|
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 xattr_list *xattr;
|
||||||
struct shash_desc *desc;
|
struct shash_desc *desc;
|
||||||
size_t xattr_size = 0;
|
size_t xattr_size = 0;
|
||||||
@ -231,6 +232,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
|
|||||||
int error;
|
int error;
|
||||||
int size, user_space_size;
|
int size, user_space_size;
|
||||||
bool ima_present = false;
|
bool ima_present = false;
|
||||||
|
u64 i_version = 0;
|
||||||
|
|
||||||
if (!(inode->i_opflags & IOP_XATTR) ||
|
if (!(inode->i_opflags & IOP_XATTR) ||
|
||||||
inode->i_sb->s_user_ns != &init_user_ns)
|
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);
|
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 */
|
/* Portable EVM signatures must include an IMA hash */
|
||||||
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
|
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
@ -305,18 +314,19 @@ out:
|
|||||||
|
|
||||||
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
|
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
|
||||||
const char *req_xattr_value, size_t req_xattr_value_len,
|
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,
|
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,
|
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
|
||||||
const char *req_xattr_value, size_t req_xattr_value_len,
|
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,
|
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)
|
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)
|
const char *xattr_value, size_t xattr_value_len)
|
||||||
{
|
{
|
||||||
struct inode *inode = d_backing_inode(dentry);
|
struct inode *inode = d_backing_inode(dentry);
|
||||||
|
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||||
struct evm_digest data;
|
struct evm_digest data;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
@ -372,7 +383,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
|
|||||||
|
|
||||||
data.hdr.algo = HASH_ALGO_SHA1;
|
data.hdr.algo = HASH_ALGO_SHA1;
|
||||||
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
|
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
|
||||||
xattr_value_len, &data);
|
xattr_value_len, &data, iint);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
|
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
|
||||||
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry,
|
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry,
|
||||||
|
@ -151,11 +151,11 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
|
|||||||
return count;
|
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);
|
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);
|
pr_info_once("%s not supported\n", inode->i_sb->s_type->name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -192,7 +192,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
|||||||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
|
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
|
||||||
return iint->evm_status;
|
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;
|
return INTEGRITY_UNKNOWN;
|
||||||
|
|
||||||
/* if status is not PASS, try to check again - against -ENOMEM */
|
/* 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;
|
digest.hdr.algo = HASH_ALGO_SHA1;
|
||||||
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
|
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
|
||||||
xattr_value_len, &digest);
|
xattr_value_len, &digest, iint);
|
||||||
if (rc)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
rc = crypto_memneq(xattr_data->data, digest.digest,
|
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;
|
hdr = (struct signature_v2_hdr *)xattr_data;
|
||||||
digest.hdr.algo = hdr->hash_algo;
|
digest.hdr.algo = hdr->hash_algo;
|
||||||
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
|
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)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
|
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;
|
evm_status = INTEGRITY_PASS_IMMUTABLE;
|
||||||
} else if (!IS_RDONLY(inode) &&
|
} else if (!IS_RDONLY(inode) &&
|
||||||
!(inode->i_sb->s_readonly_remount) &&
|
!(inode->i_sb->s_readonly_remount) &&
|
||||||
!IS_IMMUTABLE(inode)) {
|
!IS_IMMUTABLE(inode) &&
|
||||||
|
!is_unsupported_hmac_fs(dentry)) {
|
||||||
evm_update_evmxattr(dentry, xattr_name,
|
evm_update_evmxattr(dentry, xattr_name,
|
||||||
xattr_value,
|
xattr_value,
|
||||||
xattr_value_len);
|
xattr_value_len);
|
||||||
@ -418,9 +425,6 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
|||||||
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
|
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
|
||||||
return INTEGRITY_UNKNOWN;
|
return INTEGRITY_UNKNOWN;
|
||||||
|
|
||||||
if (is_unsupported_fs(dentry))
|
|
||||||
return INTEGRITY_UNKNOWN;
|
|
||||||
|
|
||||||
return evm_verify_hmac(dentry, xattr_name, xattr_value,
|
return evm_verify_hmac(dentry, xattr_name, xattr_value,
|
||||||
xattr_value_len);
|
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 (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (is_unsupported_fs(dentry))
|
if (is_unsupported_hmac_fs(dentry))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
} else if (!evm_protected_xattr(xattr_name)) {
|
} else if (!evm_protected_xattr(xattr_name)) {
|
||||||
if (!posix_xattr_acl(xattr_name))
|
if (!posix_xattr_acl(xattr_name))
|
||||||
return 0;
|
return 0;
|
||||||
if (is_unsupported_fs(dentry))
|
if (is_unsupported_hmac_fs(dentry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
evm_status = evm_verify_current_integrity(dentry);
|
evm_status = evm_verify_current_integrity(dentry);
|
||||||
@ -512,7 +516,7 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
|
|||||||
(evm_status == INTEGRITY_NOXATTRS))
|
(evm_status == INTEGRITY_NOXATTRS))
|
||||||
return 0;
|
return 0;
|
||||||
goto out;
|
goto out;
|
||||||
} else if (is_unsupported_fs(dentry))
|
} else if (is_unsupported_hmac_fs(dentry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
evm_status = evm_verify_current_integrity(dentry);
|
evm_status = evm_verify_current_integrity(dentry);
|
||||||
@ -733,6 +737,31 @@ static void evm_reset_status(struct inode *inode)
|
|||||||
iint->evm_status = INTEGRITY_UNKNOWN;
|
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
|
* evm_revalidate_status - report whether EVM status re-validation is necessary
|
||||||
* @xattr_name: pointer to the affected extended attribute name
|
* @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))
|
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (is_unsupported_fs(dentry))
|
if (is_unsupported_hmac_fs(dentry))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
|
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)
|
if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (is_unsupported_fs(dentry))
|
if (is_unsupported_hmac_fs(dentry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
|
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))
|
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (is_unsupported_fs(dentry))
|
if (is_unsupported_hmac_fs(dentry))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
|
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
|
||||||
evm_update_evmxattr(dentry, NULL, NULL, 0);
|
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)
|
struct evm_ima_xattr_data *xattr_data = NULL;
|
||||||
return 1; /* Discard */
|
int rc;
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
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 */
|
/* bitset of digests algorithms allowed in the setxattr hook */
|
||||||
extern atomic_t ima_setxattr_allowed_hash_algorithms;
|
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 */
|
/* set during initialization */
|
||||||
extern int ima_hash_algo __ro_after_init;
|
extern int ima_hash_algo __ro_after_init;
|
||||||
extern int ima_sha1_idx __ro_after_init;
|
extern int ima_sha1_idx __ro_after_init;
|
||||||
extern int ima_hash_algo_idx __ro_after_init;
|
extern int ima_hash_algo_idx __ro_after_init;
|
||||||
extern int ima_extra_slots __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 int ima_appraise;
|
||||||
extern struct tpm_chip *ima_tpm_chip;
|
extern struct tpm_chip *ima_tpm_chip;
|
||||||
extern const char boot_aggregate_name[];
|
extern const char boot_aggregate_name[];
|
||||||
@ -175,12 +183,10 @@ struct ima_kexec_hdr {
|
|||||||
/* IMA integrity metadata associated with an inode */
|
/* IMA integrity metadata associated with an inode */
|
||||||
struct ima_iint_cache {
|
struct ima_iint_cache {
|
||||||
struct mutex mutex; /* protects: version, flags, digest */
|
struct mutex mutex; /* protects: version, flags, digest */
|
||||||
u64 version; /* track inode changes */
|
struct integrity_inode_attributes real_inode;
|
||||||
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;
|
||||||
|
@ -245,8 +245,10 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
|||||||
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));
|
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_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;
|
struct kstat stat;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int length;
|
int length;
|
||||||
@ -286,9 +288,9 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
|||||||
result = -ENODATA;
|
result = -ENODATA;
|
||||||
}
|
}
|
||||||
} else if (buf) {
|
} else if (buf) {
|
||||||
result = ima_calc_buffer_hash(buf, size, &hash.hdr);
|
result = ima_calc_buffer_hash(buf, size, hash_hdr);
|
||||||
} else {
|
} else {
|
||||||
result = ima_calc_file_hash(file, &hash.hdr);
|
result = ima_calc_file_hash(file, hash_hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result && result != -EBADF && result != -EINVAL)
|
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;
|
iint->ima_hash = tmpbuf;
|
||||||
memcpy(iint->ima_hash, &hash, length);
|
memcpy(iint->ima_hash, &hash, length);
|
||||||
iint->version = i_version;
|
if (real_inode == inode)
|
||||||
if (real_inode != inode) {
|
iint->real_inode.version = i_version;
|
||||||
iint->real_ino = real_inode->i_ino;
|
else
|
||||||
iint->real_dev = real_inode->i_sb->s_dev;
|
integrity_inode_attrs_store(&iint->real_inode, i_version,
|
||||||
}
|
real_inode);
|
||||||
|
|
||||||
/* 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)
|
||||||
@ -317,9 +319,13 @@ out:
|
|||||||
if (file->f_flags & O_DIRECT)
|
if (file->f_flags & O_DIRECT)
|
||||||
audit_cause = "failed(directio)";
|
audit_cause = "failed(directio)";
|
||||||
|
|
||||||
|
take_dentry_name_snapshot(&filename, file->f_path.dentry);
|
||||||
|
|
||||||
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
||||||
filename, "collect_data", audit_cause,
|
filename.name.name, "collect_data",
|
||||||
result, 0);
|
audit_cause, result, 0);
|
||||||
|
|
||||||
|
release_dentry_name_snapshot(&filename);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -432,6 +438,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
|
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
|
||||||
{
|
{
|
||||||
|
struct name_snapshot filename;
|
||||||
char *pathname = NULL;
|
char *pathname = NULL;
|
||||||
|
|
||||||
*pathbuf = __getname();
|
*pathbuf = __getname();
|
||||||
@ -445,7 +452,10 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!pathname) {
|
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;
|
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,
|
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) {
|
if (rc) {
|
||||||
*cause = "sigv3-hashing-error";
|
*cause = "sigv3-hashing-error";
|
||||||
*status = INTEGRITY_FAIL;
|
*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_shash *ima_shash_tfm;
|
||||||
static struct crypto_ahash *ima_ahash_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_sha1_idx __ro_after_init;
|
||||||
int ima_hash_algo_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;
|
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)
|
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++);
|
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:
|
/* print format:
|
||||||
* 32bit-le=pcr#
|
* 32bit-le=pcr#
|
||||||
* char[20]=template digest
|
* char[n]=template digest
|
||||||
* 32bit-le=template name size
|
* 32bit-le=template name size
|
||||||
* char[n]=template name
|
* char[n]=template name
|
||||||
* [eventdata length]
|
* [eventdata length]
|
||||||
@ -132,7 +154,15 @@ int ima_measurements_show(struct seq_file *m, void *v)
|
|||||||
char *template_name;
|
char *template_name;
|
||||||
u32 pcr, namelen, template_data_len; /* temporary fields */
|
u32 pcr, namelen, template_data_len; /* temporary fields */
|
||||||
bool is_ima_template = false;
|
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 */
|
/* get entry */
|
||||||
e = qe->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));
|
ima_putc(m, &pcr, sizeof(e->pcr));
|
||||||
|
|
||||||
/* 2nd: template digest */
|
/* 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 */
|
/* 3rd: template name size */
|
||||||
namelen = !ima_canonical_fmt ? strlen(template_name) :
|
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_queue_entry *qe = v;
|
||||||
struct ima_template_entry *e;
|
struct ima_template_entry *e;
|
||||||
char *template_name;
|
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 */
|
/* get entry */
|
||||||
e = qe->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) */
|
/* 1st: PCR used (config option) */
|
||||||
seq_printf(m, "%2d ", e->pcr);
|
seq_printf(m, "%2d ", e->pcr);
|
||||||
|
|
||||||
/* 2nd: SHA1 template hash */
|
/* 2nd: template hash */
|
||||||
ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
|
ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
|
||||||
|
|
||||||
/* 3th: template name */
|
/* 3th: template name */
|
||||||
seq_printf(m, " %s", template_name);
|
seq_printf(m, " %s", template_name);
|
||||||
@ -379,6 +417,71 @@ static const struct seq_operations ima_policy_seqops = {
|
|||||||
};
|
};
|
||||||
#endif
|
#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
|
* ima_open_policy: sequentialize access to the policy file
|
||||||
*/
|
*/
|
||||||
@ -454,6 +557,9 @@ int __init ima_fs_init(void)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ascii_securityfs_measurement_lists = NULL;
|
||||||
|
binary_securityfs_measurement_lists = NULL;
|
||||||
|
|
||||||
ima_dir = securityfs_create_dir("ima", integrity_dir);
|
ima_dir = securityfs_create_dir("ima", integrity_dir);
|
||||||
if (IS_ERR(ima_dir))
|
if (IS_ERR(ima_dir))
|
||||||
return PTR_ERR(ima_dir);
|
return PTR_ERR(ima_dir);
|
||||||
@ -465,19 +571,21 @@ int __init ima_fs_init(void)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = create_securityfs_measurement_lists();
|
||||||
|
if (ret != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
binary_runtime_measurements =
|
binary_runtime_measurements =
|
||||||
securityfs_create_file("binary_runtime_measurements",
|
securityfs_create_symlink("binary_runtime_measurements", ima_dir,
|
||||||
S_IRUSR | S_IRGRP, ima_dir, NULL,
|
"binary_runtime_measurements_sha1", NULL);
|
||||||
&ima_measurements_ops);
|
|
||||||
if (IS_ERR(binary_runtime_measurements)) {
|
if (IS_ERR(binary_runtime_measurements)) {
|
||||||
ret = PTR_ERR(binary_runtime_measurements);
|
ret = PTR_ERR(binary_runtime_measurements);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ascii_runtime_measurements =
|
ascii_runtime_measurements =
|
||||||
securityfs_create_file("ascii_runtime_measurements",
|
securityfs_create_symlink("ascii_runtime_measurements", ima_dir,
|
||||||
S_IRUSR | S_IRGRP, ima_dir, NULL,
|
"ascii_runtime_measurements_sha1", NULL);
|
||||||
&ima_ascii_measurements_ops);
|
|
||||||
if (IS_ERR(ascii_runtime_measurements)) {
|
if (IS_ERR(ascii_runtime_measurements)) {
|
||||||
ret = PTR_ERR(ascii_runtime_measurements);
|
ret = PTR_ERR(ascii_runtime_measurements);
|
||||||
goto out;
|
goto out;
|
||||||
@ -515,6 +623,8 @@ out:
|
|||||||
securityfs_remove(runtime_measurements_count);
|
securityfs_remove(runtime_measurements_count);
|
||||||
securityfs_remove(ascii_runtime_measurements);
|
securityfs_remove(ascii_runtime_measurements);
|
||||||
securityfs_remove(binary_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_symlink);
|
||||||
securityfs_remove(ima_dir);
|
securityfs_remove(ima_dir);
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ static void ima_iint_init_always(struct ima_iint_cache *iint,
|
|||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
iint->ima_hash = NULL;
|
iint->ima_hash = NULL;
|
||||||
iint->version = 0;
|
iint->real_inode.version = 0;
|
||||||
iint->flags = 0UL;
|
iint->flags = 0UL;
|
||||||
iint->atomic_flags = 0UL;
|
iint->atomic_flags = 0UL;
|
||||||
iint->ima_file_status = INTEGRITY_UNKNOWN;
|
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,
|
struct ima_event_data event_data = { .iint = iint,
|
||||||
.filename = boot_aggregate_name };
|
.filename = boot_aggregate_name };
|
||||||
struct ima_max_digest_data hash;
|
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 result = -ENOMEM;
|
||||||
int violation = 0;
|
int violation = 0;
|
||||||
|
|
||||||
memset(iint, 0, sizeof(*iint));
|
memset(iint, 0, sizeof(*iint));
|
||||||
memset(&hash, 0, sizeof(hash));
|
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->algo = ima_hash_algo;
|
||||||
iint->ima_hash->length = hash_digest_size[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.
|
* is not found.
|
||||||
*/
|
*/
|
||||||
if (ima_tpm_chip) {
|
if (ima_tpm_chip) {
|
||||||
result = ima_calc_boot_aggregate(&hash.hdr);
|
result = ima_calc_boot_aggregate(hash_hdr);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
audit_cause = "hashing_error";
|
audit_cause = "hashing_error";
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
@ -30,6 +30,7 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file.file = NULL;
|
||||||
file.size = segment_size;
|
file.size = segment_size;
|
||||||
file.read_pos = 0;
|
file.read_pos = 0;
|
||||||
file.count = sizeof(khdr); /* reserved space */
|
file.count = sizeof(khdr); /* reserved space */
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <linux/ima.h>
|
#include <linux/ima.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/iversion.h>
|
#include <linux/iversion.h>
|
||||||
|
#include <linux/evm.h>
|
||||||
|
|
||||||
#include "ima.h"
|
#include "ima.h"
|
||||||
|
|
||||||
@ -173,7 +174,7 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
|
|||||||
STATX_CHANGE_COOKIE,
|
STATX_CHANGE_COOKIE,
|
||||||
AT_STATX_SYNC_AS_STAT) ||
|
AT_STATX_SYNC_AS_STAT) ||
|
||||||
!(stat.result_mask & STATX_CHANGE_COOKIE) ||
|
!(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->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
|
||||||
iint->measured_pcrs = 0;
|
iint->measured_pcrs = 0;
|
||||||
if (update)
|
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,
|
u32 secid, char *buf, loff_t size, int mask,
|
||||||
enum ima_hooks func)
|
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_iint_cache *iint = NULL;
|
||||||
struct ima_template_desc *template_desc = NULL;
|
struct ima_template_desc *template_desc = NULL;
|
||||||
|
struct inode *metadata_inode;
|
||||||
char *pathbuf = NULL;
|
char *pathbuf = NULL;
|
||||||
char filename[NAME_MAX];
|
char filename[NAME_MAX];
|
||||||
const char *pathname = NULL;
|
const char *pathname = NULL;
|
||||||
@ -285,17 +287,28 @@ 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));
|
* On stacked filesystems, detect and re-evaluate file data and
|
||||||
if (backing_inode != inode &&
|
* metadata changes.
|
||||||
|
*/
|
||||||
|
real_inode = d_real_inode(file_dentry(file));
|
||||||
|
if (real_inode != inode &&
|
||||||
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
|
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
|
||||||
if (!IS_I_VERSION(backing_inode) ||
|
if (!IS_I_VERSION(real_inode) ||
|
||||||
backing_inode->i_sb->s_dev != iint->real_dev ||
|
integrity_inode_attrs_changed(&iint->real_inode,
|
||||||
backing_inode->i_ino != iint->real_ino ||
|
real_inode)) {
|
||||||
!inode_eq_iversion(backing_inode, iint->version)) {
|
|
||||||
iint->flags &= ~IMA_DONE_MASK;
|
iint->flags &= ~IMA_DONE_MASK;
|
||||||
iint->measured_pcrs = 0;
|
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
|
/* 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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,6 +961,8 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
|||||||
.buf_len = size};
|
.buf_len = size};
|
||||||
struct ima_template_desc *template;
|
struct ima_template_desc *template;
|
||||||
struct ima_max_digest_data hash;
|
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];
|
char digest_hash[IMA_MAX_DIGEST_SIZE];
|
||||||
int digest_hash_len = hash_digest_size[ima_hash_algo];
|
int digest_hash_len = hash_digest_size[ima_hash_algo];
|
||||||
int violation = 0;
|
int violation = 0;
|
||||||
@ -979,7 +1001,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
|||||||
if (!pcr)
|
if (!pcr)
|
||||||
pcr = CONFIG_IMA_MEASURE_PCR_IDX;
|
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->algo = ima_hash_algo;
|
||||||
iint.ima_hash->length = hash_digest_size[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) {
|
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,
|
ret = ima_calc_buffer_hash(digest_hash, digest_hash_len,
|
||||||
iint.ima_hash);
|
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_field_data *field_data)
|
||||||
{
|
{
|
||||||
struct ima_max_digest_data hash;
|
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;
|
u8 *cur_digest = NULL;
|
||||||
u32 cur_digestsize = 0;
|
u32 cur_digestsize = 0;
|
||||||
struct inode *inode;
|
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 ((const char *)event_data->filename == boot_aggregate_name) {
|
||||||
if (ima_tpm_chip) {
|
if (ima_tpm_chip) {
|
||||||
hash.hdr.algo = HASH_ALGO_SHA1;
|
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 */
|
/* algo can change depending on available PCR banks */
|
||||||
if (!result && hash.hdr.algo != HASH_ALGO_SHA1)
|
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));
|
memset(&hash, 0, sizeof(hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_digest = hash.hdr.digest;
|
cur_digest = hash_hdr->digest;
|
||||||
cur_digestsize = hash_digest_size[HASH_ALGO_SHA1];
|
cur_digestsize = hash_digest_size[HASH_ALGO_SHA1];
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -379,14 +381,14 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
|
|||||||
inode = file_inode(event_data->file);
|
inode = file_inode(event_data->file);
|
||||||
hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
|
hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
|
||||||
ima_hash_algo : HASH_ALGO_SHA1;
|
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) {
|
if (result) {
|
||||||
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
||||||
event_data->filename, "collect_data",
|
event_data->filename, "collect_data",
|
||||||
"failed", result, 0);
|
"failed", result, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
cur_digest = hash.hdr.digest;
|
cur_digest = hash_hdr->digest;
|
||||||
cur_digestsize = hash.hdr.length;
|
cur_digestsize = hash.hdr.length;
|
||||||
out:
|
out:
|
||||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
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)
|
bool size_limit)
|
||||||
{
|
{
|
||||||
const char *cur_filename = NULL;
|
const char *cur_filename = NULL;
|
||||||
|
struct name_snapshot filename;
|
||||||
u32 cur_filename_len = 0;
|
u32 cur_filename_len = 0;
|
||||||
|
bool snapshot = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
BUG_ON(event_data->filename == NULL && event_data->file == NULL);
|
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) {
|
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);
|
cur_filename_len = strlen(cur_filename);
|
||||||
} else
|
} 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;
|
cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
|
||||||
out:
|
out:
|
||||||
return ima_write_template_field_data(cur_filename, cur_filename_len,
|
ret = ima_write_template_field_data(cur_filename, cur_filename_len,
|
||||||
DATA_FMT_STRING, field_data);
|
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 {
|
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[];
|
u8 data[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* Only used in the EVM HMAC code. */
|
/* Only used in the EVM HMAC code. */
|
||||||
struct evm_xattr {
|
struct evm_xattr {
|
||||||
struct evm_ima_xattr_data data;
|
struct evm_ima_xattr_data_hdr data;
|
||||||
u8 digest[SHA1_DIGEST_SIZE];
|
u8 digest[SHA1_DIGEST_SIZE];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define IMA_MAX_DIGEST_SIZE HASH_MAX_DIGESTSIZE
|
#define IMA_MAX_DIGEST_SIZE HASH_MAX_DIGESTSIZE
|
||||||
|
|
||||||
struct ima_digest_data {
|
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 algo;
|
||||||
u8 length;
|
u8 length;
|
||||||
union {
|
union {
|
||||||
@ -57,6 +62,7 @@ struct ima_digest_data {
|
|||||||
} ng;
|
} ng;
|
||||||
u8 data[2];
|
u8 data[2];
|
||||||
} xattr;
|
} xattr;
|
||||||
|
);
|
||||||
u8 digest[];
|
u8 digest[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
@ -65,7 +71,7 @@ struct ima_digest_data {
|
|||||||
* with the maximum hash size, define ima_max_digest_data struct.
|
* with the maximum hash size, define ima_max_digest_data struct.
|
||||||
*/
|
*/
|
||||||
struct ima_max_digest_data {
|
struct ima_max_digest_data {
|
||||||
struct ima_digest_data hdr;
|
struct ima_digest_data_hdr hdr;
|
||||||
u8 digest[HASH_MAX_DIGESTSIZE];
|
u8 digest[HASH_MAX_DIGESTSIZE];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
@ -2628,6 +2628,7 @@ EXPORT_SYMBOL(security_inode_copy_up);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* security_inode_copy_up_xattr() - Filter xattrs in an overlayfs copy-up op
|
* security_inode_copy_up_xattr() - Filter xattrs in an overlayfs copy-up op
|
||||||
|
* @src: union dentry of copy-up file
|
||||||
* @name: xattr name
|
* @name: xattr name
|
||||||
*
|
*
|
||||||
* Filter the xattrs being copied up when a unioned file is copied up from a
|
* 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
|
* if the security module does not know about attribute, or a negative
|
||||||
* error code to abort the copy up.
|
* 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;
|
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
|
* xattr), -EOPNOTSUPP if it does not know anything about the xattr or
|
||||||
* any other error code in case of an error.
|
* 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))
|
if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -3526,7 +3526,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
|
|||||||
return 0;
|
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
|
/* 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
|
* 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;
|
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.
|
* Return 1 if this is the smack access Smack attribute.
|
||||||
|
Reference in New Issue
Block a user